Public/Add-VellumPdfImage.ps1
|
function Add-VellumPdfImage { <# .SYNOPSIS Embeds an image into a VellumPdf document, from a file or from memory. .DESCRIPTION Wraps Document.Add(LayoutImage). Reads the image from -Path (loader chosen by file extension) or from -ImageBytes with an explicit -Format, constructs a LayoutImage, and adds it to the document. Formats: JPEG, PNG, BMP, GIF, TIFF, JBIG2, JPEG 2000. Supported extensions: .jpg/.jpeg, .png, .bmp, .gif, .tif/.tiff, .jbig2/.jb2, and .jp2/.jpx/.j2k/.jpf (JPEG 2000). For -ImageBytes, pass -Format (Jpeg/Png/Bmp/Gif/Tiff/Jbig2/Jpeg2000) since there is no extension. Note for PDF/A: JPEG 2000 and JBIG2 images compose with PDF/A-2. The bundled engine (VellumPdf 1.5.4+) embeds the JP2 box metadata that PDF/A-2 clause 6.2.8.3 requires, and CI validates a PDF/A-2b document with each image type through veraPDF. The JPEG 2000 source must still satisfy PDF/A-2's own rules - 1, 3, or 4 colour channels, all sharing a single bit depth. Optional -Width and -Height (in points) constrain the rendered size; when omitted the image renders at its natural size. -Alignment positions the image horizontally on the page. -AltText supplies alternate text that aids tagged PDF and PDF-A accessibility readers. -MarginTop and -MarginBottom apply spacing above and below the image without affecting the left/right margins already set on the element. The document flows through the pipeline for chaining with other Add-VellumPdf* functions. .PARAMETER Document The live VellumPdf document flowing through the pipeline. The same instance is returned after the image is added, enabling chaining. .PARAMETER Path File system path to the image file (parameter set 'Path'). Supported extensions are .jpg, .jpeg, .png, .bmp, .gif, .tif, .tiff, .jbig2, .jb2, .jp2, .jpx, .j2k, and .jpf. The path is resolved relative to the current PowerShell provider location. Mandatory and positional (position 0). .PARAMETER ImageBytes Raw image bytes to embed (parameter set 'Bytes'), for images produced in memory rather than read from disk. Requires -Format. .PARAMETER Format The format of -ImageBytes: Jpeg, Png, Bmp, Gif, Tiff, Jbig2, or Jpeg2000. Required with -ImageBytes (there is no extension to infer it from). .PARAMETER Width Rendered width of the image in points, between 1 and 100000. When omitted the image is rendered at its natural width. .PARAMETER Height Rendered height of the image in points, between 1 and 100000. When omitted the image is rendered at its natural height. .PARAMETER Alignment Horizontal alignment of the image on the page. Accepts Left, Center, Right, or Justify. Defaults to Left. .PARAMETER AltText Alternate text description for the image. Stored on the LayoutImage element and included in tagged PDF structure for accessibility readers and PDF/A compliance. .PARAMETER MarginTop Extra spacing in points above the image element. Does not affect the left/right page margins. .PARAMETER MarginBottom Extra spacing in points below the image element. Does not affect the left/right page margins. .EXAMPLE New-VellumPdfDocument | Add-VellumPdfImage -Path ./logo.png | Save-VellumPdfDocument -Path ./report.pdf .EXAMPLE $doc | Add-VellumPdfImage -Path ./photo.jpg -Width 200 -Height 150 ` -Alignment Center -AltText 'Company photo' .EXAMPLE # Embed an in-memory PNG (e.g. a chart) without a temp file $doc | Add-VellumPdfImage -ImageBytes $pngBytes -Format Png -Width 150 .OUTPUTS VellumPdf.Layout.Document (the same instance, for chaining) #> [CmdletBinding(DefaultParameterSetName = 'Path')] [OutputType([VellumPdf.Layout.Document])] param( [Parameter(Mandatory, ValueFromPipeline)] [VellumPdf.Layout.Document]$Document, [Parameter(Mandatory, Position = 0, ParameterSetName = 'Path')] [string]$Path, # In-memory image bytes (e.g. a chart or QR rendered by another library). [Parameter(Mandatory, ParameterSetName = 'Bytes')] [byte[]]$ImageBytes, # Image format of -ImageBytes, since there is no file extension to infer it. [Parameter(Mandatory, ParameterSetName = 'Bytes')] [ValidateSet('Jpeg', 'Png', 'Bmp', 'Gif', 'Tiff', 'Jbig2', 'Jpeg2000')] [string]$Format, [ValidateRange(1, 100000)] [double]$Width, [ValidateRange(1, 100000)] [double]$Height, [ValidateSet('Left', 'Center', 'Right', 'Justify')] [string]$Alignment = 'Left', [string]$AltText, [ValidateRange(0, 10000)] [double]$MarginTop, [ValidateRange(0, 10000)] [double]$MarginBottom ) process { Assert-VellumPdfDocumentOpen -Document $Document -CommandName 'Add-VellumPdfImage' # Resolve the bytes and a format key from either input set. if ($PSCmdlet.ParameterSetName -eq 'Bytes') { $bytes = $ImageBytes $formatKey = $Format.ToLowerInvariant() $source = 'the supplied image bytes' } else { $resolved = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) if (-not [System.IO.File]::Exists($resolved)) { throw "Add-VellumPdfImage: file not found: '$resolved'. Verify the path and try again." } $bytes = [System.IO.File]::ReadAllBytes($resolved) $source = "'$resolved'" $ext = [System.IO.Path]::GetExtension($resolved).ToLowerInvariant() $formatKey = switch ($ext) { '.jpg' { 'jpeg' } '.jpeg' { 'jpeg' } '.png' { 'png' } '.bmp' { 'bmp' } '.gif' { 'gif' } '.tif' { 'tiff' } '.tiff' { 'tiff' } '.jbig2' { 'jbig2' } '.jb2' { 'jbig2' } '.jp2' { 'jpeg2000' } '.jpx' { 'jpeg2000' } '.j2k' { 'jpeg2000' } '.jpf' { 'jpeg2000' } default { throw ("Add-VellumPdfImage: unsupported image extension '$ext'. " + "Supported extensions are: .jpg, .jpeg, .png, .bmp, .gif, .tif, " + ".tiff, .jbig2, .jb2, .jp2, .jpx, .j2k, .jpf.") } } } # Loader errors ("Not a PNG file.") do not mention the source; rethrow # with it so batch scripts can identify the culprit. try { $xObject = switch ($formatKey) { 'jpeg' { [VellumPdf.Images.JpegImageLoader]::Load($bytes) } 'png' { [VellumPdf.Images.PngImageLoader]::Load($bytes) } 'bmp' { [VellumPdf.Images.BmpImageLoader]::Load($bytes) } 'gif' { [VellumPdf.Images.GifImageLoader]::Load($bytes) } 'tiff' { [VellumPdf.Images.TiffImageLoader]::Load($bytes) } 'jbig2' { [VellumPdf.Images.Jbig2ImageLoader]::Load($bytes) } 'jpeg2000' { [VellumPdf.Images.JpxImageLoader]::Load($bytes) } } } catch { if ($_.Exception.Message -like 'Add-VellumPdfImage:*') { throw } $inner = if ($_.Exception.InnerException) { $_.Exception.InnerException.Message } else { $_.Exception.Message } throw "Add-VellumPdfImage: failed to load $($source): $inner" } $layoutImage = [VellumPdf.Layout.Elements.LayoutImage]::new($xObject) if ($PSBoundParameters.ContainsKey('Width')) { $layoutImage.Width = $Width } if ($PSBoundParameters.ContainsKey('Height')) { $layoutImage.Height = $Height } $layoutImage.Alignment = [VellumPdf.Layout.Core.HorizontalAlignment]::$Alignment if ($PSBoundParameters.ContainsKey('AltText')) { $layoutImage.AltText = $AltText } Set-VellumPdfElementMargin -Element $layoutImage -Top $MarginTop -Bottom $MarginBottom ` -BoundParameters $PSBoundParameters [void]$Document.Add($layoutImage) $Document } } |