Подтвердить что ты не робот

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

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

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

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

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

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

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

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

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

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

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

$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; большинство, если не все, не содержащие количество страниц. Источник.

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

Смотрите ответ ниже

4b9b3361

Ответ 1

Простой исполняемый файл командной строки: 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-документ, в котором он возвращал false 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-странице, в которых я не нашел ответ, который я искал, Вот почему я задал этот вопрос и сам ответил сам.

Ответ 2

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

вот пример кода

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

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

Ответ 3

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

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

Ответ 4

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

<?php                                                                               

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

Ответ 5

Если у вас есть доступ к оболочке, самым простым (но не используемым на 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+ любое количество цифр
  • end "delimiter": (?=\/) lookahead /

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

Ответ 6

Так как вы можете использовать утилиты командной строки, вы можете использовать cpdf (Microsoft Windows/Linux/Mac OS X). Чтобы получить количество страниц в одном PDF:

cpdf.exe -pages "my file.pdf"

Ответ 7

Вы можете использовать qpdf, как показано ниже. Если файл file_name.pdf содержит 100 страниц,

$ qpdf --show-npages file_name.pdf
100

Ответ 8

Вот функция 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")
}

Ответ 9

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

Ответ 10

Пакет 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