【问题标题】:Excel VBA to return Page Count from protected PDF fileExcel VBA 从受保护的 PDF 文件返回页数
【发布时间】:2018-01-28 09:22:59
【问题描述】:

我需要使用 Excel VBA 检索 PDF 文件中的 页数(具有安全性)。

以下代码在 PDF 文件中没有启用安全性时有效:

Sub PDFandNumPages()

   Dim Folder As Object
   Dim file As Object
   Dim fso As Object
   Dim iExtLen As Integer, iRow As Integer
   Dim sFolder As String, sExt As String
   Dim sPDFName As String

   sExt = "pdf"
   iExtLen = Len(sExt)
   iRow = 1
   ' Must have a '\' at the end of path
   sFolder = "C:\test\"

   Set fso = CreateObject("Scripting.FileSystemObject")

   If sFolder <> "" Then
      Set Folder = fso.GetFolder(sFolder)
      For Each file In Folder.Files
         If Right(file, iExtLen) = sExt Then
            Cells(iRow, 1).Value = file.Name
            Cells(iRow, 2).Value = pageCount(sFolder & file.Name)
            iRow = iRow + 1
         End If
      Next file
   End If

End Sub

但是,如果启用了任何类型的安全性,则代码无法提取页码并返回零页。

注意:打开这些 PDF 文件没有密码保护,它仅启用了一些安全功能以防止 修改 PDF。

启用安全的示例 PDF 可在以下 Google Drive 链接上找到:Google Drive PDF with security

我的要求是调整代码,以便显示 PDF 文件中的页码,无论是否有任何安全性。

对于 Python,我在 this page 找到了类似的问题和解决方案,但是它使用 Python 库。如果可能的话,我希望 VBA 方面的专家建议我如何在 VBA 中复制它

【问题讨论】:

  • 文档是否有“权限密码”?
  • 不,它没有任何密码。您还可以访问我在 google drive 上上传的文件以查看它们
  • 好的——见下面我的回答。您可能需要 Adob​​e Acrobat 的“完整版”(不是“阅读器”)
  • 我的要求是找到一堆PDF文件的页码,就像你打开一个文件一样,看看有多少页。我不想手动打开每个受保护的 PDF 文件并更改 PDF 中的任何设置。即使要更改任何设置,我也希望通过代码以自动方式完成。注意:我不想提取任何页面,只想要文件的总页数。
  • 我明白了。 “extract”这个词把我吓跑了。那么在那种情况下......

标签: vba excel pdf text-extraction


【解决方案1】:

如果 PDF 文档没有设置权限密码(或者如果您知道密码),您可以修改文档限制,例如页面提取。

  • 使用专有或第 3 方编辑器手动打开文档
  • FileProperties
  • Security 选项卡中,选择Show Details…

  • 要更改 PDF 的限制,请转到查看 → 工具 → 保护
  • 工具窗格中,单击Encrypt,然后在Protection部分中,选择Remove Security
  • 如果有权限密码,您需要在此处输入。

权限现在将更改为“允许”

(Source)


“Hacky”方法:

如果上述方法对您不起作用,则有一种解决方法可以解决问题。您不会解锁文件本身,但您可以生成一个解锁的等价物,可以根据您的喜好对其进行编辑和操作。

  • Adobe Acrobat Reader中打开要解锁的文档
  • 单击File,然后单击Print
  • 打印机列表中,选择"Microsoft XPS Document Writer",然后单击打印

如果您尝试使用 Adob​​e 的 PDF 打印机驱动程序,它会检测到您正在尝试将受保护的 PDF 导出为新文件,并且会拒绝继续。即使是第三方 PDF 打印驱动程序也倾向于阻塞此类文件。

但是,通过使用 XPS 文档编写器,您可以有效地完全绕过该检查,留下XPS 输出。

  • 打开您刚刚创建的新XPS 文件并简单地重复打印过程,仅这次打印为 PDF 格式

如果您的打印机列表中没有可供选择的 PDF 打印机,可以在线选择各种免费软件选项(例如 CutePDF Writer),这些选项可让您设置生成 PDF 的虚拟打印机。 (Source)


编辑(替代答案)

返回 PDF 文件的页数

要在 VBA 中查找 PDF 文件中的总页数,您可以将其作为二进制文件打开,然后解析文件以查找“/Count”,然后读取数字接下来。

以下是适用于您的示例文件(6 页和 8 页)的示例,但可能需要“调整”,具体取决于手头各个 PDF 文件的结构。

(在某些情况下,您最好计算/Page”或“/Pages”标签的单独出现次数,尽管该数字可能需要减少 1或2。)

请注意,这不是一种非常有效的二进制文件解析方式,因此解析大文件可能需要一段时间。

Sub Get_PDF_Page_Count()
'scrape PDF file as binary, looking for "/Count" tag, then return the number following it
    Const fName = "C:\your_path_here\1121-151134311859-64.pdf"
    Dim bytTemp As Byte, fileStr As String, c As Long, p1 As Long, p2 As Long

    'open PDF as binary file
    Debug.Print "Reading File '" & fName & "'";
    Open fName For Binary Access Read As #1

    'read file into string
    Do While Not EOF(1)

        'parse PDF file, one byte at a time
        Get #1, , bytTemp
        c = c + 1
        fileStr = fileStr & Chr(bytTemp)

        'check every 20000 characters, if the tag was found yet
        If c / 20000 = c \ 20000 Then
            If InStr(fileStr, "/Count") > 0 Then Exit Do
            ' not found yet, keep going
            Debug.Print ".";
            DoEvents
        End If
    Loop

    'close file
    Close #1
    Debug.Print

    'check if tag was found
    If InStr(fileStr, "/Count") = 0 Then
        Debug.Print "'/Count' tag not found in file: " & fName
        Exit Sub
    End If

    'return page count
    p1 = InStr(fileStr, "/Count")
    p1 = InStr(p1, fileStr, " ") + 1
    p2 = InStr(p1, fileStr, vbLf)
    Beep
    Debug.Print Val(Mid(fileStr, p1, p2 - p1)) & " pages in file: " & fName

End Sub

【讨论】:

  • 我在单个文件上运行了代码,但即使在 5 分钟后它仍然循环运行。当我中断正在运行的代码时,我看到它卡在 If c/20000 块中。您在 google 驱动器文件上运行代码并获得结果需要多长时间?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-03
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多