Skip to content

Merge images in with PDFs - #12

Merged
techygeekshome merged 5 commits into
mainfrom
merge-images
Aug 29, 2026
Merged

Merge images in with PDFs#12
techygeekshome merged 5 commits into
mainfrom
merge-images

Conversation

@techygeekshome

Copy link
Copy Markdown
Owner

Closes #8.

Merge takes JPG, PNG and WebP alongside PDFs now, so a set of pages that arrived as scans no
longer has to be converted somewhere else first - which rather defeated the point of a tool that
never uploads anything.

What the user sees

The file picker and drag-and-drop both accept images, the list marks them so the order stays
readable, and there is a page-size choice with two behaviours, which is what @qwerty13 asked for
in the thread:

  • Every page keeps its own size (default). PDF pages are copied across untouched, so links,
    annotations and form fields survive. Each image becomes a page cut to its own size.
  • Force everything to A4 or Letter, portrait or landscape. Every page is redrawn at that
    size, scaled to fit and centred, so a page of a different shape gets margins.

The note under the box changes with the choice and says plainly that forcing a size is a redraw
and loses links and form fields. That is a real cost and it should be visible before the button
is pressed, not discovered afterwards.

How it works

PDFsharp embeds a JPEG straight into the PDF and reads PNG on its own, so both are handed over
untouched - re-encoding a photograph would cost quality and size for nothing. WebP is the one it
cannot read, so it is decoded with SkiaSharp and re-encoded: JPEG when the picture is opaque, PNG
when it is not. Forcing every WebP through PNG would turn a 200 KB photograph into a
several-megabyte page.

SkiaSharp already arrives with Avalonia. It is named explicitly in the csproj so this does not
quietly depend on a transitive package.

Three things that were not obvious

  1. XImage.PointWidth is just the pixel count. It does not apply the DPI, so the size on the
    page is worked out here instead: pixels, the file’s own resolution, fall back to 96 when that
    is missing or nonsense. A 300 DPI scan therefore lands at its real physical size rather than at
    four times it. The result is clamped to the 14400-point limit a PDF page has, because a very
    large image at a very low DPI can otherwise ask for a page the format cannot represent.
  2. A converted WebP is sized from its own pixels, not from the container it was converted into.
    WebP records no resolution, so whatever the intermediate JPEG or PNG claims is invented - and
    letting it through would mean the same picture landed at one size with an alpha channel and a
    different size without one.
  3. new MemoryStream(bytes, writable: false) breaks PDFsharp. It calls GetBuffer(), which
    throws unless the stream was created publiclyVisible: true. The smoke tests caught this.

Testing

Nine new checks in the smoke suite, which builds its own images with Skia rather than carrying
fixtures in the repository: what counts as mergeable, an image becoming a page of its own size,
PDFs and images interleaving in the order given, both forced sizes, WebP with and without alpha,
an unsupported file being refused before anything is written, and the sizing rule itself including
the clamp.

38 passed, 0 failed on Linux. Three of them failed first time round and found the two
stream and sizing bugs above.

Version bumped to 1.1.0 - this is a feature, not a patch.

Not in this

TIFF, which qwerty13 agreed was rare enough to leave out, and any per-image size override. The
page-size choice is document-wide.

@techygeekshome
techygeekshome merged commit 15d1ceb into main Aug 29, 2026
1 check passed
@techygeekshome
techygeekshome deleted the merge-images branch August 29, 2026 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add "Merging Images to PDF"

1 participant