diff --git a/Examples/AddImage/Add-ExcelImage.ps1 b/Examples/AddImage/Add-ExcelImage.ps1 new file mode 100644 index 0000000..38ce80e --- /dev/null +++ b/Examples/AddImage/Add-ExcelImage.ps1 @@ -0,0 +1,119 @@ +function Add-ExcelImage { + <# + .SYNOPSIS + Adds an image to a worksheet in an Excel package. + .DESCRIPTION + Adds an image to a worksheet in an Excel package using the + `WorkSheet.Drawings.AddPicture(name, image)` method, and places the + image at the location specified by the Row and Column parameters. + + Additional position adjustment can be made by providing RowOffset and + ColumnOffset values in pixels. + .EXAMPLE + $image = [System.Drawing.Image]::FromFile($octocat) + $xlpkg = $data | Export-Excel -Path $path -PassThru + $xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell + + Where $octocat is a path to an image file, and $data is a collection of + data to be exported, and $path is the output path for the Excel document, + Add-Excel places the image at row 4 and column 6, resizing the column + and row as needed to fit the image. + .INPUTS + [OfficeOpenXml.ExcelWorksheet] + .OUTPUTS + None + #> + [CmdletBinding()] + param( + # Specifies the worksheet to add the image to. + [Parameter(Mandatory, ValueFromPipeline)] + [OfficeOpenXml.ExcelWorksheet] + $WorkSheet, + + # Specifies the Image to be added to the worksheet. + [Parameter(Mandatory)] + [System.Drawing.Image] + $Image, + + # Specifies the row where the image will be placed. Rows are counted from 1. + [Parameter(Mandatory)] + [ValidateRange(1, [int]::MaxValue)] + [int] + $Row, + + # Specifies the column where the image will be placed. Columns are counted from 1. + [Parameter(Mandatory)] + [ValidateRange(1, [int]::MaxValue)] + [int] + $Column, + + # Specifies the name to associate with the image. Names must be unique per sheet. + # Omit the name and a GUID will be used instead. + [Parameter()] + [string] + $Name, + + # Specifies the number of pixels to offset the image on the Y-axis. A + # positive number moves the image down by the specified number of pixels + # from the top border of the cell. + [Parameter()] + [int] + $RowOffset = 1, + + # Specifies the number of pixels to offset the image on the X-axis. A + # positive number moves the image to the right by the specified number + # of pixels from the left border of the cell. + [Parameter()] + [int] + $ColumnOffset = 1, + + # Increase the column width and row height to fit the image if the current + # dimensions are smaller than the image provided. + [Parameter()] + [switch] + $ResizeCell + ) + + begin { + if ($IsWindows -eq $false) { + throw "This only works on Windows and won't run on $([environment]::OSVersion)" + } + + <# + These ratios work on my machine but it feels fragile. Need to better + understand how row and column sizing works in Excel and what the + width and height units represent. + #> + $widthFactor = 1 / 7 + $heightFactor = 3 / 4 + } + + process { + if ([string]::IsNullOrWhiteSpace($Name)) { + $Name = (New-Guid).ToString() + } + if ($null -ne $WorkSheet.Drawings[$Name]) { + Write-Error "A picture with the name `"$Name`" already exists in worksheet $($WorkSheet.Name)." + return + } + + <# + The row and column offsets of 1 ensures that the image lands just + inside the gray cell borders at the top left. + #> + $picture = $WorkSheet.Drawings.AddPicture($Name, $Image) + $picture.SetPosition($Row - 1, $RowOffset, $Column - 1, $ColumnOffset) + + if ($ResizeCell) { + <# + Adding 1 to the image height and width ensures that when the + row and column are resized, the bottom right of the image lands + just inside the gray cell borders at the bottom right. + #> + $width = $widthFactor * ($Image.Width + 1) + $height = $heightFactor * ($Image.Height + 1) + $WorkSheet.Column($Column).Width = [Math]::Max($width, $WorkSheet.Column($Column).Width) + $WorkSheet.Row($Row).Height = [Math]::Max($height, $WorkSheet.Row($Row).Height) + } + } +} \ No newline at end of file diff --git a/Examples/AddImage/AddImage.ps1 b/Examples/AddImage/AddImage.ps1 new file mode 100644 index 0000000..4d38e09 --- /dev/null +++ b/Examples/AddImage/AddImage.ps1 @@ -0,0 +1,39 @@ +if ($IsWindows -eq $false) { + throw "This only works on Windows and won't run on $([environment]::OSVersion)" +} + +Add-Type -AssemblyName System.Drawing + +. $PSScriptRoot\Add-ExcelImage.ps1 + +$data = ConvertFrom-Csv @" +Region,State,Units,Price +West,Texas,927,923.71 +North,Tennessee,466,770.67 +East,Florida,520,458.68 +East,Maine,828,661.24 +West,Virginia,465,053.58 +North,Missouri,436,235.67 +South,Kansas,214,992.47 +North,North Dakota,789,640.72 +South,Delaware,712,508.55 +"@ + +$path = "$PSScriptRoot/Add-Picture-test.xlsx" +Remove-Item $path -ErrorAction SilentlyContinue + + +try { + $octocat = "$PSScriptRoot/Octocat.jpg" + $image = [System.Drawing.Image]::FromFile($octocat) + $xlpkg = $data | Export-Excel -Path $path -PassThru + $xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell +} +finally { + if ($image) { + $image.Dispose() + } + if ($xlpkg) { + Close-ExcelPackage -ExcelPackage $xlpkg -Show + } +} diff --git a/Examples/AddImage/Octocat.jpg b/Examples/AddImage/Octocat.jpg new file mode 100644 index 0000000..a48c349 Binary files /dev/null and b/Examples/AddImage/Octocat.jpg differ diff --git a/Examples/AddImage/README.md b/Examples/AddImage/README.md new file mode 100644 index 0000000..4d71141 --- /dev/null +++ b/Examples/AddImage/README.md @@ -0,0 +1,33 @@ +# Add-ExcelImage Example + +Adding pictures to an Excel worksheet is possible by calling the `AddPicture(name, image)` +method on the `Drawings` property of an `ExcelWorksheet` object. + +The `Add-ExcelImage` example here demonstrates how to add a picture at a given +cell location, and optionally resize the row and column to fit the image. + +## Running the example + +To try this example, run the script `AddImage.ps1`. The `Add-ExcelImage` +function will be dot-sourced, and an Excel document will be created in the same +folder with a sample data set. The Octocat image will then be embedded into +Sheet1. + +The creation of the Excel document and the `System.Drawing.Image` object +representing Octocat are properly disposed within a `finally` block to ensure +that the resources are released, even if an error occurs in the `try` block. + +## Note about column and row sizing + +Care has been taken in this example to get the image placement to be just inside +the cell border, and if the `-ResizeCell` switch is present, the height and width +of the row and column will be increased, if needed, so that the bottom right of +the image also lands just inside the cell border. + +The Excel row and column sizes are measured in "point" units rather than pixels, +and a fixed multiplication factor is used to convert the size of the image in +pixels, to the corresponding height and width values in Excel. + +It's possible that different DPI or text scaling options could result in +imperfect column and row sizing and if a better strategy is found for converting +the image dimensions to column and row sizes, this example will be updated.