Repository navigation
Releases
v1.25.0
Highlights
- .NET 11. PdfPecker, PdfPecker.Fluent, PdfPecker.Testing and PdfPecker.Razor gain a
net11.0target next tonet8.0,net9.0andnet10.0, and PdfPecker.Razor's .NET 11 build takesMicrosoft.AspNetCore.Components.Web11.0.0. Thepdfpeckertool keeps installing as a Native AOT executable on a .NET 10 or 11 SDK. - Print-ready output: PDF/X-4 and CMYK.
PdfOptions.PdfXtakes the press's ICC output profile and printing condition and writes a PDF/X-4 file (ISO 15930-7) with the output intent, trim boxes inside the@pagebleed, embedded fonts and sRGB tagged by profile. CSSdevice-cmyk()is written as DeviceCMYK for text, backgrounds, borders, rules and SVG shapes, so black text prints in black ink only. - PDF/A-2a and PDF/A-3a.
PdfConformance.PdfA2aandPdfA3awrite the accessible level: a tagged structure tree and a declared language whateverPdfOptions.Accessibilitysays. They combine with PDF/UA-1, and 3a carries attachments and e-invoices as 3b and 3u do. The CLI takes--pdfa 2aand--pdfa 3a. - Vertical Chinese and Japanese. In
vertical-rlandvertical-lr, CJK characters stand upright with the font's vertical forms, as Chrome draws them (UAX #50);text-orientation(mixed, upright, sideways) andtext-combine-upright: allwork, and images and SVG stay upright in vertical text. - Khmer, Myanmar, Sinhala and Tibetan are shaped as HarfBuzz 14.6.0 does: vowel signs, subscript consonants and stacks are reordered and positioned instead of drawn in text order. All 190 texts of the HarfBuzz reference corpus match.
- Tables across pages. Rows that start, lie under or end a
rowspannow break inside at a page's end as other rows do, as in Chrome, instead of moving to the next page whole; spanning cells leave room for repeated headers, and a spanning cell's extra height is shared over its rows instead of all going to the last. - More CSS: ruby annotations (
<ruby>,<rt>,<rp>) above their base text,text-autospacebetween ideographs and Latin letters or digits,font-paletteand@font-palette-valuesfor colour fonts,font-variant-alternatesand@font-feature-values, and percentage heights inside flex items with a definite flexed or stretched height. - Closer to Chrome: solid underlines, overlines and line-throughs as thick and placed as in Chrome; translucent gradient stops interpolated premultiplied (
linear-gradient(red, rgba(0,0,255,.2))no longer turns pink at once); images keep a givenheightwhenmin-widthormax-widthlimits their width, andmin-width/min-heightapply to images; a flex row with anobject-fit: coverimage moves whole to the next page instead of leaving an empty frame. - PDF renderer: annotations without an appearance stream (notes, highlights, free text and other comments some tools write that way) are drawn in PDF to image and PDF to HTML, as viewers draw them, and the text of such free text is extracted with
IncludeAnnotations. - Hostile input: overridden
var(),attr()andsibling-index()declarations are skipped (a 1.24.0 regression found by the fuzzer: 6.2 s to 1.0 s), SVG filters count the pixels their content fills, the renderer charges the pixel rows that paths cross, font fallback looks at most 64 characters into a cluster, tables and positioned boxes carried through captures count against the relayout budget, and the stops added to translucent gradients are capped.
.NET 8 and 9: 1.25.0 is the last release
Microsoft ended support for .NET 8 and .NET 9 on 10 November 2026. 1.25.0 is the last PdfPecker release that targets
net8.0 and net9.0; the next release targets .NET 10 and later only. 1.25.0 and earlier releases keep working on
.NET 8 and 9. This applies to PdfPecker, PdfPecker.Fluent, PdfPecker.Testing, PdfPecker.Razor and the pdfpecker tool.
Behaviour changes
- Ruby is laid out.
<rt>annotations now sit above their base at half the font size and<rp>parentheses are no longer drawn; before, the annotation ran inline after its base. - Rows under a
rowspanbreak across pages, so tables with spanning cells can take fewer pages and break in different places than in 1.24.0. - Solid text decorations are a tenth of the font size thick in whole pixels (they were 5.5%), and the overline stands on the ascent.
- Annotations without an appearance stream are drawn by
PdfToImage,PdfRendererandPdfToHtml; 1.24.0 skipped them. - PdfPecker.Razor depends on
Microsoft.AspNetCore.Components.Web8.0.34, 9.0.23, 10.0.15 and 11.0.0, the November patches.
Output changes
Golden baselines changed:
features/text-decoration,features/text-styling,features/font-face-metrics,markdown/demoandmarkdown/report, and the fluent goldenstext,extrasandcatalogue: only their solid underlines, overlines and line-throughs, now as thick and placed as in Chrome.features/table-rowspan-breaks: spanning cells break across pages as in Chrome (3 pages instead of 4) and the rows beside a tall spanning cell share its height.features/table-visibility-collapse: in case 4 the span's height is shared between its rows instead of all going to the last.
The new golden page complex/vertical-cjk adds a baseline and changes none.
Other documents change when they use what changed: solid text decorations, tables with rowspan, vertical text with CJK characters or images, Khmer, Myanmar, Sinhala or Tibetan text, <ruby>, images with min-width, max-width, min-height or max-height, flex rows with object-fit: cover images at a page end, percentage heights in flex items, and CSS gradients between translucent stops of different colours. Documents without device-cmyk(), PdfX or level A conformance are otherwise unchanged.
The manual for this version: https://pdfpecker.net/docs/
Full Changelog: v1.24.0...v1.25.0
v1.24.0
Highlights
- Text extraction in reading order.
PdfTextnow reads a tagged PDF in the order of its structure tree, and columns, boxes and text set side by side one after the other instead of across the page line by line. It also reads columns of unequal length, right-to-left columns from the right, pages turned with/Rotate, vertical CJK writing drawn letter by letter, skewed scans, Arabic words joined by cursive attachment, and numbers in Hebrew and Arabic lines with their separators and signs.PdfTextOptions.Order = PdfTextOrder.TopToBottomgives the 1.23.0 order back. Thai, Indic and Arabic text now copies and extracts as the letters written in PdfPecker's PDFs (Poppler, MuPDF and PdfText alike), also on SVG text paths. - Faster text, Markdown and structured HTML from PDFs. Text extraction,
PdfToMarkdownand structuredPdfToHtmlallocate about half as much and run 44 to 57% faster than before the speed work; the 30-page report extracts 27% faster than in 1.23.0 even in reading order. Tables whose cells draw their own borders (the CSS default) are now found as tables. - PDF redaction.
PdfRedactor.RedactandRedactTexttake text, image pixels, shapes, links and form fields out of given areas, or wherever a text or regular expression matches, instead of only covering them. The rest of the text keeps its place, partly covered images are written again with those pixels painted over, and the originals of redacted images and forms leave the file. - Barcode reader.
Barcode.Readreads QR codes, Data Matrix (square, rectangular and DMRE), Code 128 and EAN-13 from images, andPdfBarcodes.Findfrom PDF pages, with the corners, a GS1 flag and EPC and Swiss QR-bill payments parsed back. - Image pixels for OCR and image pipelines.
ImageToPixels.Convertdecodes PNG, JPEG, GIF, WebP, BMP and TIFF (any page) straight to grey, RGB or RGBA pixels, andPdfRenderer.RenderPagecan render into a caller's buffer as grey, RGB or RGBA. A 300 dpi A4 PNG decodes in 98 ms instead of 341 ms through a PDF, with 12.6 MB allocated instead of 227 MB. Rendering scanned pages one after another keeps far less memory. - Native command line tool. On a .NET 10 SDK,
dotnet tool install -g PdfPecker.Cliinstalls a Native AOT executable for Linux (glibc and musl), macOS and Windows, x64 and Arm64: the sample invoice converts in 17 ms instead of 355 ms. .NET 8 and 9 SDKs install the framework-dependent tool as before. On Windows the native tool starts throughpdfpecker.cmd. - Deferred fonts and hyphenation patterns.
FontCollection.AddDeferredregisters a face by family, weight, style and unicode-range and reads it only when a document needs it, andHyphenationPatterns.Deferreddoes the same for patterns. Font fallback skips families whose ranges cannot draw a character. CFF subsets of fonts such as Noto CJK are much smaller (a few Chinese characters in Noto Sans SC: 1.93 MB to 133 KB). - More CSS:
@page { bleed; marks: crop cross }with trim and bleed boxes,@page :nth()and page groups (:nth(1 of chapter)),if()withmedia(),supports()andstyle(),sibling-index()andsibling-count(),contrast-color(),object-view-box, inset box shadows on inline boxes, borders of<col>and<colgroup>in collapsed tables,visibility: collapseon table rows and columns,revertandrevert-layeron every property, and contextual alternates (calt,clig,rclt) by default, as Chrome applies them, so fonts such as Inter and Fira Code draw their arrows and programming ligatures. Fonts' Unicode variation sequences (cmap format 14) draw their variant glyphs. - Closer to Chrome: table headers and footers across page breaks (repeated only up to a quarter of the page, a table moved whole when its header does not fit, spacing dropped at a break), spanning cells that no longer run past the page end, grid
frrows of indefinite height and items spanning flexible columns, intrinsic widths that keepmin-widthand the automatic minimum of grid and flex items, column flex boxes with amin-height, border spacing in whole pixels, letter spacing that skips hidden characters, invisible characters no longer drawn as?or boxes, HTML character references decoded as browsers do (all 2,231 names), links inside transformed elements, and in SVGcurrentColorand fonts inherited through<use>, lengths with units, nestedsvgviewports and symbols clipped to their viewport. - Faster images: PNG encoding 19% faster, WebP 28 to 32% (PDF to HTML 12 to 15%, 65% less allocated), TIFF 14%, JPEG encoding 29% and decoding 25 to 35%, with pages of photos rendering 17 to 38% faster and multi-page conversions reusing their pixel buffers. Output bytes are unchanged.
- PDF renderer: non-isolated transparency groups blend with what is below them, transparency groups and soft masks cost only the area they draw (pages of hundreds of translucent boxes that were too complex at 300 dpi now render in milliseconds), Type 3 text honours invisible and clipping render modes, and colour spaces and functions are parsed once per document.
- Unicode normalization of its own. NFC, NFD, NFKC and NFKD come from the library's tables, so shaping, hyphenation and passwords behave the same with invariant globalization (Native AOT, containers) as on desktop .NET.
- Signatures: signatures are verified against the revision they signed, so a certification cannot be stripped by a later update, and the byte range check now also runs in encrypted files.
- PdfPecker.Fluent: vertical alignment in page headers, content and footers (
Content().AlignMiddle()centres a cover title as in QuestPDF), border calls in a row merge into one border, and braces in band Markdown stay text. - Hostile input: CMaps, colour spaces, functions, inline images, tagged tables, combining marks, nested flex items, foreign objects, columns in columns, blurred shadows and redaction areas are bounded, and object streams are decoded on the file's budget, so a page renders the same whatever was rendered before it.
Behaviour changes
- AES-256 passwords are prepared with SASLprep (ISO 32000-2), as pypdf and PDFBox do. Setting a password with control, private-use or bidi control characters, or with code points Unicode 3.2 did not assign (most emoji), now throws
ArgumentException. Files encrypted by 1.23.0 or other tools with such passwords still open. PdfTextreads in reading order by default. Multi-column and side-by-side pages give different text from 1.23.0; setPdfTextOptions.Order = PdfTextOrder.TopToBottomfor the old order.PdfSanitizerkeeps only http, https, mailto and tel links, and drops relative ones. A damaged file is written out again from what PdfPecker read; intact files still come back byte for byte.pdfpecker convert -reads local files only from--base-dir, no longer from the current folder. Pass--base-dir .to keep relative images working with piped HTML.- The LTV client never uses a proxy; a caller who needs one supplies an
HttpClient.convertandstampget-envforms of their password options. - The CLI with several inputs now keeps encryption, PDF/A, linearization and the creation date for the merged file, and
[page]and[topage]count the whole output as in wkhtmltopdf. PDF/A-4 and PDF/UA-2 with several inputs are refused with exit code 2.
Output changes
Golden baselines changed:
complex/scripts,features/tables,features/units-fonts,features/selectors-cascadeandrtl/demo:/ActualTextspans around Devanagari, Thai, Arabic and Hebrew clusters, so they copy as written. The pages render the same.complex/dashboard,features/effects,inline-borders/demoandtransparency/demo: transparency groups and soft masks get a bounding box round what they paint instead of the whole plane. The pages render the same, and faster in MuPDF and Poppler.features/images: SVG symbols are clipped to their viewport (pixel for pixel the same page).features/tables:border-spacing: 2ptis now 2px, as in Chrome.subgrid/demo: an item spanning1frandautocolumns no longer widens the auto column.
New golden pages features/contextual-alternates, features/table-column-borders, features/table-rowspan-breaks and features/table-visibility-collapse add baselines and change none.
Other documents change when they use what changed: fonts with contextual alternates, tables with border spacing in points or ems, tables that break across pages with headers, footers or spanning cells, grids with fr rows or spanning items, boxes with a min-width wider than their content, revert, invalid var() (the property is now unset), named character references in attributes, default ignorable characters, letter spacing next to hidden or supplementary characters, links in transformed elements, SVG sprites and symbols, and translucent boxes with a blend mode inside (now written as isolated groups).
The manual for this version: https://pdfpecker.net/docs/v1.24.0/
Full Changelog: v1.23.0...v1.24.0
v1.23.0
Highlights
- Three new packages, released with PdfPecker under the same version:
- PdfPecker.Cli, the
pdfpeckerdotnet tool:convert(HTML or Markdown, files or standard input),watch,merge,split,extract,remove,rotate,stamp,compact,linearize,sanitize,sign,verify,encrypt,decrypt,to-image,to-html,textandinfo. A call without a command reads wkhtmltopdf's options, header and footer texts included. It has no dependencies and refuses web addresses. - PdfPecker.Razor:
RazorToPdfrenders a.razorcomponent with Microsoft'sHtmlRendererand converts it, so templates get typed parameters, child components, layouts and dependency injection without an ASP.NET Core host. Trimmable and AOT-compatible. - PdfPecker.Testing:
PdfAssert.MatchesSnapshotcompares a PDF with a stored one object by object, ignoring dates and IDs, and writes expected, actual and diff page images when they differ;ContainsText,DoesNotContainTextandHasPageCountcheck the rest. No test framework dependency.
- PdfPecker.Cli, the
- Existing PDFs to PDF/A.
PdfToPdfA.Convertturns a PDF from any tool into PDF/A-2b, 2u, 3b or 3u without rasterizing it: it embeds missing fonts, repairs embedded TrueType programs, adds the output intent and XMP metadata, removes forbidden actions and gives annotations appearances, and reports what it changed and what it could not fix. veraPDF checks all four levels in CI. - PDF to Markdown.
PdfToMarkdownwrites the structure PdfToHtml finds as GitHub Flavored Markdown: headings, paragraphs, lists, bold and italic, links and pipe tables. - Barcodes:
Barcode.DataMatrixandBarcode.Gs1DataMatrix(ECC 200, GS1 element strings with FNC1), and Swiss QR-bills:SwissQrBillbuilds and checks the payload (IBAN, QR-IBAN, QR and creditor references) andBarcode.SwissQrCodedraws it with the Swiss cross. - Empty signature fields. An element with
data-pdf-signature="Name"becomes an empty signature field thatPdfSignersigns later withFieldName = "Name", tagged as PDF/UA asks. - Templates from Prince, WeasyPrint and Chrome: running elements in page-margin boxes (
position: running(name)withcontent: element(name), picked byfirst,start,lastandfirst-except),@scopefor component styles, CSSzoomas Chrome computes it, and even-page headers and footers (data-sticky-pdf-even-headeranddata-sticky-pdf-even-footer) for documents printed on both sides. - More CSS: typed
attr()in any property (CSS Values 5, as in Chrome 133), gap decorations in grid and flex containers (row-rule,column-rulelists,rule-break,rule-inset),box-decoration-break: clonefor block boxes split across pages,size-adjust,ascent-override,descent-overrideandline-gap-overridein@font-face,target-counters(),white-space-collapse,hyphenate-limit-lines,accent-colorandappearance: nonefor check boxes and radio buttons,:in-rangeand:out-of-range,image-rendering: pixelatedandcrisp-edges,continue: discard,@page { size: 80mm auto }for pages as tall as their content, and in SVGvector-effect: non-scaling-stroke, CSStransformwithtransform-box, and the geometry (cx,r,d, ...) and gradient stop properties from style sheets. - PdfPecker's own properties:
-pdfpecker-repeat: each-pagedraws a box again on its parent's later pages, and-pdfpecker-image-qualityand-pdfpecker-image-max-resolutionmake PDFs with photos smaller. - Page numbers in any style: the
{page},{pages},{total-pages}and{section-page:id}tokens in running headers and footers take a counter style, such as{page:upper-roman}, including the document's@counter-stylerules. - Tagged PDF:
role="math"becomes a Formula with its alternative text,role="doc-index"an Index,role="doc-toc"a TOC with TOCI entries, anddata-pdf-list-labelmarks a hand-made list label as Lbl. - Closer to Chrome: shapes drawn by an SVG
<use>inherit its fill and stroke (sprite icons, MathJax formulas in coloured text), the SVG viewBox scale is exact (MathJax formulas no longer lose their last glyph), andposition: fixedboxes such as watermarks paint over the running headers and footers. - Existing PDFs:
PdfLinearizerlinearizes and encrypts in one pass, and opens encrypted input with its password. - PdfPecker.Fluent: more QuestPDF calls port unchanged:
DocumentOperation(merge, overlay, underlay, attachments, encrypt, linearize),ImageandSvgImageobjects withWithCompressionQuality,WithRasterDpiand the document image settings, pageBackgroundandForeground,Repeat,StopPaging,ContinuousSize,ExtendLastCellsToTableBottom,Overline,BreakAnywhere, the direction calls and everySemantic*call,Format(PageNumberFormat)for page numbers, gradients andOpacity.Document.Merge,EvenPageHeaderandEvenPageFooter,HyphenateandLanguage. New:Chart(column, bar, line and pie charts),Leaderin text,Markdowncontent,TableOfContentsfrom headings,SignatureField,DataMatrix,Gs1DataMatrix,SwissQrCodeand the wholeSwissQrBillpayment part with its receipt. - Hostile input and speed: a line's footnotes are handed on in linear time (10,000 footnotes on one line in 0.85 s instead of 21 s), stacked floats are no longer quadratic (60,000 floats in 0.3 s instead of 7.1 s),
@scopelimits are found in one walk (21 s to 2.4 s for the worst case),PdfSanitizerremoves active annotations in one pass (35 s to under a second), SVG foreign objects inside patterns and masks no longer throw, and character references such as�decode as U+FFFD instead of throwing.
Output changes
Golden baselines changed only where inline SVG is drawn: the viewBox scale is now written with six decimals instead of three, which moves SVG drawings by a fraction of a point (complex/svg-charts, features/images, features/paged-content, image-formats/demo, svg-effects/demo, translucent-effects/demo, and the fluent catalogue and invoice through their barcodes). Documents with inline SVG, especially formulas with large viewBoxes, can therefore differ byte for byte from 1.22.0. New golden pages (features/math-svg, svg-css-geometry, svg-effects/non-scaling-stroke-transform-box, box-decoration-break/demo, features/font-face-metrics, features/gap-decorations, features/attr-charts) add baselines and change none.
Other documents change only when they use a new feature: shapes inside <use> that set no paint of their own now take the <use> element's, and fixed boxes with a z-index of auto or more now paint over the running headers and footers.
The manual for this version: https://pdfpecker.net/docs/v1.23.0/
Full Changelog: v1.22.0...v1.23.0
v1.22.0
Highlights
- Page numbers anywhere.
counter(pages)gives the page count in the content, not only in the page-margin boxes, as in Prince, and-pdfpecker-target-pages()gives the first and last page of a section, how many pages it covers and the page within it, also on elements without an id ({section-page:name}in running headers and footers). - Removing active content.
PdfSanitizer.RemoveActiveContenttakes JavaScript, actions that launch programs, open other files or submit form data, XFA and media annotations out of PDFs from others, andHasActiveContenttells whether a PDF has any. Pages, text, links and form fields stay. - Safer signatures and long-term validation. SHA-1 signatures are no longer
ValidunlessPdfSignatureVerificationOptions.AllowSha1is set (PdfSignatureVerification.UsesSha1says why); verification catches shadow attacks that redirect the cross-reference table after a certification and a dropped/Perms; andFetchRevocationDatafetches OCSP and CRL data only from public addresses unless aUrlFilterallows others. - More CSS: the
gridshorthand, thestretchsizing keyword and-webkit-fill-availablefor widths, heights and their limits,image-set()in backgrounds, list markers and generated content,text-box,text-box-trimandtext-box-edge(lines trimmed to the cap height and baseline, as Chrome trims them),corner-shape(squircle, bevel, scoop, notch andsuperellipse()corners),overflow-clip-margin,rect()andxywh()inclip-pathandshape-outside,text-emphasis,text-indentwithhanging,each-lineand percentages,font-width,:valid,:invalidand:open, borders, padding and background images on the@pagebox, and backgrounds on::first-line. ::markeras in Chrome: a larger marker font or a tall marker image makes its line taller,content: nonehides the marker,counter(list-item)numbers it, and its owndirectionorders its text.- Closer to Chrome: icons drawn with
<use>from a hidden SVG sprite (as in Bootstrap), a forced break before a box's first child breaks before the whole box (so tables of contents point at the right page), images and inline-blocks aligned totext-topandtext-bottom, SVG backgrounds without aviewBoxscaled tobackground-size, flex rows break inside their items at a page's end, quirks-mode line heights, square dots for thin dotted borders, percentage lengths in inline SVG, percentage heights in table cells that span rows, auto margins on floats, the legacy body margin attributes, border-image number widths in standards mode, and a whole shorthand dropped when one part has a unitless length. - Fonts: fonts whose only Unicode cmap is format 10 or 13, such as last-resort fonts, are used by HTML to PDF instead of falling back to Helvetica.
PdfOptions.Clone()copies shared options so one setting can change without touching the others.- PdfPecker.Fluent: page numbers and the page count in the content,
EndPageNumberOfSection,TotalPagesWithinSectionandPageNumberWithinSection, and cell backgrounds and borders that fill the row in any call order. - Hostile input and speed: a total budget for decoded object streams (a 4 MB file could make 9 GB), bounded stream decoding outside a render scope, rasterizer coordinates kept finite, a bounded cache of pattern tiles in the renderer, and fuzzing fixes for JPEG scans, footnote calls, grid items, very tall split table rows and large paginated grids (60,000 grid items lay out in 0.4 s instead of 7.4 s). Text measured with a font-family list allocates about a third of what it did in 1.21.0, and invoices allocate about an eighth less.
Output changes
Golden baselines changed where the output now matches Chrome more closely: square dots for thin dotted borders (features/images, inline-borders/demo), images aligned to text-top (features/images and the PDF-to-HTML pdf-to-html/features-images made from it) and quirks-mode line heights (forms/demo, which has no doctype). Documents without a doctype can have shorter lines of small text and shorter table cells holding only an image; documents with flex rows that cross a page now break inside the row instead of moving it to the next page whole, and a section whose first child has break-before: page now starts on the new page together with its border and background. Eight new golden pages cover the features since 1.17.0; they add baselines and change none.
Verification results change for SHA-1 signatures, which are now reported as not valid; set AllowSha1 to accept them for old archives.
The manual for this version: https://pdfpecker.net/docs/v1.22.0/
Full Changelog: v1.21.0...v1.22.0
v1.21.0
Highlights
- Tables across pages, as in Chrome. A row that does not fit at the bottom of a page now breaks inside, cell by cell, instead of moving to the next page whole, and the repeated header and footer close each page around it.
break-beforeandbreak-afterwork on rows and row groups,break-inside: avoidon atbody(orbreak-after: avoidon a group's header row) keeps a group together, a kept box taller than a page starts on the next page, and a collapsed table closes with its own border on every page it crosses. - Colour fonts. Text in COLR colour fonts (versions 0 and 1, such as Noto Color Emoji) prints in colour as Chrome prints it, stays searchable text, and passes veraPDF for every PDF/A and PDF/UA profile. Skin tones, flags and zero width joiner sequences join.
- Structured PDF to HTML.
PdfHtmlMode.Structuredwrites a PDF's text as headings, paragraphs, lists and real tables, reads tagged PDFs from their structure tree, and withPdfHtmlOptions.IncludeStylesandIncludeImageskeeps fonts, colours, filled boxes, table borders and images. Column and row detection was measured on the ICDAR 2013 table set. - Acid2 passes. CSS error recovery, escapes in selectors, margin collapsing with mixed signs, mitred border corners, empty CSS tables, a stray
</p>, unitless lengths only in quirks mode, stylesheets indata:URLs and fixed boxes painting byz-indexnow behave as in browsers, taking the Acid2 face from 26% to 99% of Chrome's pixels. - More CSS and HTML:
srcset,sizesand<picture>; images and gradients in::beforeand::aftercontent; gradient colour interpolation (in oklch,in oklab,hsl longer hue, as Tailwind 4 writes); gradient list markers; bookmarks from CSS (bookmark-level,bookmark-label,bookmark-state);block-ellipsis;image-orientationfrom EXIF;text-underline-position; legacyclip: rect();background-attachment: fixed; pictures in<embed>and<object>; HTML inside SVGforeignObject; SVGcontext-fillandcontext-stroke; Charts.css charts; old-webkit-syntax; floats and sized boxes in vertical writing modes and left-to-right line order invertical-lr; absolutely positioned boxes inside positioned inline elements. - Closer to Chrome: outlines and dashed or dotted borders with Chrome's corners and 3D shades, the outline of a wrapped inline as one shape, percentage table columns that fill the table, stretched images and stretched items in flex and grid, a smaller default size for bare monospace text, images on whole CSS pixels,
break-allandoverflow-wrap: anywhereshrinking table cells, forced page breaks between flex lines, bottom margins truncated at page breaks, and row backgrounds that no longer cover collapsed borders. - Named pages: a header or footer with
data-sticky-pdf-page="name"belongs to the pages of that named page. - PdfPecker.Fluent: several
Pagecalls become named pages of one document, so page numbers, links, PDF/A, PDF/UA and signatures work across them andGenerateHtmlaccepts them; newTextField,CheckBox,RadioButton,ComboBox,ListBoxand footnotes;ScaleToFit,ShowOnceandSkipOnce; a much faster QR code mask choice. - Hostile input: limits on generated-content images and on colour-font paints per document keep both within bounded time and memory, and a fuzzing fix keeps the layer order of headers and footers with page numbers per page.
Output changes
Golden baselines changed where the output now matches Chrome more closely: dashed and dotted border fitting (background-image/demo, complex/cjk, complex/flex-grid, complex/invoice, css3/demo, features/anonymous-boxes, features/images, features/tables, features/text-wrap, inline-borders/demo, layout-fixes/box-edges, multicol/demo, overflow-clip/demo, small-css-gaps/demo, transparency/demo and the fluent extras), 3D border shades (layout-fixes/registration, svg-effects/demo), row backgrounds under collapsed borders (css3/demo, features/tables, large-table/demo and the operations/encrypt, merge and stamp built from them), images on whole CSS pixels (image-formats/demo and the fluent catalogue and invoice), vertical-lr headers (features/selectors-cascade, pixel-identical) and table rows breaking inside at a page's end (complex/cjk). Documents with long tables can now break rows where they used to move them whole; break-inside: avoid on a row keeps the old behaviour.
The manual for this version: https://pdfpecker.net/docs/v1.21.0/
Full Changelog: v1.20.0...v1.21.0
v1.20.0
Highlights
- Linearized output for Fast Web View.
PdfOptions.Linearize = truewrites a linearized PDF, and the newPdfLinearizerlinearizes any existing PDF, such as a merged one, so a viewer loading it over the web shows the first page before the rest has arrived. Checked with qpdf, and PDF/A, PDF/UA and encryption stay valid. - Certification (DocMDP) signatures.
PdfSignatureOptions.Certificationmakes the first signature a certification signature at level 1 (no changes), 2 (form filling and signing) or 3 (also annotations), andPdfSignatureVerifierreports theCertificationLeveland anyDisallowedChangesmade after it. Checked with pyHanko. - Viewer settings and page labels.
PdfOptions.Viewersets how a viewer opens the PDF (start page and zoom, page layout, bookmarks or thumbnails panel, full screen, window preferences, print scaling and duplex), andPdfOptions.PageLabelsnumbers pages the way the viewer shows them, such as roman numerals for front matter.PdfMergeOptionshas both too. - Reading existing PDFs:
PdfDocumentProperties.Readgives the title, author, dates, custom properties, PDF version, page sizes, encryption and permissions, claimed PDF/A and PDF/UA conformance, and whether the file is tagged or linearized.PdfImages.Extractreturns the images the pages draw, each once with where it is drawn, with JPEGs as their original bytes and the rest as PNG, and their EXIF and XMP metadata. - Privacy:
PdfOptions.StripImageMetadataremoves EXIF (camera, time, GPS location), XMP, IPTC and comments from embedded JPEGs, and keeps the colour profile, so the images look the same. - PDF to HTML: the browser's find now matches phrases in the text layer, not only single words, and the text layer is about 30% smaller.
- Fixes: a heading's bookmark in a grid row that crosses a page points at the heading, blurred box shadows no longer show a thin line at their outer edge in Poppler-based viewers, words with letters outside the Basic Multilingual Plane hyphenate without failing, and SVG text inside many nested translucent groups gets its font.
- Faster running headers and footers: a sticky header or footer without page numbers is laid out once instead of on every page.
- Hostile input: fuzzing fixes keep nested columns, flex rows, keep-with-next chains, running bands, CID font widths, JBIG2, JPEG 2000, SVG and filter regions within bounded time and memory.
- PdfPecker.Fluent copies the new
Viewer,PageLabels,LinearizeandStripImageMetadataoptions (a document of several page sets is linearized once, after merging), andHyperlinkno longer lets anIndexOutOfRangeExceptionfromSystem.Urithrough for some file and UNC paths.
Output changes
Golden baselines changed only by an /I true on the soft mask of each blurred box shadow (complex/dashboard, features/images, translucent-effects/demo, transparency/demo and the fluent extras), which PDFium renders pixel for pixel the same, and by the new text-layer markup in the three PdfToHtml baselines. Without the new options, output is otherwise byte-identical to 1.19.0 except for documents that hit the fixes: bookmarks of headings in grid rows that cross a page, and very deeply nested or hostile documents.
The manual for this version: https://pdfpecker.net/docs/v1.20.0/
Full Changelog: v1.19.0...v1.20.0
v1.19.0
Highlights
- PdfPecker.Fluent is on nuget.org. A fluent C# API in the style of QuestPDF (pages, headers, footers, columns, rows, tables, text, images and barcodes in code) that writes HTML and CSS and renders it with PdfPecker. It is released with every PdfPecker release under the same version, and its only dependency is PdfPecker.
dotnet add package PdfPecker.Fluent - Faster repeated conversions. Documents made from one template now reuse their fonts and font subsets, parsed CSS declaration blocks and the PDF writer's buffers between conversions: an invoice is about 10% faster with 8% fewer allocations, and documents with web fonts gain the most. Output is byte-identical.
- New CSS:
-pdfpecker-scale-to-fit: shrinkscales a box's content down to fit its height, anddata-sticky-pdf-first-header/data-sticky-pdf-first-footergive the first page a header or footer of its own (or none). - Layout fixes against Chrome: positioned boxes paint in document order, absolutely positioned children of flex and grid containers are placed as Chrome places them,
vertical-align: top/bottommoves a span's whole content,<br>directly in a flex container keeps one anonymous item, and words that may break stay whole in a shrink-to-fit box. - PDF to image and HTML: faster lossless WebP encoding (same bytes), a lower default WebP effort that makes WebP output about 44% faster to encode and 1% larger (
Qualitynow defaults to 85 for JPEG and 29 for WebP; setQuality = 85for the old WebP bytes), masks finer than their image keep their resolution, Type 3 fonts at their own scale keep their words whole, and mesh-shading fills no longer allocate a page-sized layer each. - Hostile input: fuzzing fixes keep deeply nested columns, flex boxes, tables, backdrop filters and long runs of combining marks within bounded time and memory.
Output changes
No golden baseline changed. Output differs from 1.18.0 only for documents that hit the fixes: pages with overlapping positioned boxes, positioned children of flex and grid boxes, vertical-align: top or bottom spans holding other boxes and <br> in flex containers look different, and WebP images at the default quality have different bytes but the same pixels.
The manual for this version: https://pdfpecker.net/docs/v1.19.0/
Full Changelog: v1.18.0...v1.19.0
v1.18.0
Highlights
- Shrink to fit: a page whose content sticks out past the right edge (a wide table
or image, a long URL,nowraptext, a Bootstrap.rowwithout a container) is laid out wider and drawn smaller,
as Chrome prints it, up to 1.5 times. It is on by default;ShrinkToFit = falsekeeps the 1.17.0 layout. An image
wider than the page now shrinks the page instead of being squeezed on its own. - Fallback fonts: characters none of the document's fonts has are drawn
with built-in fonts, as browsers use system fonts: Central European, Greek and Cyrillic letters with the bundled
Liberation fonts (no more?with the standard fonts), and arrows, check marks, stars, dingbats, math and box
drawing with PdfPecker Symbols, a DejaVu Sans subset. Documents that need no fallback come out byte-identical. - Positioning: absolutely positioned children of flex and grid containers (corner ribbons, sale badges) take no room
and are placed by their offsets, aposition: relativetable cell holds its positioned content, and outlines on
cells of a collapsed table are drawn. - Logical border properties (
border-inline,border-block-startand the rest,
and the logical radii), and logical margins, paddings and insets now followwriting-modetoo. - Fractions with
diagonal-fractionsorfont-feature-settings: "frac"are formed as in Chrome. - Fixes, all closer to Chrome: an empty clearfix
divand<br clear=all>clear floats;vertical-align: top,
middleandtext-topwork on smaller inline text; auto margins on inline-blocks count as 0; a flex or grid item
keeps its first and last child's margins; percentage columns that crowd out other columns give way and a cell's
max-widthcaps its column (with an ellipsis where asked); an image with a percentage width no longer widens a
table; a box shadow never adds a blank page;backdrop-filterworks at every box size; the default<hr>has
Chrome's lighter shading,<hr size>,colorandnoshadework, and a margin on a vertical inline-block no
longer counts twice. - About 10% faster on invoices, feature tours and reports than 1.17.0, with byte-identical output.
- Pages with content wider than the page area, clearfix divs, floats, tables with percentage columns or capped cells,
inline-blocks with auto margins and default<hr>rules look different from 1.17.0.
The manual for this version: https://pdfpecker.net/docs/v1.18.0/
Full Changelog: v1.17.0...v1.18.0
v1.17.0
Highlights
- PDF to HTML:
PdfToHtmlturns any PDF into one self-contained HTML page, with the page images,
an invisible text layer that can be selected, searched and read aloud, and working links. - Float shapes (
shape-outside,shape-margin,shape-image-threshold),
drop caps withinitial-letter, masks andbackdrop-filter
on HTML elements,display: contents,
3D transforms drawn flat, and vertical text
withwriting-mode. - Text wrapping and justification:
text-wrap: balanceand
pretty, andtext-justify; justified Chinese and Japanese text is spread between characters, as in Chrome. - CJK punctuation trimming with
text-spacing-trim. CJK text with
adjacent punctuation is narrower than before and can break into lines differently;text-spacing-trim: space-all
keeps the old spacing. - Text: underlines and overlines skip descenders (
text-decoration-skip-ink), dashed, dotted, double and wavy lines
are drawn as Chrome draws them, outlined text with-webkit-text-strokeandpaint-order, nested superscripts, and
font propertiesfont-kerning,font-synthesis,font-size-adjust,
font-variant-positionandfont-variant-east-asian, with the font's own small capitals and the@font-face
font-stretchdescriptor. - Units measured from the font (
ex,ch,cap,ic,lhand the root versions), the viewport unitsvi,vb,
svh,dvhand the rest,q, and the logicalinset-inline,inset-block,inline-sizeandblock-size. width: min-content,max-contentandfit-content, wrapping column flex boxes,min-width: 0on flex items,
capped gridfit-content()tracks, and flex items taller than their row staying in place (Bootstrap progress bars).- Tables: CSS tables on any element with anonymous table boxes,
inline-table, row group
and column backgrounds,caption-side,empty-cells, cellmin-widthandmax-width, column widths under spanning
cells and percentages over 100% shared out as in Chrome, long words widening a table instead of overflowing, and
collapsed borders resolved as in Chrome, on rows and row groups too. - HTML:
<details>,<progress>and<meter>,list-style-position: inside, old attributes (img align,hspace,
table bordercolorandrules, listtype,reversed,align=center), and thehtml,headandbody
elements a fragment leaves out (an implied body has no default margin, so fragments keep their layout). - Images: a missing image prints its alt text, inline images draw their border, padding, background and shadow, take
vertical margins in the line, and resolve percentage widths against the containing block, as in Chrome. - Selectors and the cascade:
:dir(),::placeholder, thequotesproperty (alsoautoby language), theall
property and CSS-wide keywords on shorthands;vertical-alignlengths and percentages. - SVG:
useof a symbol from another inline SVG, symbolviewBoxfitting, groupopacity, andtext-decorationon
SVG text. Gradients and background tiles turn and scale with transformed boxes. - Despite the new features, warm conversions are within a few percent of 1.16.0's speed. Bounded work for nested columns,
tables, generated content and backdrop filters on hostile input. - Tables with colspans, percentages, long words or collapsed borders, lines with superscripts, decorated text,
inline images and justified CJK text look different from 1.16.0, closer to Chrome.
The manual for this version: https://pdfpecker.net/docs/v1.17.0/
Full Changelog: v1.16.0...v1.17.0
v1.16.0
Highlights
- Borders on inline elements: badges, keyboard keys and dotted underlines drawn
withborderon a<span>are painted, withbox-decoration-breakdeciding how a border split over several lines
is drawn. - SVG dashed strokes with
stroke-dasharray,stroke-dashoffsetandpathLength, and text
along a path withtextPath. - Grid rows break across pages where they start instead of moving whole and leaving a
gap, and a margin that runs past the end of a page is dropped, as in Chrome. A box's top and bottom borders stay on
the page with its content, and a paragraph that ends just past the page keeps its widows. - A
<fieldset>'s legend sits on its top border, and groove and ridge borders have Chrome's two shades. - Form controls are sized as in Chrome: text fields in tables, textarea rows, drop-downs, date fields and check boxes,
and controls the page gives its own border have Chrome's plain square look. - Text can break before and after inline-blocks, images and form controls, so a label no longer wraps a word down
next to its input. - Line heights are rounded to Chrome's layout units, and line breaking counts the kerning next to spaces, so lines
break where Chrome breaks them more often. - Text extraction reads the standard Symbol and ZapfDingbats fonts (αβγ, ✓✔) instead of returning their raw codes.
- Bounded layout time for deeply nested flex, grid, tables, columns and keep-with-next chains found by fuzzing.
- Line positions, page breaks, forms, fieldsets and SVG dashes look different from 1.15.0; most documents move by a
pixel or less.
The manual for this version: https://pdfpecker.net/docs/v1.16.0/
Full Changelog: v1.15.0...v1.16.0