0

I have a page with some SVG, and I want to generate a PDF from it. For this scope I'm using Flying Saucer with OpenPDF, and I converted the SVGs to images using:

var $body_clone = $('#pdf_container').clone();

var $svgs  = $body_clone.find('svg');
var $svg;
var xml;
var data;
var $img;

for (var i=0; i<$svgs.length; i++) {
    var $svg = $svgs.eq(i);
    xml = new XMLSerializer().serializeToString($svg[0]);
    data = "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(xml)));
    $img  = $(new Image());
    $img.attr('src', data);
    $img.width($svg.outerWidth(true));
    $img.height($svg.outerHeight(true));
    $svg.replaceWith($img[0].outerHTML);
}

I tried removing clone() and the submit and it works: the SVGs are replaced in page with (ugly) images.

Restoring clone() and form submit, I send the html of $body_clone on server, where is added to an ad hoc template for pdfs, using Mustache. Then I sanitize the html converting to xhtml with jsoup, I transform it with Flying Saucer and send it to the http response.

What I get is a pdf with text only. The SVGs converted to images are not present.

I also added -Djava.protocol.handler.pkgs=org.xhtmlrenderer.protocols as suggested in this SO answer, but nothing. I suspect the problem is the src of images are not data:image/png, for example, but data:image/svg+xml.

Anyway I tried to print the entire page with the browser (Firefox), printing to file as PDF (Lubuntu). Not only the images are shown, but they are perfect. What Lubuntu uses to print to pdf? It's possible to use it as an external converter? If not, how it works and there's a way to emulate the print to file?

Marco Sulla
  • 15,299
  • 14
  • 65
  • 100

1 Answers1

0

I ended up using SaveSvgAsPng this way:

function downloadPdf() {
    "use strict";

    //  get the graphics global container
    var $body_clone = $('#pdf_container');
    // get the SVGs
    var $svgs = $('.graph_container svg');
    var $svg;
    var promises = [];

    for (var i=0; i<$svgs.length; i++) {
        $svg = $svgs.eq(i);

        // convert the SVGs to images srcs
        promises.push(svgAsPngUri($svg[0]));
    }

    $.when.apply(null, promises).then(function() {
    var img_scrs = Array.prototype.slice.call(arguments);
    var $img;

        for (var i=0; i<$svgs.length; i++) {
            $svg = $svgs.eq(i);
            $img = $(new Image());
            $img.attr("src", img_scrs[i]);
            // substitute the SVGs with the image
            $svg.replaceWith(imgs[i]);
        }

        var $body_clone = $('#pdf_container');
        var body = $body_clone[0].outerHTML;
        $('#pdfBody').val(body);

        // send to the server the HTML of the container of all images
        $('#pdfForm').submit();

        // get all images
        var $imgs = $('.graph_container img:not(.waiting)');
        var $img;

        for (var i=0; i<$imgs.length; i++) {
            $img = $imgs.eq(i);
            // replace image with empty svg
            $img.replaceWith('<svg></svg>');
        }

        // repopulate the graphs as you did at the page load
        grafic();
    });
}

As alternative, you could use chromium as pdf converter:

chromium-browser --headless --print-to-pdf=path/to/file.pdf https://example.com

or

chromium-browser --headless --print-to-pdf=path/to/file.pdf file:/path/to/file.html

The result is perfect.

Marco Sulla
  • 15,299
  • 14
  • 65
  • 100