71

这个问题是为了参考和比较。解决方案是以下公认的答案

我花了好几个小时寻找一种快速简单但大部分准确的方法来获取 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 ; 大多数(如果不是全部)包含页数。来源。

那么,什么工作可靠和准确呢?

请看下面的答案

4

15 回答 15

104

一个简单的命令行可执行文件名为:pdfinfo

可用于 Linux 和 Windows 下载。您下载了一个压缩文件,其中包含几个与 PDF 相关的小程序。在某处提取它。

其中一个文件是pdfinfo(或Windows 的pdfinfo.exe)。在 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 文档(还)。它也非常快,即使是 200+ MB 的大文档,响应时间也只有几秒钟或更短。

有一种从输出中提取 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 pagecount 的问题,但我没有找到我想要的答案。这就是我提出这个问题并自己回答的原因。

安全注意事项:如果文档名称来自用户输入或文件上传,则使用escapeshellargon 。$document

于 2013-02-01T10:33:13.213 回答
24

最简单的是使用ImageMagick

这是一个示例代码

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

否则你也可以使用PDF类似MPDFTCPDFfor 的库PHP

于 2015-12-30T15:29:17.180 回答
8

你可以qpdf像下面这样使用。如果文件 file_name.pdf 有 100 页,

$ qpdf --show-npages file_name.pdf
100
于 2019-08-19T19:26:33.530 回答
2

如果你不能安装任何额外的包,你可以使用这个简单的单行:

foundPages=$(strings < $PDF_FILE | sed -n 's|.*Count -\{0,1\}\([0-9]\{1,\}\).*|\1|p' | sort -rn | head -n 1)
于 2014-09-25T05:10:56.153 回答
2

由于您可以使用命令行实用程序,因此您可以使用 cpdf (Microsoft Windows/Linux/Mac OS X)。要获取一个 PDF 中的页数:

cpdf.exe -pages "my file.pdf"
于 2019-05-19T02:06:43.793 回答
2

根据理查德的回答@,我为 pdfinfo 创建了一个包装类,以防它对任何人都有用

/**
 * Wrapper for pdfinfo program, part of xpdf bundle
 * http://www.xpdfreader.com/about.html
 * 
 * this will put all pdfinfo output into keyed array, then make them accessible via getValue
 */
class PDFInfoWrapper {

    const PDFINFO_CMD = 'pdfinfo';

    /**
     * keyed array to hold all the info
     */
    protected $info = array();

    /**
     * raw output in case we need it
     */
    public $raw = "";

    /**
     * Constructor
     * @param string $filePath - path to file
     */
    public function __construct($filePath) {
        exec(self::PDFINFO_CMD . ' "' . $filePath . '"', $output);

        //loop each line and split into key and value
        foreach($output as $line) {
            $colon = strpos($line, ':');
            if($colon) {
                $key = trim(substr($line, 0, $colon));
                $val = trim(substr($line, $colon + 1));

                //use strtolower to make case insensitive
                $this->info[strtolower($key)] = $val;
            }
        }

        //store the raw output
        $this->raw = implode("\n", $output);

    }

    /**
     * get a value
     * @param string $key - key name, case insensitive
     * @returns string value
     */
    public function getValue($key) {
        return @$this->info[strtolower($key)];
    }

    /**
     * list all the keys
     * @returns array of key names
     */
    public function getAllKeys() {
        return array_keys($this->info);
    }

}
于 2020-02-06T09:30:52.320 回答
2

这是一个使用 PHP 获取 PDF 中页数的简单示例。

<?php

function count_pdf_pages($pdfname) {
  $pdftext = file_get_contents($pdfname);
  $num = preg_match_all("/\/Page\W/", $pdftext, $dummy);

  return $num;
}

$pdfname = 'example.pdf'; // Put your PDF path
$pages = count_pdf_pages($pdfname);

echo $pages;

?>
于 2020-10-27T13:38:47.820 回答
1

这似乎工作得很好,不需要特殊的包或解析命令输出。

<?php                                                                               

$target_pdf = "multi-page-test.pdf";                                                
$cmd = sprintf("identify %s", $target_pdf);                                         
exec($cmd, $output);                                                                
$pages = count($output);
于 2017-06-01T21:40:58.943 回答
1

这个简单的 1 班轮似乎做得很好:

strings $path_to_pdf | grep Kids | grep -o R | wc -l

PDF 文件中有一个块详细说明了这个时髦字符串中的页数:

/Kids [3 0 R 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R]

'R' 字符的数量是页数

显示字符串输出的终端屏幕截图

于 2021-08-22T21:45:42.283 回答
1

您可以使用mutool.

mutool show FILE.pdf trailer/Root/Pages/Count

mutoolMuPDF软件包的一部分。

于 2021-10-11T08:17:20.760 回答
0

这是一个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")
}
于 2015-08-13T19:41:54.570 回答
0

这是一个使用 gsscript 报告 PDF 文件页码的 Windows 命令脚本

@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
于 2015-11-03T00:17:06.233 回答
0

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
于 2017-01-18T22:03:31.223 回答
0

如果您可以访问 shell,最简单(但不能在 100% 的 PDF 上使用)的方法是使用grep.

这应该只返回页数:

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

示例:https ://regex101.com/r/BrUTKn/1

开关说明:

  • -m 1是必要的,因为某些文件可以有多个匹配的正则表达式模式(志愿者需要用仅匹配的正则表达式解决方案扩展替换它)
  • -a必须将二进制文件视为文本
  • -o只显示匹配
  • -P使用 Perl 正则表达式

正则表达式解释:

  • 开始“分隔符”:(?<=\/N )向后看/N(nb。此处未显示空格字符)
  • 实际结果:\d+任意位数
  • 结束“分隔符”:(?=\/)前瞻/

注意事项:如果在某些情况下未找到匹配项,则可以安全地假设仅存在 1 页。

于 2017-06-21T15:57:13.907 回答
-1

您经常阅读正则表达式/\/Page\W/,但它不适用于我的几个 pdf 文件。所以这是另一个对我有用的正则表达式。

$pdf = file_get_contents($path_pdf);
return preg_match_all("/[<|>][\r\n|\r|\n]*\/Type\s*\/Page\W/", $path_pdf, $dummy);
于 2021-12-31T09:09:17.097 回答