php - titulo - Obtener el número de páginas en un documento PDF
metadata pdf (8)
Esta pregunta es para referenciar y comparar. La solución es la respuesta aceptada a continuación .
Muchas horas he buscado una manera rápida y fácil, pero en su mayoría precisa , de obtener el número de páginas en un documento PDF. Como trabajo para una empresa de impresión y reproducción gráfica que trabaja mucho con archivos PDF, el número de páginas de un documento debe conocerse con precisión antes de que se procesen. Los documentos PDF provienen de muchos clientes diferentes, por lo que no se generan con la misma aplicación y / o no usan el mismo método de compresión.
Estas son algunas de las respuestas que encontré insuficientes o que simplemente NO funcionan :
Usando Imagick (una extensión de PHP)
Imagick requiere mucha instalación, apache necesita reiniciarse, y cuando finalmente lo tuve funcionando, me llevó mucho tiempo procesarlo (2-3 minutos por documento) y siempre devolvía 1
página en cada documento (no he visto un trabajo copia de Imagick hasta el momento), así que lo arrojé. Eso fue con los getNumberImages()
e identifyImage()
.
Usando FPDI (una biblioteca de PHP)
FPDI es fácil de usar e instalar (simplemente extrae archivos y llama a un script PHP), PERO muchas de las técnicas de compresión no son compatibles con FPDI. Luego devuelve un error:
Error de FPDF: este documento (test_1.pdf) probablemente utiliza una técnica de compresión que no es compatible con el analizador gratuito enviado con FPDI.
Abrir una secuencia y buscar con una expresión regular:
Esto abre el archivo PDF en una secuencia y busca algún tipo de cadena, que contenga el conteo de páginas o algo similar.
$f = "test1.pdf";
$stream = fopen($f, "r");
$content = fread ($stream, filesize($f));
if(!$stream || !$content)
return 0;
$count = 0;
// Regular Expressions found by Googling (all linked to SO answers):
$regex = "///Count/s+(/d+)/";
$regex2 = "///Page/W*(/d+)/";
$regex3 = "///N/s+(/d+)/";
if(preg_match_all($regex, $content, $matches))
$count = max($matches);
return $count;
-
///Count/s+(/d+)/
(busca/Count <number>
) no funciona porque solo unos pocos documentos tienen el parámetro/Count
inside, por lo que la mayoría de las veces no devuelve nada. Source. -
///Page/W*(/d+)/
(busca/Page<number>
) no obtiene el número de páginas, la mayoría contiene otros datos. Source. -
///N/s+(/d+)/
(busca/N <number>
) tampoco funciona, ya que los documentos pueden contener valores múltiples de/N
; la mayoría, si no todos, no contienen el conteo de páginas. Source.
Entonces, ¿qué funciona de manera confiable y precisa?
Ver la respuesta a continuación
Un simple ejecutable de línea de comando llamado: pdfinfo .
Se puede descargar para Linux y Windows . Usted descarga un archivo comprimido que contiene varios pequeños programas relacionados con PDF. Extraerlo en alguna parte.
Uno de esos archivos es pdfinfo (o pdfinfo.exe para Windows). Un ejemplo de datos devueltos al ejecutarlo en un documento PDF:
Title: test1.pdf
Author: John Smith
Creator: PScript5.dll Version 5.2.2
Producer: Acrobat Distiller 9.2.0 (Windows)
CreationDate: 01/09/13 19:46:57
ModDate: 01/09/13 19:46:57
Tagged: yes
Form: none
Pages: 13 <-- This is what we need
Encrypted: no
Page size: 2384 x 3370 pts (A0)
File size: 17569259 bytes
Optimized: yes
PDF version: 1.6
No he visto un documento PDF en el que se haya devuelto un número de página falso (todavía). También es muy rápido, incluso con documentos grandes de más de 200 MB, el tiempo de respuesta es de unos pocos segundos o menos.
Hay una manera fácil de extraer la cuenta de página de la salida, aquí en PHP:
// Make a function for convenience
function getPDFPages($document)
{
$cmd = "/path/to/pdfinfo"; // Linux
$cmd = "C://path//to//pdfinfo.exe"; // Windows
// Parse entire output
// Surround with double quotes if file name has spaces
exec("$cmd /"$document/"", $output);
// Iterate through lines
$pagecount = 0;
foreach($output as $op)
{
// Extract the number
if(preg_match("/Pages:/s*(/d+)/i", $op, $matches) === 1)
{
$pagecount = intval($matches[1]);
break;
}
}
return $pagecount;
}
// Use the function
echo getPDFPages("test 1.pdf"); // Output: 13
Por supuesto, esta herramienta de línea de comandos se puede usar en otros lenguajes que pueden analizar el resultado de un programa externo, pero yo lo uso en PHP.
Sé que no es puro PHP , pero los programas externos son mucho mejores en el manejo de PDF (como se ve en la pregunta).
Espero que esto pueda ayudar a las personas, porque he pasado mucho tiempo tratando de encontrar la solución a esto y he visto muchas preguntas sobre el número de páginas PDF en las que no encontré la respuesta que estaba buscando. Es por eso que hice esta pregunta y la respondí yo mismo.
Aquí hay un script de comando de Windows que usa gsscript e informa el número de página del archivo PDF
@echo off
echo.
rem
rem this file: getlastpagenumber.cmd
rem version 0.1 from commander 2015-11-03
rem need Ghostscript e.g. download and install from http://www.ghostscript.com/download/
rem Install path "C:/prg/ghostscript" for using the script without changes // and have less problems with UAC
rem
:vars
set __gs__="C:/prg/ghostscript/bin/gswin64c.exe"
set __lastpagenumber__=1
set __pdffile__="%~1"
set __pdffilename__="%~n1"
set __datetime__=%date%%time%
set __datetime__=%__datetime__:.=%
set __datetime__=%__datetime__::=%
set __datetime__=%__datetime__:,=%
set __datetime__=%__datetime__:/=%
set __datetime__=%__datetime__: =%
set __tmpfile__="%tmp%/%~n0_%__datetime__%.tmp"
:check
if %__pdffile__%=="" goto error1
if not exist %__pdffile__% goto error2
if not exist %__gs__% goto error3
:main
%__gs__% -dBATCH -dFirstPage=9999999 -dQUIET -dNODISPLAY -dNOPAUSE -sstdout=%__tmpfile__% %__pdffile__%
FOR /F " tokens=2,3* usebackq delims=:" %%A IN (`findstr /i "number" test.txt`) DO set __lastpagenumber__=%%A
set __lastpagenumber__=%__lastpagenumber__: =%
if exist %__tmpfile__% del %__tmpfile__%
:output
echo The PDF-File: %__pdffilename__% contains %__lastpagenumber__% pages
goto end
:error1
echo no pdf file selected
echo usage: %~n0 PDFFILE
goto end
:error2
echo no pdf file found
echo usage: %~n0 PDFFILE
goto end
:error3
echo.can not find the ghostscript bin file
echo. %__gs__%
echo.please download it from:
echo. http://www.ghostscript.com/download/
echo.and install to "C:/prg/ghostscript"
goto end
:end
exit /b
Aquí hay una función R
que informa el número de página del archivo PDF utilizando el comando pdfinfo
.
pdf.file.page.number <- function(fname) {
a <- pipe(paste("pdfinfo", fname, "| grep Pages | cut -d: -f2"))
page.number <- as.numeric(readLines(a))
close(a)
page.number
}
if (F) {
pdf.file.page.number("a.pdf")
}
El paquete R pdftools y la función pdf_info()
proporcionan información sobre el número de páginas en un pdf.
library(pdftools)
pdf_file <- file.path(R.home("doc"), "NEWS.pdf")
info <- pdf_info(pdf_file)
nbpages <- info[2]
nbpages
$pages
[1] 65
Esto parece funcionar bastante bien, sin la necesidad de paquetes especiales o resultados de comandos de análisis.
<?php
$target_pdf = "multi-page-test.pdf";
$cmd = sprintf("identify %s", $target_pdf);
exec($cmd, $output);
$pages = count($output);
Lo más simple de todo es usar ImageMagick
aquí hay un código de muestra
$image = new Imagick();
$image->pingImage(''myPdfFile.pdf'');
echo $image->getNumberImages();
de lo contrario, también puede usar bibliotecas de PDF
como MPDF
o TCPDF
para PHP
Si no puede instalar ningún paquete adicional, puede usar este sencillo delineador:
foundPages=$(strings < $PDF_FILE | sed -n ''s|.*Count -/{0,1/}/([0-9]/{1,/}/).*|/1|p'' | sort -rn | head -n 1)
Si tiene acceso a shell, el enfoque más simple (pero no utilizable en el 100% de los PDF) sería usar grep
.
Esto debería devolver solo el número de páginas:
grep -m 1 -aoP ''(?<=//N )/d+(?=//)'' file.pdf
Ejemplo: https://regex101.com/r/BrUTKn/1
Descripción de los interruptores:
-
-m 1
es necesario ya que algunos archivos pueden tener más de una coincidencia de patrón de expresión regular (se necesita un volonteer para reemplazar esto con la extensión de solución de expresiones regulares de solo coincidencia) -
-a
es necesario tratar el archivo binario como texto -
-o
para mostrar solo el partido -
-P
para usar la expresión regular de Perl
Explicación de Regex:
- comenzando "delimitador":
(?<=//N )
mira detrás de/N
(nb. carácter de espacio no se ve aquí) - resultado real:
/d+
cualquier cantidad de dígitos - terminando "delimiter":
(?=//)
lookahead de/
Nota bene: si en algún caso no se encuentra la coincidencia, es seguro suponer que solo existe 1 página.