Bug 707824 - Conversion to SVG respects invalid OCGs
Summary: Conversion to SVG respects invalid OCGs
Status: RESOLVED FIXED
Alias: None
Product: MuPDF
Classification: Unclassified
Component: mupdf (show other bugs)
Version: unspecified
Hardware: All All
: P2 major
Assignee: Tor Andersson
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-06-12 10:58 UTC by Jorj
Modified: 2024-07-17 16:01 UTC (History)
1 user (show)

See Also:
Customer:
Word Size: ---


Attachments
Minimized example. (10.96 KB, application/pdf)
2024-06-28 16:51 UTC, Tor Andersson
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jorj 2024-06-12 10:58:16 UTC
In contrast to page rendering, SVG conversion does not make sure whether any OCGs are valid at all.

PyMuPDF Discussion item: https://github.com/pymupdf/PyMuPDF/discussions/3567
File link: https://github.com/user-attachments/files/15791552/dwe1_2.pdf

How to reproduce:

mutool draw -o test.svg dwe1_2.pdf

Compare to:

mutool draw -o test.png dwe1_2.pdf

Note:
The page refers to dozens of OCGs in its /Properties. But there exists no /OCProperties in the file - so all of the OCGs must be treated as non-existent, like it happens in rendering.
Comment 1 Robin Watts 2024-06-14 10:02:18 UTC
I have a fix in review:

https://cgit.ghostscript.com/cgi-bin/cgit.cgi/user/robin/mupdf.git/commit/?h=so&id=8a01ae1ca85902adae87fde06e58af9de301a02e

The issueis not the /OCProperties not existing, it's a bad interaction between layers and clips in the generated SVG file.
Comment 2 Robin Watts 2024-06-14 14:31:38 UTC
Tor isn't keen on my fix, because it can split layers into more groups that are strictly needed. We have therefore agreed to park my fix for a couple of weeks to see if he can find a formulation he likes better.
Comment 3 Tor Andersson 2024-06-28 16:51:10 UTC
Created attachment 25767 [details]
Minimized example.
Comment 4 Tor Andersson 2024-07-17 16:01:53 UTC
Fixed with the following two commits:

commit 65f283f2ac0445b15a106d565d999637aac9081a
Author: Tor Andersson <tor.andersson@artifex.com>
Date:   Wed Jul 3 19:16:44 2024 +0200

    Bug 707824: Emit properly nested clip and layer operations in PDF.
    
    If BMC/EMC and q/Q pairs (that apply clipping) don't nest properly, warn
    and close the EMC either immediately (if badly nested one way) or at the
    next Q (if badly nested the other way).
    
    Example 1:
            q
            BMC
            Q       (close layer before this Q)
            EMC     (ignore this EMC)
    
    Example 2:
            BMC
            q
            EMC     (ignore this EMC)
            Q       (close layer after this Q)
    
    Also change SVG output to emit Inkscape specific layer attributes.
    
    ---
    
    mc_depth tracks the level of BMC/EMC nesting in the content stream.
    
    nest_mark tracks the level of layer and clip calls that we've made to the fz_device.
    
    If the q/Q and BMC/EMC are badly nested, we ignore some EMCs and save them
    until we hit the next Q. The check in do_end_layer only ends the layer if the
    device and content stream are "in sync".
    
    If we're not in sync, we ignore the EMC. This can happen in two cases: either
    we saw a Q too early, or we saw an EMC too early.
    
    In the first case we have already popped the layer (so the EMC should be
    completely ignored).
    
    In the second case the layer started before the clip and we cannot end the
    layer just yet (so ignore the EMC until we see the Q and then pdf_grestore puts
    the world back into order).
    
    The loops around the pop_clip in pdf_grestore recover the syncing. The loop
    before closes any layers that need to be ended before the clip is popped (layer
    started with BMC inside the clip, but ends after the clip). The loop after
    closes any layers that had the EMC inside the clip but were started with BMC
    before the clip mask was pushed.


commit 711e82dde434dfe8f36feca88c5c4b9d70ab87ce
Author: Sebastian Rasmussen <sebras@gmail.com>
Date:   Wed Jul 17 01:08:27 2024 +0200

    Check nesting depth before pushing clip mark.
    
    Without this the nesting depth might step outside the layer/clip stack.