سؤال

I'm currently trying to generate a PDF document from a HTML page through Node & PhantomJS.

If my page contains local resources, or only static things, it works fine :

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <link rel="StyleSheet" media="screen" href="./style.css" />
        <link rel="StyleSheet" media="print" href="./print.css" />
    </head>
    <body>
        <h1>The title</h1>
        <p>hai <span class="foo">lol <span class="bar">I'm generating</span> a pdf</span> !</p>
        <p class="centre"><img src="http://www.gratuit-en-ligne.com/telecharger-gratuit-en-ligne/telecharger-image-wallpaper-gratuit/image-wallpaper-animaux/img/images/image-wallpaper-animaux-autruche.jpg" /></p>
        <canvas id="test_canvas" width="200px" height="100px"/>

        <script>
            setTimeout(function () {
                var ctx = document.getElementById('test_canvas').getContext('2d');

                ctx.fillStyle = '#FF0000';
                ctx.fillRect(0, 0, 150, 75);
            }, 1000);

            setTimeout(function () {
                evt = document.createEvent('CustomEvent');
                evt.initEvent('pdfTrigger', true, false);

                document.dispatchEvent(evt);
            }, 3000);
        </script>
    </body>
</html>

So here, the image is correctly rendered, and the stylesheets are also correctly rendered. But if I add an inclusion from a distant image, or a distant script (something beginning with either //, either http:// or https://, even if it is directed towards my local environment), the content is not loaded :

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <link rel="StyleSheet" media="screen" href="./style.css" />
        <link rel="StyleSheet" media="print" href="./print.css" />
    </head>
    <body>
        <h1>The title</h1>
        <p>hai <span class="foo">lol <span class="bar">I'm generating</span> a pdf</span> !</p>
        <p class="centre"><img src="http://upload.wikimedia.org/wikipedia/commons/7/7c/Ostrich,_mouth_open.jpg" /></p>

        <script>
            setTimeout(function () {
                evt = document.createEvent('CustomEvent');
                evt.initEvent('pdfTrigger', true, false);

                document.dispatchEvent(evt);
            }, 3000);
        </script>
    </body>
</html>

The image is not rendered ; if I try with a jQuery include from a cdn and some jQuery code (like firing an event through $(document).trigger('pdfTrigger')), it says ReferenceError: Can't find variable: $, and thus the event is never fired. If I include it in my html file on a local resource (like <script src="./jquery.min.css"></script>), the error disappear but the event is never fired...

Here is the phantomjs script i'm using :

/**
 * Render a PDF from an HTML file
 *
 * @author Baptiste Clavié <baptiste@wisembly.com>
 * Adapted from PhantomJs' example "rasterize.js"
 */

var orientation = 'portrait',
    system = require('system'),
    args = system.args.slice(1);

if (args.length < 2 || args.length > 3) {
    system.stderr.writeLine('Usage: rasterize.js source output [orientation]');
    system.stderr.writeLine('   source : html source to put in the pdf');
    system.stderr.writeLine('   output : output when the pdf will be written');
    system.stderr.writeLine('   orientation : document orientation (either portrait or landscape');

    phantom.exit((args.length === 1 & args[0] === '--help') ? 0 : 1);
}

if (typeof args[2] !== 'undefined') {
    if (-1 === ['portrait', 'landscape'].indexOf(args[2])) {
        system.stderr.writeLine('Invalid argument for [orientation]');
        system.stderr.write('Expected either "portrait", either "landscape" ; got "' + args[2] + '"');

        phantom.exit(1);
    }

    orientation = args[2];
}

var page = require('webpage').create(),
    identifier = '___RENDER____';

page.paperSize = { format: 'A4', orientation: orientation, margin: '1cm' };

page.onInitialized = function() {
    page.evaluate(function(identifier) {
        document.addEventListener('pdfTrigger', function () {
            console.log(identifier);
        }, false);
    }, identifier);
};

page.onError = function (msg, trace) {
    system.stderr.writeLine(msg);

    trace.forEach(function(item) {
        system.stderr.writeLine('   ' + item.file + ':' + item.line);
    });

    phantom.exit(1);
}

page.onConsoleMessage = function (msg) {
    console.log(msg);

    if (msg !== identifier) {
        return;
    }

    page.render(args[1], { format: 'pdf' });
    phantom.exit(0);
}

page.open(args[0], function (status) {
    if (status !== 'success') {
        system.stderr.write('Unable to load the file "' + args[0] + '"');
        phantom.exit(1);
    }
});

To launch my script, i'm using the following command : phantomjs rasterize.pdf test.html test.pdf

to sum up, it seems I can't load any external things from a html when trying to render it in Phantom, and jQuery is not recognized (and probably some other scripts ?)

Any idea ? If more precision if needed, please don't hesitate.

هل كانت مفيدة؟

المحلول

Change:

setTimeout(function () {
    evt = document.createEvent('CustomEvent');
    evt.initEvent('pdfTrigger', true, false);

    document.dispatchEvent(evt);
}, 3000);

To:

window.onload = function () {
    evt = document.createEvent('CustomEvent');
    evt.initEvent('pdfTrigger', true, false);

    document.dispatchEvent(evt);
};

The reason why it was failing is because that image is pretty big, and you were triggering the pdf event before the image had been properly downloaded. Using window.onload is reliable as the onload event will only be run when all page resources have loaded.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top