Private/Split-VellumPdfTextLine.ps1
|
function Split-VellumPdfTextLine { <# .SYNOPSIS Breaks text into lines that fit a width, using the real font metrics. .DESCRIPTION Greedy line breaking shared by the text box, table and list cmdlets. A line break in the text starts a new paragraph, an empty paragraph gives an empty line, only spaces and tabs separate words (a no-break space stays inside its word), and a word wider than the width is split at character boundaries. Returns objects with Words (string[]) and Last ($true for the last line of a paragraph, which justified text leaves ragged). #> [CmdletBinding()] [OutputType([pscustomobject[]])] param( [AllowEmptyString()] [Parameter(Mandatory)] [string]$Text, [Parameter(Mandatory)] [double]$Width, [Parameter(Mandatory)] $Resolved, [Parameter(Mandatory)] [double]$FontSize ) $fontResolved = $Resolved $size = $FontSize $measure = { param($s) Measure-VellumPdfTextWidth -Resolved $fontResolved -Text $s -FontSize $size } $lines = [System.Collections.Generic.List[object]]::new() foreach ($paragraph in ($Text -split '\r?\n')) { $words = @($paragraph -split '[ \t]+' | Where-Object { $_ -ne '' }) if ($words.Count -eq 0) { $lines.Add([pscustomobject]@{ Words = [string[]]@(); Last = $true }); continue } $current = [System.Collections.Generic.List[string]]::new() foreach ($word in $words) { $pieces = @($word) if ((& $measure $word) -gt $Width) { $pieces = [System.Collections.Generic.List[string]]::new() $chunk = '' foreach ($rune in $word.EnumerateRunes()) { $next = $chunk + $rune.ToString() if ($chunk -ne '' -and (& $measure $next) -gt $Width) { $pieces.Add($chunk); $chunk = $rune.ToString() } else { $chunk = $next } } if ($chunk -ne '') { $pieces.Add($chunk) } } foreach ($piece in $pieces) { $candidate = if ($current.Count) { ($current -join ' ') + ' ' + $piece } else { $piece } if ($current.Count -and (& $measure $candidate) -gt $Width) { $lines.Add([pscustomobject]@{ Words = $current.ToArray(); Last = $false }) $current = [System.Collections.Generic.List[string]]::new() } $current.Add($piece) } } $lines.Add([pscustomobject]@{ Words = $current.ToArray(); Last = $true }) } , $lines.ToArray() } |