Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding ability to specify 'UserStyleSheetURI' for an SVGDrawer, this … #496

Closed

Conversation

amckain92
Copy link

…allows SVGs to render without requiring styles to be inline.
Fixes #493

Hi @danfickle,

So I was trying to find a solution to issue 493 where in order for SVG elements to render with the correct css, the styles are required to be declared inline in the SVG. Ideally, SVG elements would be able to reference an external stylesheet to pull their styles as well. This was possible in the older itext/flying saucer implementation by providing a transcoder hint for the svg/png transcoder used by Batik.

Eventually I tracked down the issue in the Batik BridgeContext class, specifically the 'initializeDocument' method tries to set up the CSSEngine on the SVGDOMImplementation using the UserAgent.

The problem that I was running into was the implementation of UserAgent, OpenHtmlUserAgent doesn't override the method 'getUserStyleSheetURI' from its base class UserAgentAdapter and thus always returns null for that method call. That method is what's used in the BridgeContext to setup the CSSEngine for the SVG.

To get the value I needed injected down to the UserAgent class I had to pass it through a number of other classes starting at the public interface point which is the BatikSVGDrawer:
BatikSVGDrawer > BatikSVGImage > PDFTranscoder > OpenHtmlUserAgent

I'm not super familiar with this library, so there may have been a more elegant implementation path that I missed, also unsure of any potential side affects this may have caused but I tried to be as minimal and backwards compatible as possible. Only obvious breaking change I can see is the modification of the existing constructor in OpenHtmlUserAgent which could be breaking if that class is used outside the library, but that could be alleviated by adding the new constructor along side the existing constructor. Using the new stylesheet property would also require the user to construct the BatikSVGDrawer with the argument SvgExternalResourceMode.INSECURE_ALLOW_EXTERNAL_RESOURCE_REQUESTS which may not be ideal.

Example usage:

BufferedOutputStream outputStream = null;
        try {
            outputStream = new BufferedOutputStream(new FileOutputStream(output));
            PdfRendererBuilder builder = new PdfRendererBuilder();
            builder.useFastMode();
            builder.withHtmlContent(html,executingUri);
            builder.toStream(outputStream);

            BatikSVGDrawer svgDrawer = new BatikSVGDrawer(BatikSVGDrawer.SvgScriptMode.SECURE, 
     BatikSVGDrawer.SvgExternalResourceMode.INSECURE_ALLOW_EXTERNAL_RESOURCE_REQUESTS);
            
            //new method added to inject external style sheet for SVG            
            svgDrawer.withUserStyleSheetURI("classpath://SOME_PATH/svgStyles.css");
            builder.useSVGDrawer(svgDrawer);
            builder.run();

        } catch (Exception e) {
            logger.error("Exception rendering pdf", e);
        }
        finally {
            outputStream.close();
        }

Thank you for the review and consideration!

…allows SVGs to render without requiring styles to be inline.
@syjer
Copy link
Contributor

syjer commented May 30, 2020

hi @amckain92 , personally I would prefer if the user don't need to specify a specific css for the svg, but instead, like a normal browser, it would apply the defined styles currently present.

That's why I'm kinda exploring the possibility to modify the dom of the svg elements and inline the css affecting them. I think it would be more transparent and less magic.

Clearly, YMMV and your solution is a nice stop gap :)

@danfickle
Copy link
Owner

I will look at this, specifically, how hard it is to extract styles to string once matches/cascade has run.

@danfickle
Copy link
Owner

Hi @amckain92,

I have now implemented auto-extraction of SVG styles as suggested by @syjer in #515. Maybe, you could have a look at it and see if it fits your requirements.

By the way, big thanks for contributing to the project.

@danfickle
Copy link
Owner

Ok, closing now. Thanks again for this contribution.

@danfickle danfickle closed this Aug 13, 2020
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.

External css file for SVG styles- best practices?
3 participants