Skip to content

Bump PeachPDF from 0.9.23 to 0.9.25 - #6

Merged
tzinmein merged 1 commit into
masterfrom
dependabot/nuget/src/OxyKit.Render.Core/PeachPDF-0.9.25
Nov 4, 2026
Merged

tzinmein merged 1 commit into
masterfrom
dependabot/nuget/src/OxyKit.Render.Core/PeachPDF-0.9.25

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Nov 4, 2026

Copy link
Copy Markdown
Contributor

Updated PeachPDF from 0.9.23 to 0.9.25.

Release notes

Sourced from PeachPDF's releases.

0.9.25

PeachPDF 0.9.25 Release Notes

Release date: October 30, 2026
Full changelog: v0.9.24...v0.9.25
Release tag: v0.9.25

PeachPDF 0.9.25 turns PeachBrackets into an engine you can select, search and edit text in, adds a Win2D backend (PeachDrawing.Win2D), and reads CSS Color 4's color(), none and relative color syntax, with gradients that fade to transparent keeping their colour. Table backgrounds now follow CSS 2.1 §17.5.1, and a long list of pagination, table, flex and grid defects is fixed. The hot paths of the engine, the PDF writer and the rasterizer allocate far less. 45 pull requests are included.

Thanks to @​ChrisVanDijk, who authored three of them (the visibility and initial fixes for inline SVG), to @​SlyNet for table track backgrounds that cover only their own cells, and to @​mbp, who made their first contribution with custom string entries in a page's dictionary.

Highlights

PeachBrackets: where the text is, selection, highlights and editing
HtmlDocument can now answer questions a viewer or an editor asks of a laid-out document, with no PDF involved. See PeachBrackets.

  • Text geometry. With HtmlDocumentOptions.RecordTextRuns set, TextRuns / GetTextRuns(pageIndex) report each line of a block in points, with per-character offsets (snapped to grapheme boundaries), baseline metrics, direction, block id and link. HitTest, GetCaretPosition, GetSelectionRects, GetText, FindText, GetWordAt, GetBlockAt, GetElement and GetElementAt are built on them. Nothing is computed unless asked for, and layout and painting are unchanged.
  • Selection. HtmlDocument.Selection is a DocumentSelection with a DOM-like model (SetBaseAndExtent, Collapse*, Extend, Modify by character, word, line or block, SelectAll, SelectWordAt, SelectBlockAt, GetRegions, GetCaretBounds) and SelectionChanged events that carry the regions to repaint. SelectionBackground / SelectionForeground set the default colours and EnableSelectionStyling applies ::selection rules.
  • Named highlights. SetHighlight / RemoveHighlight / ClearHighlights paint ::highlight(), ::spelling-error and ::grammar-error, and ApplyTextFragmentDirective paints a URL text fragment as ::target-text. A highlight fills the whole line box, restyles text with text-shadow and a text stroke, draws a text-decoration it adds, and inherits color and text-shadow from an ancestor's highlight through an element with rules of its own. Vertical text has no text runs yet, so it is not highlighted.
  • Editing in place. With EnableIncrementalUpdates set, InsertTextAsync, DeleteTextAsync, ReplaceTextAsync, SplitParagraphAsync, JoinWithNextParagraphAsync (list items included, with the markers after them renumbered), WrapRangeAsync and UnwrapElementAsync (for strong, em, u, a, span and the like) change the document and re-lay out only what the edit reaches. SetStyle restyles an element, and PaintPageRegionAsync repaints just the region an edit dirtied. After a split or join, later siblings are re-cascaded so :first-child, :last-child and adjacent-sibling rules see the new tree, and counters, quote depths and generated content are resolved again. A paragraph split no longer gives its copy the original's id.

New package: PeachDrawing.Win2D
A fourth Canvas / RenderContext backend, over Win2D for the Windows App SDK, at the same version as PeachPDF and usable with no PeachPDF reference. It is Windows-only (net10.0-windows10.0.19041.0, plus net11.0-windows under the .NET 11 SDK). See PeachDrawing.Win2D.

  • Win2dCanvas draws into a caller's CanvasDrawingSession (borrowed, never closed, state restored) or into the offscreen bitmap of a Win2dComposer (PNG, JPEG, BMP, TIFF, GIF or premultiplied pixels).
  • Shapes, strokes and dashes, linear, radial and conic gradients, tile brushes, clips, transforms, images, and layers with opacity, colour matrix, blur and shadow effects, masks and blend images.
  • Text goes through the shared PeachDrawing.Text engine by default, or through DirectWrite; the DirectWrite mode is documented as not feature complete.
  • Links are recorded for the host to hit-test and are opened with the system handler behind a scheme allowlist.
  • Every native resource has one owner and a deterministic disposer, counted so tests can prove nothing leaks, and device loss is handled.

CSS Color 4: color(), none, relative color syntax and alpha-aware gradients

  • color() is read in every predefined space (a98-rgb, prophoto-rgb and rec2020 are new) and clipped to sRGB. A background-color using it used to be dropped.
  • none is a missing component. It is 0 on its own (an alpha of none is transparent), and in a color-mix() or an animation it takes the other colour's value. rgb(), hsl() and hwb() with none mix in Oklab, like Chrome. none is not accepted in the legacy comma syntax.
  • Relative color syntax works in every colour function: rgb(from #​336699 calc(r + 20) g b), and the same in hsl(), hwb(), lab(), lch(), oklab(), oklch() and color(). An omitted alpha is the origin's, and in an animation the colour is mixed in Oklab.
  • A gradient that fades to transparent keeps its colour. Stops are interpolated premultiplied by alpha (CSS Color 4 §12.3), so linear-gradient(to right, red, transparent) stays red while it fades instead of going gray in the middle. This applies in every interpolation space, with hints and in conic gradients.
  • A gray stop takes its hue from the other stop in lch, oklch, hsl and hwb gradients (and in color-mix() in hsl / hwb), as the specification says and as color-mix() already did.

Table backgrounds, rowspans and nested tables

  • A row, row group, column or column group background covers only its own cells. As CSS 2.1 §17.5.1 requires, each one fills the cells that originate in it, beneath every cell, instead of its whole rectangle: a transparent rowspan cell no longer shows a later row's colour in its lower part, a colspan cell takes the colour of the column it starts in, and the border-spacing gaps and empty slots show the table's own background. Details and the empty-cells / visibility consequences are in the migration section below.
  • A rowspan cell is drawn once. It used to be drawn once per row it spanned.
  • A row's cells stay together across the page foot. A keep-with-next run at the top of a cell no longer carries that cell to the next page while its sibling stays, and a short cell is vertically aligned within the room left on the page instead of against a row taller than its band.
  • Tables nested in a sliced row. A table inside a cell of an outer row that is too tall for a page is now broken in the row's own coordinates, so its rows no longer drift by the repeated header's height per page and a row at the foot is no longer drawn on two pages. break-inside: avoid on a row of such a nested table is honoured.
  • A table narrower than its rtl container is anchored to the right edge, less its right margin, as a block-level box is (CSS 2.1 §10.3.3).

Page metadata
PdfComposerPage.SetCustomString(dictionaryKey, key, value) stores a custom string entry in a dictionary associated with the page, and TryGetCustomString reads it back from a written document. Names must be valid PDF names, an existing page entry (including the reserved page keys) is never overwritten, and a dictionary name is reused for every entry set under it.

Much less allocation in the hot paths
Output is unchanged; these only reduce garbage and time.

  • The engine and fragment tree: fragment lines and children are built as arrays with no per-draft slice dictionary, and selectors, class tokens, lengths and data URIs are parsed without per-call allocations.
  • PeachDrawing.Text: a case-insensitive family dictionary and cached range query in font matching, span-based hyphenation lookup, per-run script-set lookups, pooled gvar scratch arrays and word-wise table checksums.
  • The PDF writer and SVG backend: glyph hex, the ToUnicode CMap, /W arrays and SVG numbers are written straight into the output, the Flate stream is presized and the PNG CRC uses slicing-by-4.
  • The rasterizer: premultiply, Porter-Duff, opacity and erase kernels run on exact integer Vector128 code with scalar references, and per-pixel allocations are gone from the arithmetic, tile and colour-matrix paths.
    ... (truncated)

0.9.25-preview1

PeachPDF 0.9.25-preview1 Release Notes

Release date: October 27, 2026
Full changelog: v0.9.24...v0.9.25-preview1
Release tag: v0.9.25-preview1

This is a preview of 0.9.25. It adds a fifth drawing package, PeachDrawing.Win2D, which draws with hardware-accelerated Win2D on Windows, and it reads the rest of CSS Color 4's color syntax (color(), none, relative colors) with gradients that fade to transparent keeping their color. Tables get four layout fixes (nested tables in sliced rows, break-inside: avoid on nested rows, rows kept whole across the page foot, tables in rtl containers), CSS Grid and inline-block alignment close four gaps, and the text, PDF-writer, SVG and raster paths allocate less. 21 pull requests are included.

Install the preview with --prerelease (or pin 0.9.25-preview1): dotnet add package PeachPDF --prerelease. The docs site is not updated for a preview.

Highlights

New package: PeachDrawing.Win2D
A Windows Canvas for the same drawing API as PeachDrawing.PDF, PeachDrawing.Svg and PeachDrawing, usable with no PeachPDF reference. It uses Win2D 1.4 (Windows App SDK) and targets net10.0-windows10.0.19041.0 (and net11.0-windows10.0.19041.0 under the .NET 11 SDK). It builds on Windows only. See PeachDrawing.Win2D.

  • Win2dCanvas.FromSession draws into a drawing session you already have (a CanvasControl, a swap chain). The session is borrowed: it is never closed and its transform, blend and anti-aliasing are put back. Win2dComposer draws an offscreen page and reads it back as pixels or saves PNG, JPEG, BMP, TIFF or GIF.
  • Shapes, strokes with caps, joins and dashes, linear, radial and conic gradients, tile and hatch brushes, clips, transforms, images, and layers with opacity, color matrix, blur and drop shadow. Masks, DrawImageBlendedOver, tiles (vector command lists) and the raster fallback are covered too.
  • Lifecycle. Every native resource has one owner and a deterministic disposer: a pushed clip holds a Win2D layer until its PopClip, brushes and geometry live for one draw call, a tile or layer owns a command list, and a canvas disposed with clips or layers still open unwinds them. A borrowed device or session is never disposed. Win2dRenderContext is IDisposable; a lost device is replaced on next use and raises DeviceLost, and reading a lost page throws Win2dDeviceLostException.
  • Text goes through the shared PeachDrawing.Text engine by default, so it lays out exactly as on the other canvases, or through DirectWrite (Win2dTextEngine.DirectWrite) so it looks like the rest of Windows. DirectWrite mode is not feature complete: no glyph outlines (gradient-filled text falls back to a solid color), no font-variation-settings, no unicode-range splitting, and its layout differs from the other backends. The guide has the full table.
  • Links are recorded in Win2dCanvas.Links for the host to hit-test. TryActivateAsync opens an address with the system's default handler for its scheme, and only http, https, mailto and tel are launched unless the host widens Win2dLinkOptions.AllowedSchemes. A link to a place in the document is left to the host to scroll to.
  • Limits: a drawing session blends only by add and minimum, so PushBlendMode is exact for Plus and Darken and draws the other modes as Normal (CSS mix-blend-mode is not honored on this canvas); a two-circle radial gradient starts from a point focus; a blur or shadow with unequal x and y deviations uses their mean.

Tables

  • A table nested in a sliced row now breaks in the row's own coordinates. A table inside a cell of an outer table's too-tall row used to break at the real page edges while the outer table sliced the row into strips below its repeated <thead>; the two disagreed by the header's height on every page, so inner rows drifted from the third page on and a row at the page foot was drawn on two pages.
  • break-inside: avoid on a row of a nested table is honored (it was declined for every table inside a table cell), so such a row moves whole to the next page, under the repeated header.
  • A row's cells stay together across the page foot. A keep-with-next run (break-after: avoid headings) at the start of a cell used to travel to the next page and leave the cell empty on the first, and a taller-than-a-band row's second cell had a line cut by the page edge. The run is now trimmed past a member that is the first in-flow child of a cell, and the row is laid out so no line is cut.
  • A table narrower than its rtl container is anchored to the right edge, as a block-level box is (CSS 2.1 §10.3.3).

Color

  • color() is read in every predefined space (srgb, srgb-linear, display-p3, a98-rgb, prophoto-rgb, rec2020, xyz, xyz-d50, xyz-d65) and clipped to sRGB, so background-color: color(...) is no longer dropped.
  • none is a missing component (CSS Color 4 §12.2): 0 on its own, and in color-mix() and animations it takes the other color's value. rgb(none 0 0) is read; none is rejected in the legacy comma syntax.
  • Relative color syntax is read in rgb(), hsl(), hwb(), lab(), lch(), oklab(), oklch() and color(): rgb(from #​336699 calc(r + 20) g b). The origin may itself be relative, the alpha is the origin's unless written, and in an animation a relative color is mixed in Oklab.
  • Gradients to transparent keep their color. Stops of different alpha are interpolated premultiplied by alpha (CSS Color 4 §12.3), so linear-gradient(to right, red, transparent) stays red as it fades instead of going gray. This is done in the engine, so the PDF and raster backends agree.
  • A gray gradient stop takes its hue from the other stop in lch, oklch, hsl and hwb (CSS Color 4 §4.4.1), so a gradient and a color-mix() of the same stops agree. #​808080 to red in oklch is rgb(198, 99, 86) at the midpoint, the color-mix() value. This differs from Chrome's oklch gradient, which keeps the gray's own hue.

CSS Grid and inline-level boxes

  • auto grid rows fill a definite container height (css-grid-2 §12.8), so items stretch or align-self has room.
  • A grid flex item with width: auto is as wide as the sum of its tracks and gutters, not all the free width of the flex container.
  • A text-less inline-grid or inline-table honors vertical-align: the box and its items move together.
  • An atomic inline-flex, inline-grid or inline-table box counts in text-align, and moves with its content, aligned at its margin-box width. Under justify it is neither moved nor resized.

Paged media and text

  • @​page margin-top and margin-bottom percentages resolve against the page height, not the width (css-page-3 §6).
  • An element() running element in a margin box follows the box's vertical-align (default middle) instead of being drawn at the top (css-page-3 §6.2).
  • A hyphenation split breaks the line whatever the hyphenate-character is. A custom or empty character no longer lets the word overflow.
  • The space between words uses the fallback face when it is outside the first face's unicode-range. It was measured and drawn in the unicode-range face.

Performance

Output is unchanged in all of these; each has equivalence tests against the code it replaced.

  • Raster kernels are vectorized: premultiply and unpremultiply, Porter-Duff (over, in, out, atop, xor), opacity and erase use exact integer Vector128 kernels, and the per-pixel allocations in the arithmetic, tile and mirror-pad filters are gone.
    ... (truncated)

0.9.24

PeachPDF 0.9.24 Release Notes

Release date: October 23, 2026
Full changelog: v0.9.23...v0.9.24
Release tag: v0.9.24

PeachPDF 0.9.24 can stamp pages of an existing PDF over or under a document you build (OverlayFile / UnderlayFile), and the HTML/CSS/SVG/MathML engine now ships as its own package, PeachBrackets, beside a new SVG output package, PeachDrawing.Svg. It also lays out text-only multi-column containers as real columns, puts text beside a float that follows it, and fixes a long list of CSS background and color-mix() mismatches with browsers. 67 pull requests are included.

Thanks to @​ChrisVanDijk, who authored five of them: the background shorthand layers, CSS animations on inline <svg> elements, percentage opacity in keyframes, the gradient alpha fix and the background-deviation notes. Thanks also to @​zzyzy for columnizing text-only multi-column containers and to @​SlyNet, who made their first contribution with keeping a table row that avoids breaks whole.

Highlights

New: OverlayFile and UnderlayFile
IDocumentBuilder.OverlayFile / UnderlayFile draw pages of an existing PDF over or under the pages of a declarative document. Pages are paired with TargetPages, SourcePages and RepeatSourcePages ranges ("1-3,5", "2-z"). They are read by a new PDF importer in PeachDrawing.PDF, public as PdfPageSource, which re-draws a page onto any Canvas.

  • The importer reads classic and stream cross-reference data, object streams, hybrid files and incremental updates, and rebuilds damaged files. Encrypted files are refused.
  • It draws paths, clips, transparency groups (with their blend mode and constant alpha), luminosity and alpha soft masks, tiling patterns, axial, radial and function-based shadings, linear transfer functions, inline images, and JPEG, JPEG 2000, CCITT and JBIG2 images. Gray and RGB ICC profiles are applied and CMYK images stay CMYK. Text from embedded TrueType/OpenType fonts keeps its text map.
  • A file layer also carries the page's navigation and structure: links (re-pointed at the pages their targets landed on), named destinations, outline entries, document information and attachments, form fields and other annotations as real objects (a signature field arrives unsigned and actions are not copied), tags, and PDF/A, PDF/X and output-intent markers.
  • The writer gains list box, push button and signature fields, multi-line text and multi-select lists, and PdfAnnotationBuilder for highlights, notes, stamps, ink and shapes.
  • Not drawn yet and reported by PdfPageSource.Paint: mesh shadings, stroked text, Type 1/CFF/Type 3 fonts. In the showcase round trip, all 430 pages stay under a 2% pixel difference from the original (it began at 32 of 429 pages over the threshold).
  • A document with no PDF/A or PDF/X level now writes an output intent when given a profile (no conformance is claimed), and a layer's output intent is used by any document that has none.
  • Tagged declarative documents built with several Page(...) calls keep all their structure: the structure tree holds one Document element with every handler's structure, and each page has its own parent-tree key. They used to keep only the last handler's.

New packages: PeachBrackets and PeachDrawing.PDF
The HTML/CSS/SVG/MathML engine and the PDF writer are now separate NuGet packages at the same version as PeachPDF, both usable with no PeachPDF reference.

  • PeachBrackets loads, paginates and paints HTML onto any Canvas: HtmlDocument.LoadAsync, LayoutAsync and PaintPageAsync, with a public annotation model (links, outline, form fields) and a tagging seam. It does not reference the PDF writer. See PeachBrackets.
  • PeachDrawing.PDF holds the PDF Canvas and PdfComposer, with PDF/A and PDF/X conformance, links and bookmarks, tagged PDF, forms and encryption. See PeachDrawing.PDF.
  • PeachPDF now goes through those public APIs only, so PdfGenerator output is unchanged. Each package carries its own README and third-party notices.

New: PeachDrawing.Svg
A vector SVG Canvas (SvgCanvas, SvgRenderContext, SvgComposer) beside the PDF and raster ones. Paths keep their curves, brushes become gradients and patterns, clips, transforms and blend modes become groups and CSS compositing, and images are embedded as they came. Text is exact glyph outlines or, with SvgTextMode.Text, selectable <text> with an embedded subset font. The only bitmap is the raster-fallback seam. See PeachDrawing.Svg.

  • Hyperlinks are now Canvas calls (AddLink, AddDestinationLink, AddDestination; default no-ops). PdfCanvas writes them as link annotations and named destinations and SvgCanvas as <a href>. HTML documents write their links through them, and tagged-PDF links stay attached to their structure elements.
  • Fixed: color glyphs were drawn twice as large at two layout units to the point (in RasterCanvas as well).
  • Every HTML showcase on the docs site now also links a one-sheet SVG render.

Multi-column containers that hold only text
Text placed directly in a columns / column-count container used to flow as one inline run across the full width. It is now divided into columns like any other column content, including text beside a float. Text in a vertical writing mode and a bounded scroll container (overflow other than visible with a height or max-height) that holds only text keep their previous layout.

A float after text no longer covers it
A float placed after text on the same line used to sit at the top of that line with the text underneath it. The text on the line now moves beside the float when it fits, and otherwise the float starts the next line. A float wider than the line takes the text below it. Float placement also no longer hangs on certain combinations of float sizes, margins and clear: a fuzz run of 560 documents hung 26 and 58 times on the previous code and 0 times now.

A flex item in a row keeps its automatic minimum size
An item of a display: flex row with min-width: auto (now the initial value, as in CSS Sizing 3) is no longer shrunk below its min-content width: an <img> used to be squeezed under its natural width, and a nowrap or long-word item narrowed until its text overflowed. It is floored at its min-content width, or at its definite width when that is smaller, and the shrink it cannot take goes to the other items; a row that cannot fit overflows, as in a browser. Items with min-width: 0 or an overflow other than visible/clip still shrink freely. Widths match Chrome on the rows tested (two 96px images in a 100pt row stay 72pt each, where they were 50pt). A document that relied on tiles squeezing to fit now overflows; add flex-wrap: wrap or min-width: 0 to restore the old fit. Flex items in a column, grid items, and items being grown (flex: 1 with a long unbreakable word) do not get the automatic minimum yet.

break-inside: avoid on a table row
break-inside: avoid (or avoid-page, or page-break-inside: avoid) on a <tr> or its cells was ignored once a cell wrapped, so the row was cut at the page foot. Such a row now moves whole to the next page, under the repeated header, when it fits there. A row taller than a page, and a row of a table nested in another table's cell, are still split. Documents with rows that avoid breaks can change page count.

  • A row moved because it straddled the page foot now starts right under the repeated header, where it used to start one header-height lower. A document with no avoid row can gain or lose a page by this.
  • A row that overflows by little more than its cell's bottom padding no longer draws its last line a second time, mostly clipped, at the top of the next page.

CSS backgrounds

... (truncated)

Commits viewable in compare view.

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

---
updated-dependencies:
- dependency-name: PeachPDF
  dependency-version: 0.9.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added .NET Pull requests that update .NET code dependencies Pull requests that update a dependency file labels Nov 4, 2026
@tzinmein
tzinmein merged commit 79168aa into master Nov 4, 2026
1 check passed
@dependabot
dependabot Bot deleted the dependabot/nuget/src/OxyKit.Render.Core/PeachPDF-0.9.25 branch November 4, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file .NET Pull requests that update .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant