Skip to content

3.0.3 - #21

Merged
ainceborn merged 7 commits into
masterfrom
release/3.0.3
Jul 15, 2026
Merged

3.0.3#21
ainceborn merged 7 commits into
masterfrom
release/3.0.3

Conversation

@ainceborn

Copy link
Copy Markdown
Owner

Image rendering: checkboxes and small images with soft masks no longer disappear.

Small images with an /SMask (soft mask) — commonly used to render checkboxes, form widgets, and icons in PDF forms — were not being drawn on the page starting from version 3.0.1.

Root cause: the new drawBufferedImageV2() code path (introduced in 3.0.1) included a downscaling optimization that reset the Canvas transformation matrix via canvas.setMatrix(new Matrix()) and attempted to reconstruct positioning from the CTM only. Because the DPI/flip transform applied in PageDrawer.drawPage() was not taken into account, the images ended up being drawn in the wrong coordinate space (typically outside the visible canvas), so nothing appeared on the rendered page.

Fix: non-stencil images (regular XObject images, including those with soft masks such as checkboxes) are now drawn via drawBitmap() again — the same simple, correct path used in 3.0.0. Stencil images with patterns still use the newer code path where it is needed for correct pattern masking.

Additional Changes

[PDFBOX-4076] - PDFBox cannot properly handle PDF Name objects containing bytes with values outside the US_ASCII range
[PDFBOX-6150] - PDComboBox constructAppearances wrong text
[PDFBOX-6173] - NullPointerException while merging PDFs with output intents
[PDFBOX-6176] - reported number of objects (7412) is not one plus the highest object number (7410)
[PDFBOX-6178] - PdfBox renames RadioButton with Umlaut
[PDFBOX-6179] - Removing fields not possible
[PDFBOX-6186] - IllegalArgumentException when calling PDDocumentCatalog.setThreads(null)
[PDFBOX-6187] - NullPointerException in AppearanceGeneratorHelper when PDFont.getName() returns null
[PDFBOX-6189] - Usage of PDF Controlled dimension may cause OOM
[PDFBOX-6191] - Print border doesn't work if using rastering
[PDFBOX-6193] - TrueTypeEmbedder.getTag() throws StringIndexOutOfBoundsException for negative Map.hashCode()
[PDFBOX-6194] - COSStream becomes COSDictionary after save — shared XObject reference replaced by Font
[PDFBOX-6202] - Possible regression when combining multiple PDFs
[PDFBOX-6203] - Splitter.split() corrupts result PDFs
[PDFBOX-6204] - PDType1FontEmbedder sets /Length to uncompressed PFB size
[PDFBOX-6206] - Rendering fails when bad annotations array
[PDFBOX-6209] - Regression in v3.0.7 causes Splitter to extract pages with text converted to symbols
[PDFBOX-6210] - Incorrect CJK Character Extraction for Shared Glyphs
[PDFBOX-6214] - PDDocument static AWT warm-up fails hard when AWT native libs are unavailable (GraalVM native-image)
[PDFBOX-6216] - Reject OpenType fonts using CFF2 outlines

ainceborn and others added 7 commits June 15, 2026 18:13
* fix: restore clipping path support in PageDrawer

The Note box text in certain PDFs (e.g. WoW manual) was invisible because
the decorative frame image was painted over the text without the intended
clipping restriction.

Root cause 1 — W/W* operators were silently ignored
clip() only stored clipWindingRule but never called intersectClippingPath().
The clipping path in the graphics state was therefore never updated,
so images were drawn over the full page instead of just the frame/border area.
Fixed by immediately calling intersectClippingPath(linePath) inside clip(),
matching the behaviour of the original Apache PDFBox.

Root cause 2 — drawImage() never applied the current clipping path
Even after fixing clip(), images were drawn without respecting the active
clip because drawImage() never called setClip() before painting.
Fixed by adding setClip() at the start of drawImage().

Regression fix — image flipping on pages with tiling patterns
After the above fixes, images on pages that use a Pattern fill (/P1 scn)
were rendered upside-down. The cause was drawTilingPattern(): it switches
to a temporary Canvas for the pattern, calls setClip() which updates
clipSaveCount to a save-level valid only for that temporary Canvas, then
returns without restoring clipSaveCount. The next setClip() call on the
main Canvas called canvas.restoreToCount() with a stale value, rolling
the main Canvas back past the page y-flip transform, which flipped every
subsequent image.
Fixed by saving and restoring clipSaveCount around the tiling pattern
rendering, the same way lastClip is already handled.
…r disappear.

Small images with an `/SMask` (soft mask) — commonly used to render checkboxes, form widgets, and icons in PDF forms — were not being drawn on the page starting from version 3.0.1.

Root cause: the new `drawBufferedImageV2()` code path (introduced in 3.0.1) included a downscaling optimization that reset the Canvas transformation matrix via `canvas.setMatrix(new Matrix())` and attempted to reconstruct positioning from the CTM only. Because the DPI/flip transform applied in `PageDrawer.drawPage()` was not taken into account, the images ended up being drawn in the wrong coordinate space (typically outside the visible canvas), so nothing appeared on the rendered page.

Fix: non-stencil images (regular XObject images, including those with soft masks such as checkboxes) are now drawn via `drawBitmap()` again — the same simple, correct path used in 3.0.0. Stencil images with patterns still use the newer code path where it is needed for correct pattern masking.
# Conflicts:
#	README.md
#	gradle.properties
@ainceborn
ainceborn merged commit a9a3e3f into master Jul 15, 2026
5 checks passed
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.

1 participant