Give SVG Form XObjects an explicit /Resources dictionary (mirrors mpdf/mpdf#2196) - #18
Closed
jakejackson1 wants to merge 1 commit into
Closed
Give SVG Form XObjects an explicit /Resources dictionary (mirrors mpdf/mpdf#2196)#18jakejackson1 wants to merge 1 commit into
jakejackson1 wants to merge 1 commit into
Conversation
A Form XObject without /Resources inherits the page's, which PDF 1.4 tolerated and PDF/A does not, so validators reject any document with an embedded SVG. Declare what the form actually paints with: the graphics states, shadings and fonts an SVG flags as it is drawn, which is the same set _putpatterns already collects for these objects. Collecting them needs the shadings resolved. _putshaders is what fills in a gradient's object number, and it ran after _putformobjects, so a gradient SVG would either name a shading as "0 R" or, with the isset() guard, quietly leave /Shading out of a dictionary its own stream paints with — worse than no dictionary at all, since inheritance had covered it. Shaders are now written before form objects; _putpatterns still sees them resolved, as its comment requires. Every snapshot in tests/data/snapshots renders unchanged. Mirrors mpdf#2196. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
Author
|
Closing as this is resolved in jakejackson1#7 and jakejackson1#6 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This mirrors mpdf#2196, so the fork carries the fix while the upstream PR sits open.
mPDF draws an embedded SVG into a Form XObject and writes no
/Resourcesfor it, leaving it to inherit the page's. PDF 1.4 allowed that; PDF/A does not, so a validator rejects any PDF/A document containing an SVG. The fix declares what the form actually paints with — the graphics states, shadings and fonts an SVG flags on its way throughSvg.php— which is the same set_putpatterns()already collects for these very objects.Collecting them needs the shadings resolved first, and they were not.
_putshaders()is what fills in a gradient's object number, and_putresources()ran it after_putformobjects(). So this branch also moves it earlier;_putpatterns()still sees the shadings resolved, as its comment has always required.Try it
On
gravitypdfthe Form XObject isand veraPDF reports the missing resource dictionary. On this branch it is
— every name the stream goes on to use.
Test plan
composer test— 1050 tests, 2542 assertions, green (gravitypdfis at 1048).composer cs— clean.gravitypdf, none new.tests/data/snapshotswere regenerated on this branch and compared against the committed files: 0 differing pixels on every one. Imagick is not built for PHP 8.5 locally, so this used the ImageMagick CLI at the same 120 dpi on white thatSnapshots\Snapshotuses. CI runs the real group.tests/Mpdf/FormObjectResourcesTest.phpfails ongravitypdf(no/Resourcesat all) and, importantly, also fails with the upstream patch applied without the reordering — on/Sh1.More info
Where it differs from upstream
_putpatterns()already notes_putshaders()still runs after_putformobjects(), so$gradient['id']is unset and theisset()guard silently drops/Shading_putshaders()moved ahead of_putformobjects()in_putresources(), so gradients resolve. Theisset()guard is kept, for gradients_putshaders()does not write at all — a soft mask, say — since emitting/Sh1 0 Rfor one would be malformed$font['used']before checking$font['fo']fofirst. Core fonts have nousedkey, so the upstream order raises Undefined array key "used" on any document with a form object —tests/Issues/Issue539TestandIssue990Testboth trip on it/ExtGStateis presentgs,shandTfoperands and asserts each one is declared with a real object number, plus a PDF/A caseWhy the missing
/ShadingmatteredWithout the reordering, a gradient SVG ends up with a
/Resourcesdictionary that omits the shading its stream paints with. That is worse than having no dictionary: inheritance from the page had been covering it. So the ordering is not a tidy-up, it is what makes the change safe for gradient SVGs.The fixture
tests/data/img/form-xobject-resources.svgis eight lines and deliberately paints with one of each: a linear gradient, a half-transparent rectangle, and a line of text. That gives a single form object naming/GS1–/GS5,/Sh1and/F2, so the test has something from all three categories to check.Not covered
/XObjectis not in the dictionary.Svg::svgImage()can write/I<n> Dofor a raster image inside an SVG, but nothing marks those images the way gradients, graphics states and fonts are marked, and_putpatterns()has the same gap. In practicesvgImage()does not currently get as far as emitting that operator, so there is nothing to declare — worth knowing about, but adding a category with no producer would be speculative.