【问题标题】:Inconsistent page count of a PDF documentPDF 文档的页数不一致
【发布时间】:2018-05-16 20:12:37
【问题描述】:

我正在尝试获取 PDF 文档中的页数。我的一些 PDF 是在 Word 中创建的(另存为 PDF),其中一些是复印到目录中的(不确定这是否重要)。

经过数小时的研究,我发现这说起来容易做起来难。 页数很少返回给我正确的页数,尽管事实上大多数 PDF 的二进制代码中确实有 /Count

例如,我使用了以下代码;它应该以二进制模式打开文档,查找 /Count/N 并获取它旁边的数字,这应该给我页数。

Public Sub pagecount(sfilename As String)
    On Error GoTo a
    Dim nFileNum As Integer
    Dim s As String
    Dim c As Integer
    Dim pos, pos1 As Integer
    pos = 0
    pos1 = 0
    c = 0
    ' Get an available file number from the system
    nFileNum = FreeFile
    'OPEN the PDF file in Binary mode
    Open sfilename For Binary Lock Read Write As #nFileNum
    ' Get the data from the file
    Do Until EOF(nFileNum)
    Input #1, s
    c = c + 1
    If c <= 10 Then
        pos = InStr(s, "/N")
    End If
    pos1 = InStr(s, "/count")
       If pos > 0 Or pos1 > 0 Then
            Close #nFileNum
            s = Trim(Mid(s, pos, 10))
            s = Replace(s, "/N", "")
            s = Replace(s, "/count", "")
            s = Replace(s, " ", "")
            s = Replace(s, "/", "")
            For i = 65 To 125
                    s = Replace(s, Chr(i), "")
            Next
            pages = Val(Trim(s))
            If pages < 0 Then
                pages = 1
            End If
            Close #nFileNum
            Exit Sub
        End If
        'imp only 1000 lines searches
        If c >= 1000 Then
             GoTo a
        End If
     Loop
       Close #nFileNum
       Exit Sub
   a:
       Close #nFileNum
       pages = 1
       Exit Sub
End Sub

但是,大多数情况下,它默认为 pages = 1(在 a: 下)。 我也将它更新为 10000 以确保它到达 /Count 行,但它仍然没有给我正确的计数。

If c >= 10000 Then
         GoTo a
End If

我也遇到过这个reddit

还有其他方法可以做到这一点,我可以在我的应用程序中使用吗?

非常感谢任何帮助。


背景:

这适用于我试图让用户操作 PDF 文件的旧版 vb6 应用程序。我添加了一个 ListBox,用于显示特定目录中的所有 PDF 文档。当用户双击任何一个文件时,我会将其显示在我的应用程序内的 WebBrowser 组件中。

编辑:包含 3 个不同文档的 BinaryMode 行计数的图像:

我仔细检查了页数,/Count 显示了三个文档中每一个的正确页数。

【问题讨论】:

  • 除非您的 PDF 是由同一个生成器创建的,否则您无法在不遵守 pdf 结构的情况下确定正确的页码,即从文件背面解析文件,定位 Pages 通过文件尾部和交叉引用创建树,并分析该根对象。

标签: pdf vb6


【解决方案1】:

正则表达式有限制,但我更喜欢用它们来搜索字符串,我认为这是一个使用它的好地方。您可能想要使用该模式,因为我只进行了少量测试就相对较快地完成了此操作。

在您的项目中添加对 Microsoft VBScript 正则表达式 5.5 的引用。然后你可以试试下面的示例代码。

Private Sub Command1_Click()
    Dim oRegEx As RegExp
    Dim fHndl As Integer
    Dim sContents As String
    Dim oMatches As MatchCollection

    On Error GoTo ErrCommand1_Click

    'Open and read in the file
    fHndl = FreeFile
    Open some pdf file For Binary Access Read As fHndl
    sContents = String(LOF(fHndl), vbNull)
    Get #fHndl, 1, sContents
    Close #fHndl    'We have the file contents so close it
    fHndl = 0

    'Instantiate and configure the RegEx
    Set oRegEx = New RegExp
    oRegEx.Global = True
    oRegEx.Pattern = "((?:/Count )(\d+))"
    Set oMatches = oRegEx.Execute(sContents)

    'Look for a match
    If oMatches.Count > 0 Then
       If oMatches(0).SubMatches.Count > 0 Then
           MsgBox CStr(oMatches(0).SubMatches(0)) & " Pages"
       End If
    End If

    Exit Sub

ErrCommand1_Click:
    Debug.Print "Error: " & CStr(Err.Number) & ", " & Err.Description
    If Not oRegEx Is Nothing Then Set oRegEx = Nothing
    If Not oMatches Is Nothing Then Set oMatches = Nothing

End Sub

RegEx 模式的解释:
() 创建一个组
括号内的?: 使组不被捕获
&lt;&lt;/Linearized 是一个文字字符串
.*贪婪限定符,匹配任意字符 0 次或多次
/N 文字字符串
\d+ 贪婪限定符,匹配数字 1 次或多次
&gt;&gt; 文字字符串

【讨论】:

  • 并非每个 pdf 都是线性化的。并不是每个带有 Linearized 字典的 pdf 仍然是线性化的。因此,如果 pdf 来自某个同类来源,您的选择可能会有所帮助,但对于通用 pdf,它往往会失败。
  • 我尝试了 3 个不同的文档,但没有得到其中任何一个的页码
  • @mkl 我在 notepad++ 中打开了手头的 pdf 文档,并从中开发了正则表达式模式。该技术有效,但可能需要调整模式,或者甚至尝试 2 个或更多模式,直到找到匹配项。你有更通用的模式吗?关键是匹配行与页码。
  • @jac 由于 PDF 格式的性质,有很多方法可以对页数进行编码,包括一些您找到文字字符串的位置仅包含对 PDF 中其他位置的引用的方法检索值。实际上,您不能希望所有 PDF 都有一个通用模式。另一方面,如果您的 PDF 生成器数量有限,那么找到一些模式来从他们的创作中提取页数是可行的。 (除非使用压缩对象流,即...)
  • @Koosh 如果您只需要处理来自单个 PDF 生成器(或其中极少数)的 PDF,您可能希望分享 jac 或其他人可以派生页码提取功能的示例。
猜你喜欢
  • 1970-01-01
  • 2015-04-19
  • 2019-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
相关资源
最近更新 更多