Aprende a convertir un PDF a una imagen en Symfony con la ayuda de Ghostscript, Imagick y pdf-to-image.

Cómo convertir un PDF a una imagen con PHP en Symfony 3

Hace un par de días, necesitaba enviar un fax (sí, en 2017 la gente todavía usa el fax, no me pregunte por qué) y parece que el enrutador necesitaba un archivo de imagen en lugar de un PDF, de lo contrario, el proceso puede fallar. . Así que simplemente convertí el PDF con un servicio en línea en imágenes y completé mi tarea. Si usted es un desarrollador backend que necesita implementar una característica tan útil en su aplicación, es posible que deba saber que no hay forma de hacerlo con PHP simple y puro.

Sin embargo, puedes lograrlo gracias a Imagick y Ghostscript y te mostraremos cómo en este artículo.

Requisitos

La biblioteca que vamos a utilizar es un contenedor que abstrae el uso de la línea de comandos con algún código PHP. Deberá haber instalado en su máquina específicamente las siguientes 2 herramientas:

Recuerde que Ghostscript debe ser accesible desde la línea de comandos, eso significa que las carpetas binlib(dentro de la ruta de instalación, por ejemplo C:\Program Files (x86)\gs\gs9.21) deben existir en la variable de entorno PATH.

1. Instale PHP Wrapper

Lo primero que debe hacer para convertir un PDF a una imagen en su proyecto Symfony es instalar la biblioteca contenedora que hace el trabajo duro de los comandos por usted. Estamos hablando de pdf-to-image, un paquete que proporciona una manera fácil de trabajar con la clase para convertir archivos PDF a imágenes. Como se mencionó, el contenedor se basa en una extensión Imagick instalada y funcional y también en Ghostscript.

Según la versión de PHP que esté utilizando, deberá instalar una versión diferente de la biblioteca:

Para PHP 7

Si está utilizando la rama 7.x de PHP, puede trabajar con la última versión de la biblioteca. Instálelo con composer ejecutando el siguiente comando:

REM Download the latest version of the wrapper library
composer require spatie/pdf-to-image

Para PHP <= 5.5.0

Como la última versión de la biblioteca requiere PHP 7 o más reciente, en caso de que esté utilizando la versión 5.x de PHP, también puede instalar una versión anterior del contenedor con Composer:

REM Download the 1.4.0 version of pdf-to-image
composer require spatie/pdf-to-image 1.4.0

Para obtener más información sobre esta biblioteca , visite el repositorio oficial en Github aquí .

2. Usando la biblioteca

El uso de esta biblioteca es bastante sencillo y funcionará perfectamente siempre que tenga Imagick y Ghostscript instalados correctamente en su máquina. Solo necesita crear una instancia de la clase Pdf de Spatie \ PdfToImage, el constructor espera como primer argumento la ruta al PDF que desea convertir en una imagen, luego puede simplemente usar el método saveImage para generar la imagen a partir del PDF. Este método espera la ruta absoluta con el nombre de archivo de la imagen que generará. Si la ruta se pasa a saveImagetiene las extensiones jpgjpegpngla imagen se guardará en ese formato. De lo contrario, la salida será un jpg. También puede forzar el formato utilizando el setOutputFormatmétodo.

En nuestro ejemplo lo vamos a forzar en formato png, para que tenga transparencia, sin embargo eres libre de usar el formato que necesites:

A. Imagen única

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Utilice la clase BinaryFileResponse de Symfony para devolver un archivo como respuesta
use Symfony\Component\HttpFoundation\BinaryFileResponse;
// Requiere clase PDF de la biblioteca
use Spatie\PdfToImage\Pdf;

class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction()
    {
        // Ruta al archivo PDF que desea convertir en una imagen
        $pdfFilePath = $this->get('kernel')->getRootDir() . '/../web/filename.pdf';

        // Ruta y nombre de archivo de la imagen que se generará
        // debe ser absoluto y con la extensión de archivo
        $outputImagePath = $this->get('kernel')->getRootDir() . '/../web/pdf_image.png';

        // Cree una instancia de PDF con la ruta de archivo del PDF
        $pdf = new Pdf($pdfFilePath);

        // Establecer el formato de imagen para el archivo de salida
        $pdf->setOutputFormat('png');

        // Genere una imagen desde PDF en la ruta de archivo deseada
        $pdf->saveImage($outputImagePath);

        // Devuelve la imagen como respuesta
        return new BinaryFileResponse(
            $outputImagePath
        );
    }
}

B. Varias imágenes de varias páginas

De forma predeterminada, si el PDF tiene varias páginas y usa el código predeterminado para convertirlo en una imagen, siempre obtendrá una sola imagen (de la primera página). Para generar una imagen de cada página, deberá cambiar el índice de página del PDF. Puede hacerlo simplemente recorriendo el número total de páginas y actualizando el índice manualmente y luego ejecute el método saveImage con el nombre del archivo y el índice como resultado: 

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Usa la clase de respuesta normal
use Symfony\Component\HttpFoundation\Response;
// Requiere clase PDF de la biblioteca
use Spatie\PdfToImage\Pdf;

class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction()
    {
        // Ruta al archivo PDF que desea convertir en una imagen
        $pdfFilePath = $this->get('kernel')->getRootDir() . '/../web/pdf_with_many_pages.pdf';

        // Crea un archivo TMP de la imagen con formato PNG
        $fileName = uniqid().'.png';
        
        // Obtén el camino de la imagen temporal
        $outputImagePath = tempnam(sys_get_temp_dir(), $fileName);

        // Cree una instancia de PDF con la ruta de archivo del PDF
        $pdf = new Pdf($pdfFilePath);

        // Recorre cada página
        foreach (range(1, $pdf->getNumberOfPages()) as $pageNumber) {
            // Establezca el índice del PDF en la página que desee
            $pdf->setPage($pageNumber);

            // Establecer el formato de imagen y la ruta de salida
            $pdf->setOutputFormat('png')
                ->saveImage('pdf_image'.$pageNumber.".png");
        }

        // Devuelve la imagen del archivo TMP en respuesta
        return new Response("All the pages of the PDF were succesfully converted to images");
    }
}

C. Genere una imagen TMP sin guardarla localmente

En caso de que esté dispuesto a generar una imagen a partir de un PDF sin guardarla dentro de una ruta local, entonces deberá crear un archivo TMP con PHP en su sistema operativo, ya que el contenedor requiere escribir el archivo en algún lugar. Usted puede crear fácilmente un archivo temporal con métodos  tempnamsys_get_temp_dir de PHP:

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Utilice una clase BinaryFileResponse de Symfony para devolver un archivo como respuesta
use Symfony\Component\HttpFoundation\BinaryFileResponse;
// Requerir clase de PDF de la biblioteca
use Spatie\PdfToImage\Pdf;

class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction()
    {
        // Ruta al archivo PDF que desea convertir en una imagen
        $pdfFilePath = $this->get('kernel')->getRootDir() . '/../web/filename.pdf';

        // Crea un archivo TMP de la imagen con formato PNG
        $fileName = uniqid().'.png';
        
        // Obtén el camino de la imagen temporal
        $outputImagePath = tempnam(sys_get_temp_dir(), $fileName);

        // Cree una instancia de PDF con la ruta de archivo del PDF
        $pdf = new Pdf($pdfFilePath);

        // Establecer el formato de imagen para el archivo de salida
        $pdf->setOutputFormat('png');

        // Genere una imagen de PDF en el archivo TMP
        $pdf->saveImage($outputImagePath);

        // Devuelve la imagen del archivo TMP como respuesta
        return new BinaryFileResponse(
            $outputImagePath
        );
    }
}

Problemas para el usuario de Windows

En Windows, es muy importante que la arquitectura de la versión instalada de Imagick y Ghostscript sea la misma. Esto significa que si tiene Imagick x86 (32 bits), Ghostscript debe tener la misma arquitectura también x86 y viceversa. De lo contrario, su código está abierto a muchas posibles excepciones como:

PDFDelegateFailed `El sistema no puede encontrar el archivo especificado. '@ error / pdf.c / ReadPDFImage / 801
PDFDelegateFailed `The system cannot find the file specified. ' @ error/pdf.c/ReadPDFImage/801

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores