Skip to content

Releases

v1.25.0

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 12 Nov 14:15
7cab532

Highlights

  • .NET 11. PdfPecker, PdfPecker.Fluent, PdfPecker.Testing and PdfPecker.Razor gain a net11.0 target next to net8.0, net9.0 and net10.0, and PdfPecker.Razor's .NET 11 build takes Microsoft.AspNetCore.Components.Web 11.0.0. The pdfpecker tool keeps installing as a Native AOT executable on a .NET 10 or 11 SDK.
  • Print-ready output: PDF/X-4 and CMYK. PdfOptions.PdfX takes 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 @page bleed, embedded fonts and sRGB tagged by profile. CSS device-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.PdfA2a and PdfA3a write the accessible level: a tagged structure tree and a declared language whatever PdfOptions.Accessibility says. They combine with PDF/UA-1, and 3a carries attachments and e-invoices as 3b and 3u do. The CLI takes --pdfa 2a and --pdfa 3a.
  • Vertical Chinese and Japanese. In vertical-rl and vertical-lr, CJK characters stand upright with the font's vertical forms, as Chrome draws them (UAX #50); text-orientation (mixed, upright, sideways) and text-combine-upright: all work, 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 rowspan now 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-autospace between ideographs and Latin letters or digits, font-palette and @font-palette-values for colour fonts, font-variant-alternates and @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 given height when min-width or max-width limits their width, and min-width/min-height apply to images; a flex row with an object-fit: cover image 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() and sibling-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 rowspan break 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, PdfRenderer and PdfToHtml; 1.24.0 skipped them.
  • PdfPecker.Razor depends on Microsoft.AspNetCore.Components.Web 8.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/demo and markdown/report, and the fluent goldens text, extras and catalogue: 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 10 Nov 08:15
d474d10

Highlights

  • Text extraction in reading order. PdfText now 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.TopToBottom gives 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, PdfToMarkdown and structured PdfToHtml allocate 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.Redact and RedactText take 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.Read reads QR codes, Data Matrix (square, rectangular and DMRE), Code 128 and EAN-13 from images, and PdfBarcodes.Find from 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.Convert decodes PNG, JPEG, GIF, WebP, BMP and TIFF (any page) straight to grey, RGB or RGBA pixels, and PdfRenderer.RenderPage can 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.Cli installs 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 through pdfpecker.cmd.
  • Deferred fonts and hyphenation patterns. FontCollection.AddDeferred registers a face by family, weight, style and unicode-range and reads it only when a document needs it, and HyphenationPatterns.Deferred does 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() with media(), supports() and style(), sibling-index() and sibling-count(), contrast-color(), object-view-box, inset box shadows on inline boxes, borders of <col> and <colgroup> in collapsed tables, visibility: collapse on table rows and columns, revert and revert-layer on 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 fr rows of indefinite height and items spanning flexible columns, intrinsic widths that keep min-width and the automatic minimum of grid and flex items, column flex boxes with a min-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 SVG currentColor and fonts inherited through <use>, lengths with units, nested svg viewports 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.
  • PdfText reads in reading order by default. Multi-column and side-by-side pages give different text from 1.23.0; set PdfTextOptions.Order = PdfTextOrder.TopToBottom for the old order.
  • PdfSanitizer keeps 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. convert and stamp get -env forms 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-cascade and rtl/demo: /ActualText spans around Devanagari, Thai, Arabic and Hebrew clusters, so they copy as written. The pages render the same.
  • complex/dashboard, features/effects, inline-borders/demo and transparency/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: 2pt is now 2px, as in Chrome.
  • subgrid/demo: an item spanning 1fr and auto columns 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 04 Nov 21:41
fe4ba52

Highlights

  • Three new packages, released with PdfPecker under the same version:
    • PdfPecker.Cli, the pdfpecker dotnet 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, text and info. A call without a command reads wkhtmltopdf's options, header and footer texts included. It has no dependencies and refuses web addresses.
    • PdfPecker.Razor: RazorToPdf renders a .razor component with Microsoft's HtmlRenderer and 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.MatchesSnapshot compares 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, DoesNotContainText and HasPageCount check the rest. No test framework dependency.
  • Existing PDFs to PDF/A. PdfToPdfA.Convert turns 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. PdfToMarkdown writes the structure PdfToHtml finds as GitHub Flavored Markdown: headings, paragraphs, lists, bold and italic, links and pipe tables.
  • Barcodes: Barcode.DataMatrix and Barcode.Gs1DataMatrix (ECC 200, GS1 element strings with FNC1), and Swiss QR-bills: SwissQrBill builds and checks the payload (IBAN, QR-IBAN, QR and creditor references) and Barcode.SwissQrCode draws it with the Swiss cross.
  • Empty signature fields. An element with data-pdf-signature="Name" becomes an empty signature field that PdfSigner signs later with FieldName = "Name", tagged as PDF/UA asks.
  • Templates from Prince, WeasyPrint and Chrome: running elements in page-margin boxes (position: running(name) with content: element(name), picked by first, start, last and first-except), @scope for component styles, CSS zoom as Chrome computes it, and even-page headers and footers (data-sticky-pdf-even-header and data-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-rule lists, rule-break, rule-inset), box-decoration-break: clone for block boxes split across pages, size-adjust, ascent-override, descent-override and line-gap-override in @font-face, target-counters(), white-space-collapse, hyphenate-limit-lines, accent-color and appearance: none for check boxes and radio buttons, :in-range and :out-of-range, image-rendering: pixelated and crisp-edges, continue: discard, @page { size: 80mm auto } for pages as tall as their content, and in SVG vector-effect: non-scaling-stroke, CSS transform with transform-box, and the geometry (cx, r, d, ...) and gradient stop properties from style sheets.
  • PdfPecker's own properties: -pdfpecker-repeat: each-page draws a box again on its parent's later pages, and -pdfpecker-image-quality and -pdfpecker-image-max-resolution make 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-style rules.
  • Tagged PDF: role="math" becomes a Formula with its alternative text, role="doc-index" an Index, role="doc-toc" a TOC with TOCI entries, and data-pdf-list-label marks 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), and position: fixed boxes such as watermarks paint over the running headers and footers.
  • Existing PDFs: PdfLinearizer linearizes 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), Image and SvgImage objects with WithCompressionQuality, WithRasterDpi and the document image settings, page Background and Foreground, Repeat, StopPaging, ContinuousSize, ExtendLastCellsToTableBottom, Overline, BreakAnywhere, the direction calls and every Semantic* call, Format(PageNumberFormat) for page numbers, gradients and Opacity. Document.Merge, EvenPageHeader and EvenPageFooter, Hyphenate and Language. New: Chart (column, bar, line and pie charts), Leader in text, Markdown content, TableOfContents from headings, SignatureField, DataMatrix, Gs1DataMatrix, SwissQrCode and the whole SwissQrBill payment 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), @scope limits are found in one walk (21 s to 2.4 s for the worst case), PdfSanitizer removes 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 &#xFFFFFFFF; 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 01 Nov 09:56
0e638ec

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.RemoveActiveContent takes JavaScript, actions that launch programs, open other files or submit form data, XFA and media annotations out of PDFs from others, and HasActiveContent tells whether a PDF has any. Pages, text, links and form fields stay.
  • Safer signatures and long-term validation. SHA-1 signatures are no longer Valid unless PdfSignatureVerificationOptions.AllowSha1 is set (PdfSignatureVerification.UsesSha1 says why); verification catches shadow attacks that redirect the cross-reference table after a certification and a dropped /Perms; and FetchRevocationData fetches OCSP and CRL data only from public addresses unless a UrlFilter allows others.
  • More CSS: the grid shorthand, the stretch sizing keyword and -webkit-fill-available for widths, heights and their limits, image-set() in backgrounds, list markers and generated content, text-box, text-box-trim and text-box-edge (lines trimmed to the cap height and baseline, as Chrome trims them), corner-shape (squircle, bevel, scoop, notch and superellipse() corners), overflow-clip-margin, rect() and xywh() in clip-path and shape-outside, text-emphasis, text-indent with hanging, each-line and percentages, font-width, :valid, :invalid and :open, borders, padding and background images on the @page box, and backgrounds on ::first-line.
  • ::marker as in Chrome: a larger marker font or a tall marker image makes its line taller, content: none hides the marker, counter(list-item) numbers it, and its own direction orders 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 to text-top and text-bottom, SVG backgrounds without a viewBox scaled to background-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, TotalPagesWithinSection and PageNumberWithinSection, 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 28 Oct 06:59
8d7d3c9

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-before and break-after work on rows and row groups, break-inside: avoid on a tbody (or break-after: avoid on 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.Structured writes a PDF's text as headings, paragraphs, lists and real tables, reads tagged PDFs from their structure tree, and with PdfHtmlOptions.IncludeStyles and IncludeImages keeps 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 in data: URLs and fixed boxes painting by z-index now behave as in browsers, taking the Acid2 face from 26% to 99% of Chrome's pixels.
  • More CSS and HTML: srcset, sizes and <picture>; images and gradients in ::before and ::after content; 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-orientation from EXIF; text-underline-position; legacy clip: rect(); background-attachment: fixed; pictures in <embed> and <object>; HTML inside SVG foreignObject; SVG context-fill and context-stroke; Charts.css charts; old -webkit- syntax; floats and sized boxes in vertical writing modes and left-to-right line order in vertical-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-all and overflow-wrap: anywhere shrinking 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 Page calls become named pages of one document, so page numbers, links, PDF/A, PDF/UA and signatures work across them and GenerateHtml accepts them; new TextField, CheckBox, RadioButton, ComboBox, ListBox and footnotes; ScaleToFit, ShowOnce and SkipOnce; 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 25 Oct 12:34
7b75418

Highlights

  • Linearized output for Fast Web View. PdfOptions.Linearize = true writes a linearized PDF, and the new PdfLinearizer linearizes 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.Certification makes the first signature a certification signature at level 1 (no changes), 2 (form filling and signing) or 3 (also annotations), and PdfSignatureVerifier reports the CertificationLevel and any DisallowedChanges made after it. Checked with pyHanko.
  • Viewer settings and page labels. PdfOptions.Viewer sets how a viewer opens the PDF (start page and zoom, page layout, bookmarks or thumbnails panel, full screen, window preferences, print scaling and duplex), and PdfOptions.PageLabels numbers pages the way the viewer shows them, such as roman numerals for front matter. PdfMergeOptions has both too.
  • Reading existing PDFs: PdfDocumentProperties.Read gives 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.Extract returns 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.StripImageMetadata removes 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, Linearize and StripImageMetadata options (a document of several page sets is linearized once, after merging), and Hyperlink no longer lets an IndexOutOfRangeException from System.Uri through 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 22 Oct 18:52

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: shrink scales a box's content down to fit its height, and data-sticky-pdf-first-header / data-sticky-pdf-first-footer give 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/bottom moves 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 (Quality now defaults to 85 for JPEG and 29 for WebP; set Quality = 85 for 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 21 Oct 19:36

Highlights

  • Shrink to fit: a page whose content sticks out past the right edge (a wide table
    or image, a long URL, nowrap text, a Bootstrap .row without a container) is laid out wider and drawn smaller,
    as Chrome prints it, up to 1.5 times. It is on by default; ShrinkToFit = false keeps 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, a position: relative table cell holds its positioned content, and outlines on
    cells of a collapsed table are drawn.
  • Logical border properties (border-inline, border-block-start and the rest,
    and the logical radii), and logical margins, paddings and insets now follow writing-mode too.
  • Fractions with diagonal-fractions or font-feature-settings: "frac" are formed as in Chrome.
  • Fixes, all closer to Chrome: an empty clearfix div and <br clear=all> clear floats; vertical-align: top,
    middle and text-top work 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-width caps 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-filter works at every box size; the default <hr> has
    Chrome's lighter shading, <hr size>, color and noshade work, 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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 21 Oct 11:37

Highlights

  • PDF to HTML: PdfToHtml turns 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 with initial-letter, masks and backdrop-filter
    on HTML elements, display: contents,
    3D transforms drawn flat, and vertical text
    with writing-mode.
  • Text wrapping and justification: text-wrap: balance and
    pretty, and text-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-stroke and paint-order, nested superscripts, and
    font properties font-kerning, font-synthesis, font-size-adjust,
    font-variant-position and font-variant-east-asian, with the font's own small capitals and the @font-face
    font-stretch descriptor.
  • Units measured from the font (ex, ch, cap, ic, lh and the root versions), the viewport units vi, vb,
    svh, dvh and the rest, q, and the logical inset-inline, inset-block, inline-size and block-size.
  • width: min-content, max-content and fit-content, wrapping column flex boxes, min-width: 0 on flex items,
    capped grid fit-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, cell min-width and max-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 bordercolor and rules, list type, reversed, align=center), and the html, head and body
    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, the quotes property (also auto by language), the all
    property and CSS-wide keywords on shorthands; vertical-align lengths and percentages.
  • SVG: use of a symbol from another inline SVG, symbol viewBox fitting, group opacity, and text-decoration on
    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

Choose a tag to compare

@Moonwalker1307 Moonwalker1307 released this 20 Oct 15:55

Highlights

  • Borders on inline elements: badges, keyboard keys and dotted underlines drawn
    with border on a <span> are painted, with box-decoration-break deciding how a border split over several lines
    is drawn.
  • SVG dashed strokes with stroke-dasharray, stroke-dashoffset and pathLength, and text
    along a path with textPath.
  • 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