PSWritePDF.psm1
class CustomSplitter : iText.Kernel.Utils.PdfSplitter { [int] $_order [string] $_destinationFolder [string] $_outputName CustomSplitter([iText.Kernel.Pdf.PdfDocument] $pdfDocument, [string] $destinationFolder, [string] $OutputName) : base($pdfDocument) { $this._destinationFolder = $destinationFolder $this._order = 0 $this._outputName = $OutputName } [iText.Kernel.Pdf.PdfWriter] GetNextPdfWriter([iText.Kernel.Utils.PageRange] $documentPageRange) { $Name = -join ($this._outputName, $this._order++, ".pdf") $Path = [IO.Path]::Combine($this._destinationFolder, $Name) return [iText.Kernel.Pdf.PdfWriter]::new($Path) } } function Convert-PDFToText { [CmdletBinding()] param([string] $FilePath, [int[]] $Page) if ($FilePath -and (Test-Path -LiteralPath $FilePath)) { $Source = [iText.Kernel.Pdf.PdfReader]::new($FilePath) [iText.Kernel.Pdf.PdfDocument] $SourcePDF = [iText.Kernel.Pdf.PdfDocument]::new($Source) [iText.Kernel.Pdf.Canvas.Parser.Listener.LocationTextExtractionStrategy] $ExtractionStrategy = [iText.Kernel.Pdf.Canvas.Parser.Listener.LocationTextExtractionStrategy]::new() $PagesCount = $SourcePDF.GetNumberOfPages() if ($Page.Count -eq 0) { for ($Count = 1; $Count -le $PagesCount; $Count++) { $ExtractedPage = $SourcePDF.GetPage($Count) [iText.Kernel.Pdf.Canvas.Parser.PdfTextExtractor]::GetTextFromPage($ExtractedPage, $ExtractionStrategy) } } else { foreach ($Count in $Page) { if ($Count -le $PagesCount -and $Count -gt 0) { $ExtractedPage = $SourcePDF.GetPage($Count) [iText.Kernel.Pdf.Canvas.Parser.PdfTextExtractor]::GetTextFromPage($ExtractedPage, $ExtractionStrategy) } else { Write-Warning "Convert-PDFToText - File $FilePath doesn't contain page number $Count. Skipping." } } } } else { Write-Warning "Convert-PDFToText - Path $FilePath doesn't exists. Terminating." } } function Merge-PDF { [CmdletBinding()] param([string[]] $InputFile, [string] $OutputFile) if ($OutputFile) { [iText.Kernel.Pdf.PdfWriter] $Writer = [iText.Kernel.Pdf.PdfWriter]::new($OutputFile) [iText.Kernel.Pdf.PdfDocument] $PDF = [iText.Kernel.Pdf.PdfDocument]::new($Writer) [iText.Kernel.Utils.PdfMerger] $Merger = [iText.Kernel.Utils.PdfMerger]::new($PDF) foreach ($File in $InputFile) { if ($File -and (Test-Path -LiteralPath $File)) { try { $Source = [iText.Kernel.Pdf.PdfReader]::new($File) [iText.Kernel.Pdf.PdfDocument] $SourcePDF = [iText.Kernel.Pdf.PdfDocument]::new($Source) $null = $Merger.merge($SourcePDF, 1, $SourcePDF.getNumberOfPages()) $SourcePDF.close() } catch { $ErrorMessage = $_.Exception.Message Write-Warning "Merge-PDF - Processing document $File failed with error: $ErrorMessage" } } } try { $PDF.Close() } catch { $ErrorMessage = $_.Exception.Message Write-Warning "Merge-PDF - Saving document $OutputFile failed with error: $ErrorMessage" } } else { Write-Warning "Merge-PDF - Output file was empty. Please give a name to file. Terminating." } } function New-InternalPDF { [CmdletBinding()] param([string] $FilePath) $Script:Writer = [iText.Kernel.Pdf.PdfWriter]::new($FilePath) $Script:PDF = [iText.Kernel.Pdf.PdfDocument]::new($writer) } function New-InternalPDFList { [CmdletBinding()] param([System.Collections.IDictionary] $Settings) $List = [iText.Layout.Element.List]::new() if ($null -ne $Settings.Indent) { $null = $List.SetSymbolIndent($Settings.Indent) } if ($Settings.Symbol) { if ($Settings.Symbol -eq 'hyphen') { } elseif ($Settings.Symbol -eq 'bullet') { $Symbol = [regex]::Unescape("\u2022") $null = $List.SetListSymbol($Symbol) } } foreach ($_ in $Settings.Items) { $null = $List.Add([iText.Layout.Element.ListItem]::new($_.Text)) } $null = $Script:Document.Add($List) } function New-InternalPDFOptions { [CmdletBinding()] param([System.Collections.IDictionary] $Settings) if ($Settings.Margins) { if ($Settings.Margins.Left) { $Script:Document.SetLeftMargin($Settings.Margins.Left) } if ($Settings.Margins.Right) { $Script:Document.SetRightMargin($Settings.Margins.Right) } if ($Settings.Margins.Top) { $Script:Document.SetTopMargin($Settings.Margins.Top) } if ($Settings.Margins.Bottom) { $Script:Document.SetBottomMargin($Settings.Margins.Bottom) } } } function New-InternalPDFPage { [CmdletBinding()] param([System.Collections.IDictionary] $Settings) if ($Settings.PageSize -or $Settings.Rotate) { if ($Settings.PageSize) { $PageSize = [iText.Kernel.Geom.PageSize]::($Settings.PageSize) } if ($Settings.Rotate) { if ($PageSize) { $PageSize = $PageSize.Rotate() } else { $PageSize = [iText.Kernel.Geom.PageSize]::A4 $PageSize = $PageSize.Rotate() } } } if ($PageSize) { $null = $Script:PDF.AddNewPage($PageSize) } else { $null = $Script:PDF.AddNewPage() } $Script:Document = [iText.Layout.Document]::new($Script:PDF) } function New-InternalPDFText { [CmdletBinding()] param([System.Collections.IDictionary] $Settings) $Paragraph = [iText.Layout.Element.Paragraph]::new() foreach ($_ in $Settings) { if ($_.Font) { $Font = [iText.IO.Font.Constants.StandardFonts]::($_.Font) $ApplyFont = [iText.Kernel.Font.PdfFontFactory]::CreateFont($Font) $null = $Paragraph.Add($_.Text).SetFont($ApplyFont) } else { $null = $Paragraph.Add($_.Text) } } $null = $Script:Document.add($Paragraph) } function New-PDF { [CmdletBinding()] param([scriptblock] $PDFContent, [string] $FilePath, [nullable[float]] $MarginLeft, [nullable[float]] $MarginRight, [nullable[float]] $MarginTop, [nullable[float]] $MarginBottom, [ValidateScript( { & $Script:PDFPageSizeValidation })][string] $PageSize, [switch] $Rotate, [alias('Open')][switch] $Show) New-InternalPDF -FilePath $FilePath $FirstPage = New-PDFPage -MarginTop $MarginTop -MarginBottom $MarginBottom -MarginLeft $MarginLeft -MarginRight $MarginRight -PageSize $PageSize -Rotate:$Rotate.IsPresent [Array] $Output = @($FirstPage & $PDFContent) foreach ($Element in $Output) { if ($Element.Type -eq 'Page') { New-InternalPDFPage -Settings $Element.Settings } if ($Element.Type -eq 'Text') { New-InternalPDFText -Settings $Element.Settings } if ($Element.Type -eq 'List') { New-InternalPDFList -Settings $Element.Settings } if ($Element.Type -eq 'Paragraph') { } if ($Element.Type -eq 'Options') { New-InternalPDFOptions -Settings $Element.Settings } } $Script:PDF.Close() if ($Show) { if (Test-Path -LiteralPath $FilePath) { Invoke-Item -LiteralPath $FilePath } } } Register-ArgumentCompleter -CommandName New-PDF -ParameterName PageSize -ScriptBlock $Script:PDFPageSize function New-PDFList { [CmdletBinding()] param([ScriptBlock] $ListItems, [nullable[float]] $Indent, [ValidateSet('bullet', 'hyphen')][string] $Symbol = 'hyphen') $Output = & $ListItems $Items = foreach ($_ in $Output) { if ($_.Type -eq 'ListItem') { $_.Settings } } [PSCustomObject] @{Type = 'List' Settings = @{Items = $Items Indent = $Indent Symbol = $Symbol } } } function New-PDFListItem { [CmdletBinding()] param([string] $Text) [PSCustomObject] @{Type = 'ListItem' Settings = @{Text = $Text } } } function New-PDFOptions { [CmdletBinding()] param([nullable[float]] $MarginLeft, [nullable[float]] $MarginRight, [nullable[float]] $MarginTop, [nullable[float]] $MarginBottom, [ValidateScript( { & $Script:PDFPageSizeValidation })][string] $PageSize) [PSCustomObject] @{Type = 'Options' Settings = @{Margins = @{Left = $MarginLeft Right = $MarginRight Top = $MarginTop Bottom = $MarginBottom } PageSize = $PageSize } } } Register-ArgumentCompleter -CommandName New-PDFOptions -ParameterName PageSize -ScriptBlock $Script:PDFPageSize function New-PDFPage { [CmdletBinding()] param([ScriptBlock] $PageContent, [nullable[float]] $MarginLeft, [nullable[float]] $MarginRight, [nullable[float]] $MarginTop, [nullable[float]] $MarginBottom, [ValidateScript( { & $Script:PDFPageSizeValidation })][string] $PageSize, [switch] $Rotate) $Page = [PSCustomObject] @{Type = 'Page' Settings = @{Margins = @{Left = $MarginLeft Right = $MarginRight Top = $MarginTop Bottom = $MarginBottom } PageSize = $PageSize Rotate = $Rotate.IsPresent } } $Page } Register-ArgumentCompleter -CommandName New-PDFPage -ParameterName PageSize -ScriptBlock $Script:PDFPageSize function New-PDFText { [CmdletBinding()] param([string[]] $Text, [ValidateScript( { & $Script:PDFFontValidation })][string] $Font) [PSCustomObject] @{Type = 'Text' Settings = @{Text = $Text Font = $Font } } } Register-ArgumentCompleter -CommandName New-PDFText -ParameterName Font -ScriptBlock $Script:PDFFont function Split-PDF { [CmdletBinding()] param([Parameter(Mandatory)][string] $FilePath, [Parameter(Mandatory)][string] $OutputFolder, [string] $OutputName = 'OutputDocument', [int] $SplitCount = 1) if ($SplitCount -eq 0) { Write-Warning "Split-PDF - SplitCount is 0. Terminating." return } if ($FilePath -and (Test-Path -LiteralPath $FilePath)) { if ($OutputFolder -and (Test-Path -LiteralPath $OutputFolder)) { try { $PDFFile = [iText.Kernel.Pdf.PdfReader]::new($FilePath) $Document = [iText.Kernel.Pdf.PdfDocument]::new($PDFFile) $Splitter = [CustomSplitter]::new($Document, $OutputFolder, $OutputName) $List = $Splitter.SplitByPageCount($SplitCount) foreach ($_ in $List) { $_.Close() } } catch { $ErrorMessage = $_.Exception.Message Write-Warning "Split-PDF - Error has occured: $ErrorMessage" } } else { Write-Warning "Split-PDF - Destination folder $OutputFolder doesn't exists. Terminating." } } else { Write-Warning "Split-PDF - Path $FilePath doesn't exists. Terminating." } } $Script:PDFPageSize = { ([iText.Kernel.Geom.PageSize] | Get-Member -static -MemberType Property).Name } $Script:PDFPageSizeValidation = { $Array = @((& $Script:PDFPageSize) '') $_ -in $Array } $Script:PDFFont = { ([iText.IO.Font.Constants.StandardFonts] | Get-Member -static -MemberType Property).Name } $Script:PDFFontValidation = { $Array = @((& $Script:PDFFont) '') $_ -in $Array } if ($PSEdition -eq 'Core') { Add-Type -Path $PSScriptRoot\Lib\Core\BouncyCastle.Crypto.dll Add-Type -Path $PSScriptRoot\Lib\Core\Common.Logging.Core.dll Add-Type -Path $PSScriptRoot\Lib\Core\Common.Logging.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.barcodes.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.forms.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.hyph.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.io.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.kernel.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.layout.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.pdfa.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.sign.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.styledxmlparser.dll Add-Type -Path $PSScriptRoot\Lib\Core\itext.svg.dll } else { Add-Type -Path $PSScriptRoot\Lib\Default\BouncyCastle.Crypto.dll Add-Type -Path $PSScriptRoot\Lib\Default\Common.Logging.Core.dll Add-Type -Path $PSScriptRoot\Lib\Default\Common.Logging.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.barcodes.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.forms.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.hyph.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.io.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.kernel.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.layout.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.pdfa.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.sign.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.styledxmlparser.dll Add-Type -Path $PSScriptRoot\Lib\Default\itext.svg.dll } Export-ModuleMember -Function @('Convert-PDFToText', 'Merge-PDF', 'New-PDF', 'New-PDFList', 'New-PDFListItem', 'New-PDFOptions', 'New-PDFPage', 'New-PDFText', 'Split-PDF') -Alias @() |