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

Unable to use SVG in PDF generation #85

Closed
tbadie opened this issue Apr 11, 2017 · 3 comments
Closed

Unable to use SVG in PDF generation #85

tbadie opened this issue Apr 11, 2017 · 3 comments

Comments

@tbadie
Copy link

tbadie commented Apr 11, 2017

Hi team, I have tried to generate a basic pdf with a svg in but somehow it doesn't come through, and I was wondering if I had anything missing.

I am using the RC10, I have included the different modules (openhtmltopdf-svg-support, openhtmltopdf-jsoup-dom-converter, openhtmltopdf-pdfbox, openhtmltopdf-core) at that version. I have created a small main with a simple example (from https://commons.wikimedia.org/wiki/SVG_examples), but cannot see the image. Here is the main:

    public static void main(String[] args) {
        String content = "<!DOCTYPE HTML>\n" +
                "<html>\n" +
                "<body>\n" +
                "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n" +
                "     width=\"120\" height=\"120\" viewBox=\"0 0 236 120\">\n" +
                "    <rect x=\"14\" y=\"23\" width=\"200\" height=\"7\" fill=\"lime\"\n" +
                "          stroke=\"black\" stroke-width=\"1\" />\n" +
                "</svg>\n" +
                "</body>\n" +
                "</html>";

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PdfRendererBuilder builder = new PdfRendererBuilder();

        org.jsoup.nodes.Document doc;

        doc = Jsoup.parse(content);

        builder.withW3cDocument(DOMBuilder.jsoup2DOM(doc), null);
        builder.useSVGDrawer(new BatikSVGDrawer());
        builder.toStream(os);
        try {
            builder.run();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(Base64.getEncoder().encodeToString(os.toByteArray()));
    }

As a side note, I do not see the openhtmltopdf-svg-support module in the documentation (https://github.com/danfickle/openhtmltopdf/blob/open-dev-v1/docs/integration-guide.md#maven-artifacts), so you may have forgotten to add it there.

Thanks for building this library, it's very useful!

@danfickle
Copy link
Owner

Hi @tbadie
Sorry for the long delay. I just got around to debugging this. It seems the problem is in the Jsoup to DOM conversion where the xmlns attribute is omitted (and the xmlns is required by the Batik SVG renderer). It is a simple fix to not omit it but I don't know why it was omitted in the first place, so I'm wary of touching it.

Could you use the XML parser, as below, or is your real input messy? If it is messy and you can't use XML, I'll make the change in the DOM converter. Let me know.

	   public static void main(String[] args) {
	        String content = "<!DOCTYPE HTML>\n" +
	                "<html>\n" +
	                "<body>\n" +
	                "<svg style=\"border: 4px solid red;\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n" +
	                "     width=\"120\" height=\"120\" viewBox=\"0 0 236 120\">\n" +
	                "    <rect x=\"14\" y=\"23\" width=\"200\" height=\"7\" fill=\"lime\"\n" +
	                "          stroke=\"black\" stroke-width=\"1\" />\n" +
	                "</svg>\n" +
	                "</body>\n" +
	                "</html>";

	        //ByteArrayOutputStream os = new ByteArrayOutputStream();
	        PdfRendererBuilder builder = new PdfRendererBuilder();

	        //org.jsoup.nodes.Document doc;

	        //doc = Jsoup.parse(content);

	        //builder.withW3cDocument(DOMBuilder.jsoup2DOM(doc), null);
	        builder.withHtmlContent(content, null);
	        builder.useSVGDrawer(new BatikSVGDrawer());
	        
	        try {
	        	builder.toStream(new FileOutputStream("/Users/you/Documents/pdftests/svg-issue-85.pdf"));
	            builder.run();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }

	        //System.out.println(Base64.getEncoder().encodeToString(os.toByteArray()));
	    }

danfickle added a commit that referenced this issue Apr 23, 2017
Also add missing SVG artifact in maven artifact list. Thanks @tbadie
@rototor
Copy link
Contributor

rototor commented May 9, 2017

@danfickle btw: I tried to use jsoup for a project of mine instead of JTidy. But jsoup destroyed my table layout, because it changed the DOM structure.

So I stick for JTidy for now, I just had to increase the max line length, because JTidy did a column wrap in between a pair of quotes in a font-family declaration. JTidy seems to preserve the HTML structure as best as possible.

	private static String tidyHtml(String htmlString) {
		Tidy tidy = new Tidy();
		tidy.setDocType("omit");
		tidy.setXmlOut(true);
		tidy.setQuiet(true);
		tidy.setTidyMark(false);
		tidy.setInputEncoding("UTF-8");
		tidy.setOutputEncoding("UTF-8");
		tidy.setWraplen(100_000);
		StringWriter outError = new StringWriter();
		tidy.setErrout(new PrintWriter(outError));
		StringWriter sw = new StringWriter();
		tidy.parse(new StringReader(htmlString), sw);
		String tidyHtml = sw.getBuffer().toString();
		tidyHtml = tidyHtml.replaceAll("(\r\n|\n|\r)+\\s*<", "<");
		if (tidyHtml.isEmpty())
			throw new IllegalStateException(outError.toString());
		return tidyHtml;
	}
		<dependency>
			<groupId>net.sf.jtidy</groupId>
			<artifactId>jtidy</artifactId>
			<version>r938</version>
		</dependency>

@danfickle
Copy link
Owner

Closing due to lack of feedback. Reopen if needed.

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

No branches or pull requests

3 participants