En el post de hoy vamos a hablar sobre la generación de pdfs en nuestras aplicaciones web. Hoy en día muchas aplicaciones requieren la generación de algún tipo de documento que almacenar o mostrar al usuario como pueden ser la generación de facturas, cartas o justificantes, informes u otro tipo de documentos que podamos imaginar.
Hoy en día se trata de una tarea bastante común y existen distintas librerías para llevarlo a cabo. Por ello hoy vamos a conocer una herramienta que nos permite generar estos pdf a través de código html. Esta herramienta es wkhtmltopdf, una librería open source a través de linea de comandos que permite renderizar html dentro de un documento pdf empleando el motor de renderizado Webkit.
Vamos a ver un ejemplo de generación de un pdf a través de una maquetación html (http://adrianalonso.es/ejemplos/pdf-symfony2/index.html). Para ello vamos a emplear un bundle para el framework Symfony 2 que integra una librería que usa la herramienta wkhtml. Este bundle se llama KNPSnappyBundle y podeis encontrar toda la documentación sobre su instalación en su repositorio de github (https://github.com/KnpLabs/KnpSnappyBundle)
Tras instalar este Bundle podemos emplear el servicio knp_snappy.pdf el cual nos proporciona una serie de métodos para generar un documento pdf a través de un renderizado previo de html. Permite directamente almacenar este documento en el directorio deseado u obtener el output del resultado para poder devolverlo en la response de nuestro Action. En el siguiente código podemos ver un pequeña Action que renderiza nuestra plantilla html y se la pasa como parámetro al generador. Además este generador tiene gran cantidad de parametros para customizar nuestra generación. En el ejemplo he inicializao un array con todos los parámetros disponibles con los que podemos jugar para obtener el resultado deseado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
<?php namespace Alonsus\ExampleBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class DefaultController extends Controller { public function indexAction() { $html = $this->renderView('AlonsusExampleBundle:Default:index.html.twig', array()); $pdf= $this->get('knp_snappy.pdf')->getOutputFromHtml($html, array( 'ignore-load-errors' => null, // old v0.9 'lowquality' => false, 'collate' => null, 'no-collate' => null, 'cookie-jar' => null, 'copies' => null, 'dpi' => null, 'extended-help' => null, 'grayscale' => false, 'help' => null, 'htmldoc' => null, 'image-dpi' => null, 'image-quality' => null, 'manpage' => null, 'margin-bottom' => 0, 'margin-left' => 0, 'margin-right' => 0, 'margin-top' => 0, 'orientation' => null, 'output-format' => null, 'page-height' => null, 'page-size' => "A4", 'page-width' => null, 'no-pdf-compression' => null, 'quiet' => null, 'read-args-from-stdin' => null, 'title' => null, 'use-xserver' => null, 'version' => null, 'dump-default-toc-xsl' => null, 'dump-outline' => null, 'outline' => null, 'no-outline' => null, 'outline-depth' => null, 'allow' => null, 'background' => null, 'no-background' => null, 'checkbox-checked-svg' => null, 'checkbox-svg' => null, 'cookie' => null, 'custom-header' => null, 'custom-header-propagation' => null, 'no-custom-header-propagation' => null, 'debug-javascript' => null, 'no-debug-javascript' => null, 'default-header' => null, 'encoding' => null, 'disable-external-links' => null, 'enable-external-links' => null, 'disable-forms' => null, 'enable-forms' => null, 'images' => true, 'no-images' => null, 'disable-internal-links' => null, 'enable-internal-links' => null, 'disable-javascript' => null, 'enable-javascript' => null, 'javascript-delay' => null, 'load-error-handling' => null, 'disable-local-file-access' => null, 'enable-local-file-access' => null, 'minimum-font-size' => null, 'exclude-from-outline' => null, 'include-in-outline' => null, 'page-offset' => null, 'password' => null, 'disable-plugins' => null, 'enable-plugins' => null, 'post' => null, 'post-file' => null, 'print-media-type' => null, 'no-print-media-type' => null, 'proxy' => null, 'radiobutton-checked-svg' => null, 'radiobutton-svg' => null, 'run-script' => null, 'disable-smart-shrinking' => true, 'enable-smart-shrinking' => null, 'stop-slow-scripts' => null, 'no-stop-slow-scripts' => null, 'disable-toc-back-links' => null, 'enable-toc-back-links' => null, 'user-style-sheet' => null, 'username' => null, 'window-status' => null, 'zoom' => 1.04, 'footer-center' => null, 'footer-font-name' => null, 'footer-font-size' => null, 'footer-html' => "<h1>aqui</h1>", 'footer-left' => null, 'footer-line' => null, 'no-footer-line' => null , 'footer-right' => null, 'footer-spacing' => null, 'header-center' => null, 'header-font-name' => null, 'header-font-size' => null, 'header-html' => null, 'header-left' => null, 'header-line' => null, 'no-header-line' => null, 'header-right' => null, 'header-spacing' => null, 'replace' => null, 'disable-dotted-lines' => null, 'cover' => null, 'toc' => null, 'toc-depth' => null, 'toc-font-name' => null, 'toc-l1-font-size' => null, 'toc-header-text' => null, 'toc-header-font-name' => null, 'toc-header-font-size' => null, 'toc-level-indentation' => null, 'disable-toc-links' => null, 'toc-text-size-shrink' => null, 'xsl-style-sheet' => null, 'redirect-delay' => null, // old v0.9 )); return new \Symfony\Component\HttpFoundation\Response( $pdf, 200, array( 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'inline; filename="file.pdf"', )); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
<html> <meta charset="utf-8"> <head> <title>Ejemplo Documento PDF</title> <style type="text/css"> body { width: 21cm; margin: 0; padding: 0; } .page{width: 210mm;height: 297mm;} table { border-spacing: 0; width: 100%; border: 1px solid black} .break {page-break-after:always; margin-bottom: 1cm;} h2 {width: 14cm; height:0.7cm; color: #000000; background-color: #E9EEF1; padding-left: 1.08cm; font-weight: bold; font-size: 0.57cm;} .header{margin-left:1cm;margin-top:1cm;} div.left-gray{width: 7cm;height:29.7cm;background-color: #E9EEF1;float:left;} div.right-white{width: 14cm;height: 29.7cm;background-color: white;float:right;} .right-white h1{margin-left: 1cm; margin-top: 1cm;color: red;padding-top:1cm} .right-white p{margin-left: 1cm; width: 12cm;text-align: justify} .left-gray h1 {margin-top: 1cm;margin-left: 1cm;padding: 0;display: inline} .left-gray h3 {margin-left: 1cm;padding:0;display:inline;} </style> <head> <body> <div class="page"> <div class="left-gray"> <img src="default-placeholder.png" style="width:7cm;" > <h1>Documento</h1> <h3>de prueba</h3> </div> <div class="right-white"> <h1 style="margin-top:1cm">Titulo de documento</h1> <h2>Subtitulo de documento</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <h1>Titulo de documento</h1> <h2>Subtitulo de documento</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <h1>Titulo de documento</h1> <h2>Subtitulo de documento</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </div> </div> <div class="break"></div> <div class="page"> <div class="left-gray"> <img src="C:\xampp\htdocs\pdfexample\web\images\default-placeholder.png" style="width:7cm;" > <h1>Documento</h1> <h3>de prueba 2</h3> </div> <div class="right-white"> <h1 style="margin-top:1cm">Titulo de documento</h1> <h2>Subtitulo de documento</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <h1>Titulo de documento</h1> <h2>Subtitulo de documento</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <h1>Titulo de documento</h1> <h2>Subtitulo de documento</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </div> </div> </body> </html> |
El ejemplo completo podéis encontrarlo en el siguiente repositorio de github: https://github.com/adrianalonso/knp-pdf-example
El resultado de la generación del pdf es el siguiente, como podemos observar es fiel al html maquetado y obtenemos el resultado deseado con tan solo conocer tecnologías web que permitan maquetar el documento a nuestro gusto.
Como vemos generar documentos en PDF desde nuestras aplicaciones desarrolladas con Symfony2 es una tarea muy sencilla y configurable que nos abre gran posibilidades de funcionalidades extra que añadir a nuestras aplicaciones.