Pobierz liczbę stron w dokumencie PDF

to pytanie jest do odwołania i porównania. Rozwiązaniem jest zaakceptowana odpowiedź poniżej .

Wiele godzin Szukałem szybkiego i łatwego, ale przede wszystkim dokładnego , sposobu na uzyskanie liczby stron w dokumencie PDF. Ponieważ pracuję dla firmy zajmującej się drukowaniem i reprodukcją grafiki, która dużo pracuje z plikami PDF, liczba stron w dokumencie musi być dokładnie znana, zanim zostaną przetworzone. Dokumenty PDF pochodzą od wielu różnych klientów, więc nie są generowane przy użyciu tej samej aplikacji i / lub nie używają tej samej metody kompresji.

Oto kilka odpowiedzi, które znalazłem niewystarczająca lub po prostu nie działa:

Using Imagick (A PHP extension)

Imagick wymaga dużo instalacji, Apache musi się zrestartować, a kiedy w końcu go uruchomiłem, przetwarzanie trwało niesamowicie długo (2-3 minuty na dokument) i zawsze zwracało 1 stronę w każdym dokument (do tej pory nie widziałem roboczej kopii Imagicka), więc go wyrzuciłem. Było to zarówno metodą getNumberImages(), jak i identifyImage().

Using FPDI (A PHP library)

FPDI jest łatwy w użyciu i instalacji (wystarczy rozpakować pliki i wywołać skrypt PHP), ale wiele technik kompresji nie jest wspieranych przez FPDI. Następnie zwraca błąd:

Błąd FPDF: ten dokument (test_1.pdf) prawdopodobnie wykorzystuje technikę kompresji, która nie jest obsługiwana przez darmowy parser dostarczany z FPDI.

Otwieranie strumienia i wyszukiwanie za pomocą wyrażenia regularnego:

Otwiera plik PDF w strumieniu i wyszukuje jakiś łańcuch zawierający liczbę stron lub coś podobnego.

$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+)/ (szuka /Count <number>) nie działa, ponieważ tylko kilka dokumentów ma parametr /Count w środku, więc przez większość czasu nic nie zwraca. źródło.
  • /\/Page\W*(\d+)/ (szuka /Page<number>) nie dostaje liczba stron, w większości zawiera inne dane. Źródło.
  • /\/N\s+(\d+)/ (szuka /N <number>) również nie działa, ponieważ dokumenty mogą zawierać wiele wartości /N; większość, jeśli nie wszystkie, Nie zawiera liczbę stron. źródło.

Więc, co działa niezawodne i dokładne?

Zobacz odpowiedź poniżej

 52
Author: Community, 2013-02-01

8 answers

Prosty program wykonywalny z linii poleceń o nazwie: pdfinfo .

Jest to do pobrania dla Linuksa i Windows. Pobierasz skompresowany plik zawierający kilka małych programów związanych z plikami PDF. Wyciągnij to gdzieś.

Jednym z tych plików jest pdfinfo (lub pdfinfo.exe Dla Windows). Przykład danych zwracanych przez uruchomienie ich na dokumencie 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

Nie widziałem dokumentu PDF, w którym zwrócił fałszywą liczbę stron (jeszcze). Jest to również naprawdę szybki, nawet przy dużych dokumentach 200 + MB czas reakcji wynosi zaledwie kilka sekund lub mniej.

Istnieje łatwy sposób na wyodrębnienie liczby stron z wyjścia, tutaj w 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

Oczywiście to narzędzie wiersza poleceń może być używane w innych językach, które mogą analizować wyjście z zewnętrznego programu, ale używam go w PHP.

Wiem, że nie jest to czysty PHP , ale zewnętrzne programy są sposób lepiej w obsłudze PDF (jak widać w pytaniu).

Mam nadzieję, że to może pomagaj ludziom, ponieważ spędziłem dużo czasu próbując znaleźć rozwiązanie tego problemu i widziałem wiele pytań dotyczących PDF pagecount, w których nie znalazłem odpowiedzi, której szukałem. Dlatego zadałem to pytanie i sam na nie odpowiedziałem.

 75
Author: Richard de Wit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-02 13:23:49

Najprostszym ze wszystkich jest użycie ImageMagick

Oto przykładowy kod

$image = new Imagick();
$image->pingImage('myPdfFile.pdf');
echo $image->getNumberImages();

W przeciwnym razie możesz również użyć PDF bibliotek, takich jak MPDF lub TCPDF dla PHP

 11
Author: Kuldeep Dangi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-11 05:31:44

Jeśli masz dostęp do powłoki, najprostszym (ale nie używalnym na 100% plików PDF) podejściem byłoby użycie grep.

To powinno zwracać tylko liczbę stron:

grep -m 1 -aoP '(?<=\/N )\d+(?=\/)' file.pdf

Przykład: https://regex101.com/r/BrUTKn/1

Opis przełączników:

  • Jest to konieczne, ponieważ niektóre pliki mogą mieć więcej niż jedno dopasowanie wzorca regex (volonteer musiał zastąpić to rozszerzeniem rozwiązania regex tylko dla pierwszego dopasowania)
  • -a jest należy traktować plik binarny jako tekst
  • -o aby pokazać tylko mecz
  • -P aby użyć wyrażenia regularnego Perla

Wyjaśnienie Regex:

  • start "delimiter": (?<=\/N ) lookbehind of /N (nb. space character not seen here)
  • rzeczywisty wynik: \d+ dowolna liczba cyfr
  • ending "delimiter": (?=\/) lookahead of /

Nota bene: jeśli w jakimś przypadku dopasowanie nie zostanie znalezione, można założyć tylko 1 stronę istnieje.

 1
Author: Saran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-21 16:06:16

Jeśli nie możesz zainstalować żadnych dodatkowych pakietów, możesz użyć tego prostego jednowiersza:

foundPages=$(strings < $PDF_FILE | sed -n 's|.*Count -\{0,1\}\([0-9]\{1,\}\).*|\1|p' | sort -rn | head -n 1)
 0
Author: Muad'Dib,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-25 05:10:56

Oto funkcja R, która zgłasza numer strony pliku PDF za pomocą polecenia 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")
}
 0
Author: Feiming Chen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-13 19:41:54

Oto skrypt poleceń systemu Windows wykorzystujący gsscript, który zgłasza numer strony pliku 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
 0
Author: commander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 00:17:06

Pakiet R pdftools i funkcja pdf_info() dostarczają informacji o liczbie stron w pliku pdf.

library(pdftools)
pdf_file <- file.path(R.home("doc"), "NEWS.pdf")
info <- pdf_info(pdf_file)
nbpages <- info[2]
nbpages

$pages
[1] 65
 0
Author: emeryville,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-18 22:03:31

Wygląda na to, że działa to całkiem dobrze, bez potrzeby stosowania specjalnych pakietów lub analizowania wyjścia poleceń.

<?php                                                                               

$target_pdf = "multi-page-test.pdf";                                                
$cmd = sprintf("identify %s", $target_pdf);                                         
exec($cmd, $output);                                                                
$pages = count($output);
 0
Author: dhildreth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-01 21:40:58