astefanutti / decktape

PDF exporter for HTML presentations
MIT License
2.21k stars 177 forks source link

Add a slimerjs backend #6

Closed hadim closed 9 years ago

hadim commented 9 years ago

Phantomjs is unfortunately based on QtWebKit which is now deprecated and so many rendering issue won't be fixed anytime soon.

The thing is QtWebKit is today year behind modern browser (Chromium and Firefox). Fortunately they planned to switch to a more modern backend (QtWebEngine, Chromium or Electron, see https://github.com/ariya/phantomjs/issues/10209). But it will obiously take time...

Slimerjs (http://slimerjs.org) is very similar to Phantomjs (almost the same API). And it is based on Gecko which fixe the issue I have (see #4, and #5).

This is why I decided to wrote a small js script to render my slides (made with revealjs) based on Slimerjs.

I wonder to know wether you're interested in integrating Slimerjs to decktape once my "proof of concept" script is done.

In the same way you created plugins, we could add a backend layer abstraction. Then, users could easly choose between both backend (Phantomjs or Slimerjs).

Some disadvantages about Slimerjs :

Would you be interested in such a feature ?

hadim commented 9 years ago

Here is a first very naive version of the script :

// TODO: pause all movies (some are played when calling Reveal.next()
// TODO: currentSlideIndex return the same thing for fragments so they are not saved as separate
// slides
// TODO: remove png files
// TODO: create pdf

var page = require('webpage').create();
var pagesPath = [];

page.open("http://localhost:8000", function (status) {

    page.viewportSize = { width: 1024, height: 768 };
    totalSlide = page.evaluate('Reveal.getTotalSlides');

    printSlide(totalSlide);

});

function printSlide(totalSlide) {
    window.setTimeout(function() {
        var i = currentSlideIndex();
        console.log("Rendering page " + i + "/" + totalSlide);
        currentPage = 'render/page' + i + '.pdf';
        pagesPath.push(currentPage);
        page.render(currentPage);

        if(!page.evaluate('Reveal.isLastSlide')) {
            page.evaluate("Reveal.next");
            printSlide(totalSlide);
        } else {
            createPDF();
            console.log("Done");
            phantom.exit(1);
        }
    }, 1000);
}

function currentSlideIndex() {
        var indices = page.evaluate("Reveal.getIndices");
        var id = page.evaluate("Reveal.getCurrentSlide").getAttribute("id");
        if (typeof id === "string" && id.length)
            return id;
        else
            return indices.h + (indices.v > 0 ? '_' + indices.v : '');
}

function createPDF(){
    // var doc = new jsPDF();
    // console.log("ddddd");
    // for (let currentPage in pagesPath) {
    //    console.log(currentPage);
    //
    //    doc.ellipse(40, 20, 10, 5);
    //
    //     doc.setFillColor(0,0,255);
    //     doc.ellipse(80, 20, 10, 5, 'F');
    //
    //     doc.setLineWidth(1);
    //     doc.setDrawColor(0);
    //     doc.setFillColor(255,0,0);
    //     doc.circle(120, 20, 5, 'FD');
    //     doc.addPage();
    // }
    //
    // doc.save('slides.pdf');
}

It will generate slides as png files from http://localhost:8000 in render/ directory.

To use it, do slimerjs test.js.

hadim commented 9 years ago

In fact I just realized that the abstraction layer would be really easy to implement since only function with printer call will need changes.

I opened an issue in slimerjs to ask wether it is possible to render multiple pages pdf.

hadim commented 9 years ago

See #7

astefanutti commented 9 years ago

@hadim that's a great idea! And thanks for the detailed analysis BTW.

The only concern that I have is about the quality of the exported PDFs. I initially had in mind a high-quality exporter for DeckTape. That being said, I don't see any problem, rather benefits, integrating SlimerJS right now and have it improved over time.

I'll review and integrate #7 ASAP.

hadim commented 9 years ago

I close here. Discussion can continue in #7.