Получить количество страниц в документе PDF

Этот вопрос предназначен для ссылок и сравнения. Решение является принятым ответом ниже .

Много часов я искал быстрый и легкий, но в основном точный способ получить количество страниц в PDF-документе. Поскольку я работаю для графической компании по печати и размножению, которая много работает с PDF-файлами, количество страниц в документе должно быть точно известно до того, как они будут обработаны. PDF-документы поступают из разных клиентов, поэтому они не генерируются с одним и тем же приложением и / или не используют один и тот же метод сжатия.

Вот некоторые из ответов, которые я нашел недостаточными или просто НЕ работают :

Использование Imagick (расширение PHP)

Imagick требует много инсталляции, apache необходимо перезапустить, и, когда я наконец-то его работал, потребовалось очень много времени для обработки (2-3 минуты на документ), и он всегда возвращал 1 страницу в каждом документе (не видел рабочего копия Imagick до сих пор), поэтому я выбросил ее. Это было как с getNumberImages() и getNumberImages() .

Использование FPDI (библиотека PHP)

FPDI прост в использовании и установке (просто извлеките файлы и вызовите скрипт PHP), но многие из методов сжатия не поддерживаются FPDI. Затем он возвращает ошибку:

Ошибка FPDF: этот документ (test_1.pdf), вероятно, использует метод сжатия, который не поддерживается свободным парсером, поставляемым с FPDI.

Открытие потока и поиск с регулярным выражением:

Это открывает PDF-файл в потоке и ищет какую-то строку, содержащую pagecount или что-то подобное.

 $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+)/ (ищет /Count <number> ) не работает, потому что только несколько документов имеют параметр /Count внутри, поэтому большую часть времени он ничего не возвращает. Источник.
  • /\/Page\W*(\d+)/ (ищет /Page<number> ) не получает количество страниц, в основном содержит некоторые другие данные. Источник.
  • /\/N\s+(\d+)/ (ищет /N <number> ) тоже не работает, так как документы могут содержать несколько значений /N ; большинство, если не все, не содержащие pagecount. Источник.

Итак, что работает надежным и точным?

См. Ответ ниже

Простой исполняемый файл командной строки: pdfinfo .

Он загружается для Linux и Windows . Вы загружаете сжатый файл, содержащий несколько небольших программ, связанных с PDF. Извлеките его где-нибудь.

Один из этих файлов – pdfinfo (или pdfinfo.exe для Windows). Пример данных, возвращаемых при запуске в 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 

Я не видел документа PDF, где он возвращал ложную pagecount (пока). Это также очень быстро, даже с большими документами в 200+ Мб время ответа составляет всего несколько секунд или меньше.

Существует простой способ извлечения pagecount из вывода, здесь, в 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 

Конечно, этот инструмент командной строки может использоваться на других языках, которые могут анализировать выходные данные из внешней программы, но я использую его в PHP.

Я знаю его не чистый PHP , но внешние программы лучше подходят для обработки PDF (как видно из вопроса).

Надеюсь, это поможет людям, потому что я потратил много времени на то, чтобы найти решение этого вопроса, и я видел много вопросов о PDF-странице, в которых я не нашел ответ, который я искал. Вот почему я задал этот вопрос и сам ответил сам.

Самый простой из всех – использование ImageMagick

здесь приведен пример кода

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

в противном случае вы также можете использовать библиотеки PDF такие как MPDF или TCPDF для PHP

если вы не можете установить дополнительные пакеты, вы можете использовать этот простой однострочный:

 foundPages=$(strings < $PDF_FILE | sed -n 's|.*Count -\{0,1\}\([0-9]\{1,\}\).*|\1|p' | sort -rn | head -n 1) 

Вот функция R которая сообщает номер страницы файла PDF, используя команду 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") } 

Вот сценарий командной строки Windows с использованием gsscript, который сообщает номер страницы файла PDF

 @echo off echo. rem rem this file: getlastpagenumber.cmd rem version 0.1 from commander 2015-11-03 rem need Ghostscript eg 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 

R pdftools и функция pdf_info() предоставляют информацию о количестве страниц в pdf.

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

Это, похоже, работает очень хорошо, без необходимости специальных пакетов или синтаксического анализа команды.

 <?php $target_pdf = "multi-page-test.pdf"; $cmd = sprintf("identify %s", $target_pdf); exec($cmd, $output); $pages = count($output); 

Если у вас есть доступ к оболочке, самым простым (но не используемым для 100% PDF-файлов) подходом будет использование grep .

Это должно возвращать только количество страниц:

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

Пример: https://regex101.com/r/BrUTKn/1

Описание переключателей:

  • -m 1 необходимо, так как некоторые файлы могут иметь более одного соответствия шаблону регулярного выражения (volonteer необходимо заменить на это расширение для решения только для соответствия только регулярному выражению)
  • -a необходимо обрабатывать двоичный файл как текст
  • -o показать только совпадение
  • -P использовать регулярное выражение Perl

Объяснение Regex:

  • начальный «разделитель»: (?<=\/N ) lookbehind of /N (символ пробела, который здесь не встречается)
  • фактический результат: \d+ любое количество цифр
  • конечный «разделитель»: (?=\/) просмотр /

Nota bene: если в некотором случае совпадение не найдено, можно предположить, что существует только одна страница.