65.9K
CodeProject 正在变化。 阅读更多。
Home

gbCapture - 提取受保护的文档内容

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2023年3月21日

CPOL

5分钟阅读

viewsIcon

7393

以文本形式捕获受保护的文档内容,无需破解 DRM

对于简单的捕获,gbCapture 以“迷你”模式运行,如下图所示

为了评估 gbCapture 的所有设置,选择性地提取页面,查看提取的文本/图像的详细信息,以及更全面地了解 gbCapture 的工作原理,还支持以下用户界面。

引言

我与低视力用户合作——特别是患有黄斑变性的人。他们视力下降对他们来说是一个巨大的打击,很大一部分原因是这阻止了他们阅读书籍,比如他们从亚马逊购买的书籍。Kindle 应用等原生图书阅读应用不允许低视力用户调整图书内容的显示方式,至少达不到低视力用户所要求的程度。我的一个产品叫做 EZReader,它允许低视力用户重新格式化书籍,以便他们能更好地看到内容,并能朗读内容。但是,EZReader 只处理文本内容,因此需要将 Kindle 书籍转换为文本,才能在 EZReader 中显示图书。

因此,本文的目的是演示一种直接的技术,用于将受保护的文档(如 DRM 保护的 Kindle 图书)转换为文本。我称该实用程序为 gbCapture,其界面设计使得即使是低视力用户也能成功地将其 DRM 保护的书籍转换为文本,以便导入 EZReader 或由其他转换应用程序转换为其他格式。

将 DRM 保护的书籍转换为其他格式的最知名且免费的解决方案之一是 Calibre。与其他可用解决方案一样,它需要使用 DeDRM 扩展。对于 Kindle 图书,它还需要使用早期版本的 Kindle 应用下载书籍,这种版本会以前台支持的格式下载书籍。

使用 gbCapture,文本是通过在其原生查看器(例如任何版本的 Kindle 应用)中查看书籍,拍摄文档的每一页,然后使用 OCR(tesseract)提取文本来提取的。gbCapture 自动化了这一过程,一次捕获一页,然后翻到原生查看器中的下一页,直到文档结束。当捕获完最后一页后,提取的文本将被合并成一个单一的文本文件。

文章正文

gbCapture 使用 PowerBASIC 语言编写,其直接访问 Win32 API 的能力特别方便地扩展了 PowerBASIC 语句。gbCapture 大量使用了 Win32 API。

我们将逐一介绍 gbCapture 的基本操作,然后重点介绍几个区域并提供更关键的 gbCapture 过程的代码示例。我将使用 Kindle 应用进行讨论,但 gbCapture 也可以用于其他显示文档的应用程序(Word、WordPad、NotePad 等)。

要开始图书捕获,请打开 Kindle 应用以显示一本书。该应用应放置在桌面的中心,并调整大小以确保要捕获的页面在文本周围有边距。gbCapture 会自动检测覆盖桌面中心的应用程序。它还会检测应用程序内包含显示文本的窗口。

gbCapture 以“迷你”模式打开并放置在 Kindle 应用旁边,只需按下 gbCapture 工具栏上的 **Capture** 即可。gbCapture 将拍摄当前查看页面的快照,提取文本,翻页,然后重复此过程直到到达书的末尾。“书的末尾”由连续两次捕获返回相同文本来确定。

这是 gbCapture 提供的一张图像,以向用户确认包含文本的窗口已被识别。

按下 **Capture** 后,gbCapture 开始自动捕获/提取文本/翻页过程。gbCapture 的状态栏将显示进度。当到达书的末尾时,捕获将自动停止。用户可以随时手动停止捕获。

关键代码段

大部分代码非常直接,不需要深入讨论。但是,我选择了一些过程进行进一步讨论。包含文本的窗口是使用相应的 Win32 API 找到的。

Sub GetHandles
   Local pt As Point
   Desktop Get Client To pt.x, pt.y
   pt.x = pt.x/2 : pt.y = pt.y/2
   hCenterWindow = WindowFromPoint(pt)
   hCenterApp    = GetParent(hCenterWindow)
End Sub 

gbCapture 提供了两种捕获文本图像的方法——一种是通过仅捕获容器窗口,另一种是通过捕获整个桌面然后提取容器窗口。以下是捕获容器窗口的代码。并非所有查看应用程序都能响应这两种方法,因此 gbCapture 允许用户选择使用哪种方法。PowerBASIC 提供了许多“Graphic”语句,可以更轻松地处理图像。特别是,“Graphic Bitmap”语句是 PowerBASIC 的一个语句,用于创建一个内存中的位图结构,该结构被用于以下捕获代码。

Sub CapturePageImage_Window
   'Capture Image to ImgName
   Local hPageDC, hBMP, hBMPDC As Dword, w,h As Long

   GetWindowRect hCenterWindow, rcCenter
   hPageDC = GetDC(hCenterWindow)

   w = rcCenter.Right - rcCenter.Left
   h = rcCenter.Bottom - rcCenter.Top

   Graphic Bitmap New w,h To hBMP
   Graphic Attach hBMP, 0
   Graphic Get DC To hBMPDC

   BitBlt hBMPDC, 0, 0, w, h, hPageDC, 0, 0, %SRCCopy
   ReleaseDC %Null, hPageDC

   Graphic Save ImgName
   Graphic Bitmap End
   Statusbar Set Text hDlg, %IDC_Statusbar, 1,0, " Image: " + PathName$(Namex,ImgName)
End Sub 

捕获页面图像后,使用 tesseract OCR 库来提取文本。完成页面图像捕获和提取文本所需的时间取决于用户的 PC 能力,但通常每页捕获可能需要最多 1 秒。这意味着一本 600 页的书将花费约 10 分钟——比其他可用工具慢得多,但仍然不需要移除文档的 DRM 保护。

Sub ExtractTextFromImage
   Local ExtractedText$
   'extract and clean the text using Tesseract
   Shell ($Tesseract + " --psm " + IIf$(MultiColumn,"4 ","1 ") + _
   ImgName + " " + PathName$(Path,TextName) + _
   PathName$(Name,TextName), 0) 'wait for it to finish
   Statusbar Set Text hDlg, %IDC_Statusbar, 1,0, " Text: " + PathName$(Namex,TextName)
   Open TextName For Binary As #1 : Get$ #1, Lof(1), _
   ExtractedText$ : Close #1 'get extracted text
   CleanText(ExtractedText$)
   If LastText$ = ExtractedText Then 'end of document
      If IsFile(ImgName)  Then Kill ImgName
      If IsFile(TextName) Then Kill TextName
      StopCapture = 1
      Exit Sub
   Else
      LastText$ = ExtractedText$        'for comparison, to know when stop
   End If
   Open TextName For Output As #1 : Print #1, _
   ExtractedText$; : Close #1           'save cleaned, but not formatted, 
                                        'extracted text
   'append the extracted text to $Document
   Open $Document For Append As #1
   If AutoParagraphFormatting Then ParagraphFormatting(ExtractedText$)
   Print #1, $CrLf + ExtractedText$ + IIf$(UsePageNumbers, _
             $CrLf + "Page: " + Str$(ActionCount) + $CrLf, "") ;
   Close #1
   Statusbar Set Text hDlg, %IDC_Statusbar, 1,0, " Text: " + PathName$(Namex,TextName)
End Sub 

当前页面被捕获并提取文本后,通过将焦点设置到应用程序并将“Page Down”按键发送到中心应用程序,就可以向查看页面发送“Next Page”命令。按键按下和按键释放都会发送到中心应用程序。

Sub NextPage
   SetFocus hCenterApp
   SetForeGroundWindow hCenterApp
   keybd_event(%VK_NEXT, 0, 0, 0)
   keybd_event(%VK_NEXT, 0, %KEYEVENTF_KEYUP, 0)
End Sub 

结论和关注点

对于从文档中捕获文本,gbCapture 提供了一种替代现有解决方案的方法。特别是,它可以在不启用文档编辑、不破坏文档 DRM 保护或不使用特定版本的原生文件查看器的情况下,从受保护的文档中提取文本。获得文本后,用户可以转向其他转换应用程序来创建其他格式的文档。

历史

  • 2023 年 3 月 20 日:初始版本
© . All rights reserved.