You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Plus a large batch of font/parsing bug fixes (no API change): TrueType simple-font missing widths #1311, CIDFont glyph displacement #1316, CID/CFF glyph naming #1318/#1322, CIDFontType0 OpenType/CFF paths #1321, Type 0/2 CID default widths & vertical displacement #1325, indirect-ref width arrays #1307, encrypted-string BOM decryption #1306, image decode values #1304, malformed CMap duplicate codes #1313/#1319, truncated inline-image EI detection #1329, TJ text-sequence over-increment #1298.
⚠️ Breaking Changes (with migration snippets)
1. PdfFunction.Eval — new abstract span overload (#1301)
The array overload public abstract double[] Eval(params double[]) became virtual, and a new abstract span method was added. Custom PdfFunction subclasses must now override the span version.
// BEFORE (v0.1.14)publicoverridedouble[]Eval(paramsdouble[]input){/* ... */}// AFTER (v0.1.15) — override the span method instead.// Return value is the number of components written into 'output'.publicoverrideintEval(ReadOnlySpan<double>input,Span<double>output){// write results into output, return countoutput[0]= ...;return1;}// The double[] Eval(...) overload now delegates to this automatically.
2. ColorSpaceDetails — new abstract GetRgb (#1301)
Any custom ColorSpaceDetails subclass must implement the new abstract method.
// AFTER (v0.1.15) — add to your custom color space:publicoverridevoidGetRgb(ReadOnlySpan<double>values,outdoubler,outdoubleg,outdoubleb){varcolor=GetColor(values.ToArray());// simplest bridge(r,g,b)=color.ToRGBValues();}
3. ISeekableTokenScanner — new StackDepthGuard member (#1276)
Adding a member to a public interface breaks custom implementers.
// AFTER (v0.1.15) — add to your custom scanner:publicStackDepthGuardStackDepthGuard{get;}=newStackDepthGuard();
4. IOperationContext — new BeginText() / EndText() members (#1294)
Custom IOperationContext implementations must add these. (BaseStreamProcessor provides virtual defaults if you derive from it.)
// AFTER (v0.1.15) — add to your custom operation context:publicvoidBeginText(){/* init text matrices, start clip path */}publicvoidEndText(){/* reset text matrices, apply clip path */}
5. UglyToad.PdfPig.Rendering types removed from the core package (#1323)
IPageImageRenderer and PdfRendererImageFormat were removed from UglyToad.PdfPig.
// AFTER: use the dedicated rendering package(s) instead of the core stubs.// dotnet add package UglyToad.PdfPig.Rendering.Skia// and use that package's renderer API rather than the old core IPageImageRenderer.
6. Nesting-depth errors now throw PdfDocumentStackDepthException (#1310)
Previously this was a PdfDocumentFormatException. It now derives from Exception (not PdfDocumentFormatException), so existing catch blocks won't catch it.
// BEFORE — this used to catch the "max nesting depth exceeded" case:catch(PdfDocumentFormatExceptionex){/* ... */}// AFTER (v0.1.15) — handle it explicitly:catch(PdfDocumentStackDepthExceptionex){/* deeply nested / malicious doc */}catch(PdfDocumentFormatExceptionex){/* other malformed-PDF cases */}
Page dimensions are now derived from the CropBox visible bounds with rotation applied (cropBox.GetVisibleBounds(rotation)), and Size from the CropBox bounds — rather than from the MediaBox∩CropBox intersection. Reported page width/height/size may change for rotated and/or cropped pages. No code change needed, but verify any layout logic that hard-codes expected page sizes.
How to adapt
You read page.Width / page.Height → nothing to do; they still return the visible (rotation‑applied) size in points.
You need the page's on‑screen size but were reading the boxes → switch to Width/Height:
You relied on the old "as‑displayed" crop box rectangle (origin at 0,0, rotation applied) → use the new helper:
// before: page.CropBox.Bounds was already rotated/normalisedvardisplayed=page.CropBox.Bounds;// after: ask for the visible bounds explicitlyvardisplayed=page.CropBox.GetVisibleBounds(page.Rotation);
The old clipping was initialMatrix.Transform(cropBox.Bounds).Normalise(). Since the initial matrix is built from this same crop box, it maps the crop box to the origin and applies the rotation, yielding (0, 0, displayedWidth, displayedHeight), precisely what GetVisibleBounds() returns directly. So the clipping path is identical for all rotations and crop offsets (verified by the rotated/cropped visual-verification and clipping tests).
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Release v0.1.15
Full list of changes: https://github.com/UglyToad/PdfPig/releases/tag/v0.1.15
Disclaimer: the below was generated with assistance of AI
✨ New Features
Microsoft.Bcl.HashCodefor that target). Purely additive.PdfDocument.Open(Stream)with your ownFileStream.FileHeaderOffset.Valuewidenedint → long.ParsingOptions.UseActualText/ActualTextwhen extracting text. Defaults tofalse, so no behavior change unless enabled.TokenScannerexposed viaStructurePdfFunction.Eval(ReadOnlySpan<double>, Span<double>),ColorSpaceDetails.GetRgb(...), span methods onShading./DefaultGray,/DefaultRGB,/DefaultCMYK)RIprocessed inSetNamedGraphicsState()ProcessOperationsis nowvirtual;BeginText/EndTextoverridable;CoreTokenScanner.ClearPreReadByte()/Aactions now extracted.StackDepthGuardexposed viaISeekableTokenScannerDebugTypefor NuGetPlus a large batch of font/parsing bug fixes (no API change): TrueType simple-font missing widths #1311, CIDFont glyph displacement #1316, CID/CFF glyph naming #1318/#1322, CIDFontType0 OpenType/CFF paths #1321, Type 0/2 CID default widths & vertical displacement #1325, indirect-ref width arrays #1307, encrypted-string BOM decryption #1306, image decode values #1304, malformed CMap duplicate codes #1313/#1319, truncated inline-image
EIdetection #1329,TJtext-sequence over-increment #1298.1.
PdfFunction.Eval— new abstract span overload (#1301)The array overload
public abstract double[] Eval(params double[])becamevirtual, and a new abstract span method was added. CustomPdfFunctionsubclasses must now override the span version.2.
ColorSpaceDetails— new abstractGetRgb(#1301)Any custom
ColorSpaceDetailssubclass must implement the new abstract method.3.
ISeekableTokenScanner— newStackDepthGuardmember (#1276)Adding a member to a public interface breaks custom implementers.
4.
IOperationContext— newBeginText()/EndText()members (#1294)Custom
IOperationContextimplementations must add these. (BaseStreamProcessorprovides virtual defaults if you derive from it.)5.
UglyToad.PdfPig.Renderingtypes removed from the core package (#1323)IPageImageRendererandPdfRendererImageFormatwere removed fromUglyToad.PdfPig.6. Nesting-depth errors now throw
PdfDocumentStackDepthException(#1310)Previously this was a
PdfDocumentFormatException. It now derives fromException(notPdfDocumentFormatException), so existing catch blocks won't catch it.7.
Page.Width/Page.Height/Page.Sizerecomputed (#1340) — behavioralPage dimensions are now derived from the CropBox visible bounds with rotation applied (
cropBox.GetVisibleBounds(rotation)), andSizefrom the CropBox bounds — rather than from the MediaBox∩CropBox intersection. Reported page width/height/size may change for rotated and/or cropped pages. No code change needed, but verify any layout logic that hard-codes expected page sizes.How to adapt
page.Width/page.Height→ nothing to do; they still return the visible (rotation‑applied) size in points.The old clipping was
initialMatrix.Transform(cropBox.Bounds).Normalise(). Since the initial matrix is built from this same crop box, it maps the crop box to the origin and applies the rotation, yielding(0, 0, displayedWidth, displayedHeight), precisely whatGetVisibleBounds()returns directly. So the clipping path is identical for all rotations and crop offsets (verified by the rotated/cropped visual-verification and clipping tests).New contributors: @username77 (#1227), @vafle228 (#1292), @VarunSaiTeja (#1307), @jeske (#1308), @OrganizationUsername (#1293), plus the GitHub Actions bot.
All reactions