Screenshots de qualquer dimensão, com o PhantomJS

O problema

Às vezes precisamos de um screenshot de uma página web com uma resolução diferente da do nosso ecrã. Se essa resolução for menor que a do nosso ecrã, a coisa até se resolve. Redimensiona-se a janela para a dimensão pretendida e usa-se um dos muitos plugins disponíveis, embora nem sempre sejam muito fiáveis se quisermos uma resolução exacta. Se a resolução for maior, torna-se um bocado mais complicado. Se precisarmos de simular uma pixel density maior (aka retina), ainda pior.

Deparei-me com este problema quando precisei de criar screenshots para o meu portefólio. Comprei um daqueles ficheiros .psd com computadores e telemóveis de vários tamanhos. Por alguma razão todos estes ficheiros apresentam produtos Apple e, para funcionar correctamente, precisava de screenshots com uma resolução idêntica à dos Macs e iPhones.

A solução

É aqui que entra o PhantomJS. Uma implementação do Webkit que pode ser manipulada via JavaScript. Tem vários casos de uso. Entre eles, o que nos interessa para hoje, a geração de capturas de ecrã.

O script para fazer isso é bastante simples.

var webPage = require('webpage');
var page = webPage.create();

// o tamanho do screenshot
page.viewportSize = { width: 2880, height: 1800 };

// o endereço da página a capturar
page.open("https://zecipriano.com/", function start(status) {

    page.evaluate(function () {

        // a escala do conteúdo, 1 para normal, 2 para uma espécie de retina
        var scale = 2;

        document.body.style.webkitTransform = "scale(" + scale + ")";
        document.body.style.webkitTransformOrigin = "0% 0%";
        document.body.style.width = 100/scale + "%";

    });

    // o ficheiro a gravar, a extensão define o formato
    page.render('output.png');

    phantom.exit();

});

Para obter um screenshot basta gravar este script num ficheiro (por exemplo screenshot.js), editar com os valores pretendidos  e executar o PhamtonJS.

phantomjs screenshot.js

O scale = 2 é o valor que vai simular um ecrã com densidade 2x (só mais ou menos, ver notas). Para um screenshot normal, o valor deve ser 1.

De notar que isto é a forma mais simples de resolver o problema. O script podia ser melhorado de vários formas, nomeadamente aceitar os valores como parâmetros em vez de serem hardcoded no script.

Algumas questões:

  • Usar o scale = 2 não emula completamente um ecrã de alta densidade. Apenas duplica o tamanho do conteúdo, o device pixel ratio continua a ser 1. O que elimina, por exemplo, a possibilidade de gerar correctamente um screenshot de um ecrã de telemóvel.
  • A versão actual (1.9) não suporta Google Web Fonts (mais especificamente ficheiros .woff). Apenas a próxima versão (2.0) resolve este problema. Podem encontrar um build da versão 2, aqui.
  • A altura do viewport parece não ter influência na altura do screenshot. Mas depois de ter o screenshot é fácil de cortar à dimensão correcta.