Como criar um PDF a partir de seu aplicativo da Web
Publicados: 2022-03-10Muitos aplicativos da web têm o requisito de dar ao usuário a capacidade de baixar algo em formato PDF. No caso de aplicativos (como lojas de comércio eletrônico), esses PDFs precisam ser criados com dados dinâmicos e estar disponíveis imediatamente para o usuário.
Neste artigo, explorarei maneiras pelas quais podemos gerar um PDF diretamente de um aplicativo da Web em tempo real. Não é uma lista abrangente de ferramentas, mas, em vez disso, pretendo demonstrar as diferentes abordagens. Se você tiver uma ferramenta favorita ou alguma experiência própria para compartilhar, adicione-a aos comentários abaixo.
Começando com HTML e CSS
É provável que nosso aplicativo da web já esteja criando um documento HTML usando as informações que serão adicionadas ao nosso PDF. No caso de uma fatura, o usuário pode visualizar as informações on-line e clicar para baixar um PDF para seus registros. Você pode estar criando guias de remessa; mais uma vez, as informações já estão armazenadas no sistema. Você deseja formatar isso de uma maneira agradável para download e impressão. Portanto, um bom ponto de partida seria considerar se é possível usar esse HTML e CSS para gerar uma versão em PDF.
CSS tem uma especificação que lida com CSS para impressão, e este é o módulo Paged Media. Eu tenho uma visão geral desta especificação em meu artigo “Projetando para impressão com CSS”, e CSS é usado por muitas editoras de livros para toda a sua saída de impressão. Portanto, como o próprio CSS possui especificações para materiais impressos, certamente deveríamos poder usá-lo?
A maneira mais simples de um usuário gerar um PDF é por meio do navegador. Ao optar por imprimir em PDF em vez de uma impressora, um PDF será gerado. Infelizmente, este PDF geralmente não é totalmente satisfatório! Para começar, ele terá os cabeçalhos e rodapés que são adicionados automaticamente quando você imprime algo de uma página da web. Ele também será formatado de acordo com sua folha de estilo de impressão - supondo que você tenha uma.
O problema que encontramos aqui é o suporte deficiente da especificação de fragmentação nos navegadores; isso pode significar que o conteúdo de suas páginas é interrompido de maneiras incomuns. O suporte para fragmentação é irregular, como descobri quando pesquisei meu artigo, “Quebrando caixas com fragmentação CSS”. Isso significa que você pode não conseguir impedir a quebra de conteúdo abaixo do ideal, com os cabeçalhos sendo deixados como o último item da página e assim por diante.
Além disso, não podemos controlar o conteúdo nas caixas de margem da página, por exemplo, adicionando um cabeçalho de nossa escolha a cada página ou numeração de página para mostrar quantas páginas uma fatura complexa possui. Essas coisas fazem parte da especificação de mídia paginada, mas não foram implementadas em nenhum navegador.
Meu artigo “Um guia para o estado das folhas de estilo de impressão em 2018” ainda é preciso em termos do tipo de suporte que os navegadores têm para imprimir diretamente do navegador, usando uma folha de estilo de impressão.
Imprimindo usando mecanismos de renderização de navegador
Existem maneiras de imprimir em PDF usando mecanismos de renderização do navegador, sem passar pelo menu de impressão no navegador e terminando com cabeçalhos e rodapés como se você tivesse impresso o documento. As opções mais populares em resposta ao meu tweet foram wkhtmltopdf e impressão usando o Chrome sem cabeça e o Puppeteer.
wkhtmltopdf
Uma solução que foi mencionada várias vezes no Twitter é uma ferramenta de linha de comando chamada wkhtmltopdf. Essa ferramenta pega um arquivo HTML ou vários arquivos, junto com uma folha de estilo e os transforma em um PDF. Ele faz isso usando o mecanismo de renderização WebKit.
Usamos wkhtmltopdf. Não é perfeito, embora provavelmente tenha sido um erro do usuário, mas facilmente bom o suficiente para um aplicativo de produção.
— Paul Cardno (@pcardno) 15 de fevereiro de 2019
Essencialmente, portanto, essa ferramenta faz a mesma coisa que imprimir a partir do navegador, no entanto, você não obterá os cabeçalhos e rodapés adicionados automaticamente. Por esse lado positivo, se você tiver uma folha de estilo de impressão funcional para o seu conteúdo, ela também deve sair em PDF usando essa ferramenta e, portanto, um layout simples pode imprimir muito bem.
Infelizmente, no entanto, você ainda terá os mesmos problemas ao imprimir diretamente do navegador da Web em termos de falta de suporte para a especificação de mídia paginada e propriedades de fragmentação, pois ainda está imprimindo usando um mecanismo de renderização do navegador. Existem alguns sinalizadores que você pode passar para wkhtmltopdf para adicionar novamente alguns dos recursos ausentes que você teria por padrão usando a especificação de mídia paginada. No entanto, isso requer algum trabalho extra além de escrever um bom HTML e CSS.
Chrome sem cabeça
Outra possibilidade interessante é usar o Headless Chrome e o Puppeteer para imprimir em PDF.
Marionetista. É incrível por isso.
— Alex Russell (@slightlylate) 15 de fevereiro de 2019
No entanto, mais uma vez, você está limitado pelo suporte do navegador para mídia paginada e fragmentação. Existem algumas opções que podem ser passadas para a função page.pdf()
. Assim como o wkhtmltopdf, eles adicionam algumas das funcionalidades que seriam possíveis do CSS caso houvesse suporte ao navegador.
Pode ser que uma dessas soluções faça tudo o que você precisa, no entanto, se você achar que está travando uma batalha, é provável que esteja atingindo os limites do que é possível com os atuais mecanismos de renderização do navegador e terá de procurar uma solução melhor.
Polyfills JavaScript para mídia paginada
Existem algumas tentativas de reproduzir essencialmente a especificação de mídia paginada no navegador usando JavaScript – essencialmente criando um Polyfill de mídia paginada. Isso pode fornecer suporte de mídia paginada ao usar o Puppeteer. Dê uma olhada em paged.js e Vivliostyle.
sim. Para documentos simples, como certificados de cursos, podemos usar o Chrome, que tem suporte mínimo para página @. Para qualquer outra coisa, usamos PrinceXML ou o polyfill paged.js no Chrome. Aqui está uma prova de conceito WIP usando paged.js para livros: https://t.co/AZ9fO94PT2
— Electric Book Works (@electricbook) 15 de fevereiro de 2019
Usando um agente de usuário de impressão
Se você quiser ficar com uma solução de HTML e CSS, você precisa procurar um User Agent (UA) projetado para imprimir a partir de HTML e CSS, que possui uma API para gerar o PDF a partir de seus arquivos. Esses User Agents implementam a especificação de mídia paginada e têm um suporte muito melhor para as propriedades de fragmentação de CSS; isso lhe dará maior controle sobre a saída. As principais escolhas incluem:
- Principe
- Casa da Antena
- PDFReactor
Um UA de impressão formatará documentos usando CSS — assim como um navegador da web. Tal como acontece com o suporte do navegador para CSS, você precisa verificar a documentação desses UAs para descobrir o que eles suportam. Por exemplo, Prince (com o qual estou mais familiarizado) suporta Flexbox, mas não CSS Grid Layout no momento da escrita. Ao enviar suas páginas para a ferramenta que você está usando, normalmente isso seria com uma folha de estilo específica para impressão. Tal como acontece com uma folha de estilo de impressão normal, o CSS que você usa em seu site não será apropriado para a versão PDF.
A criação de uma folha de estilo para essas ferramentas é muito semelhante à criação de uma folha de estilo de impressão normal, tomando as decisões em termos do que exibir ou ocultar, talvez usando um tamanho de fonte ou cores diferentes. Assim, você poderá aproveitar os recursos da especificação de mídia paginada, adicionando notas de rodapé, números de página e assim por diante.
Em termos de uso dessas ferramentas em seu aplicativo web, você precisaria instalá-las em seu servidor (tendo adquirido uma licença para isso, é claro). O principal problema com essas ferramentas é que elas são caras. Dito isto, dada a facilidade com que você pode produzir documentos impressos com eles, eles podem se pagar em tempo de desenvolvedor economizado.
É possível usar o Prince por meio de uma API, com pagamento por documento, por meio de um serviço chamado DocRaptor. Este seria certamente um bom lugar para muitos aplicativos começarem, pois parece que se tornaria mais econômico hospedar o seu próprio, o custo de desenvolvimento da comutação seria mínimo.
Uma alternativa gratuita, que não é tão abrangente quanto as ferramentas acima, mas pode alcançar os resultados que você precisa, é o WeasyPrint. Ele não implementa totalmente toda a mídia paginada, no entanto, implementa mais do que um mecanismo de navegador. Definitivamente, um para experimentar!
Outras ferramentas que afirmam oferecer suporte à conversão de HTML e CSS incluem PDFCrowd, que afirma ousadamente suportar HTML5, CSS3 e JavaScript. No entanto, não consegui encontrar nenhum detalhe sobre exatamente o que era suportado e se alguma das especificações de mídia paginada era. Também recebendo uma menção nas respostas ao meu tweet foi o mPDF.
Afastando-se de HTML e CSS
Existem várias outras soluções que se afastam do uso de HTML e CSS e exigem que você crie uma saída específica para a ferramenta. Alguns concorrentes JavaScript são os seguintes:
- jsPDF
- pdf make
Navegador sem cabeça + salvar em PDF já foi minha primeira escolha, mas sempre produzia resultados abaixo da média para qualquer coisa que não fosse um documento de página única. Mudamos para https://t.co/3o8Ce23F1t para relatórios de várias páginas que exigia muito mais esforço, mas valeu a pena no final!
— JimmyJoy (@jimle_uk) 15 de fevereiro de 2019
Recomendações
Além das abordagens baseadas em JavaScript, que exigiriam que você criasse uma representação completamente diferente do seu conteúdo para impressão, a beleza de muitas dessas soluções é que elas são intercambiáveis. Se sua solução for baseada em chamar uma ferramenta de linha de comando e passar a essa ferramenta seu HTML, CSS e possivelmente algum JavaScript, é bastante simples alternar entre as ferramentas.
Enquanto escrevia este artigo, também descobri um wrapper Python que pode executar várias ferramentas diferentes. (Observe que você já precisa ter as próprias ferramentas instaladas, no entanto, essa pode ser uma boa maneira de testar as várias ferramentas em um documento de amostra.)
Para suporte de mídia paginada e fragmentação, Prince, Antenna House e PDFReactor serão os melhores. Como produtos comerciais, eles também vêm com suporte. Se você tiver um orçamento, páginas complexas para imprimir em PDF e sua limitação for o tempo do desenvolvedor, provavelmente achará que esse é o caminho mais rápido para que sua criação de PDF funcione bem.
No entanto, em muitos casos, as ferramentas gratuitas funcionarão bem para você. Se seus requisitos forem muito diretos, o wkhtmltopdf, ou uma solução básica do Chrome e do Puppeteer sem cabeça, pode resolver o problema. Certamente pareceu funcionar para muitas das pessoas que responderam ao meu tweet original.
No entanto, se você estiver lutando para obter a saída desejada, esteja ciente de que pode ser uma limitação da impressão do navegador e não algo que você esteja fazendo de errado. No caso de você desejar mais suporte de mídia paginada, mas não estiver em condições de optar por um produto comercial, talvez dê uma olhada no WeasyPrint.
Espero que este seja um resumo útil das ferramentas disponíveis para criar PDFs de seu aplicativo da web. Se nada mais, ele demonstra que há uma grande variedade de opções, se sua escolha inicial não estiver funcionando bem.
Por favor, adicione suas próprias experiências e sugestões nos comentários, esta é uma daquelas coisas com as quais muitos de nós acabam lidando, e a experiência pessoal compartilhada pode ser incrivelmente útil.
Leitura adicional
Um resumo dos vários recursos e ferramentas mencionados neste artigo, juntamente com alguns outros recursos úteis para trabalhar com arquivos PDF de aplicativos da web.
Especificações
- Módulo de mídia paginada
- Fragmentação
Artigos e Recursos
- Projetando para impressão com CSS
- Quebrando caixas com fragmentação CSS
- Um guia para o estado das folhas de estilo de impressão em 2018
- Introdução ao Headless Chrome e ao Puppeteer
- print-css.rocks
Ferramentas
- wkhtmltopdf
- paged.js
- Viviestilo
- Principe
- Casa da Antena
- PDFReactor
- DocRaptor
- WeasyPrint
- PDFMultidão
- mPDF
- jsPDF
- pdf make
- Servidor de produção e publicação