我正在使用
PyQt5.QWebEngineView
显示 pdf。目前,我正在使用 PDF.js
使用以下代码从 PDF 文档中的选定区域中提取文本坐标(基于此 question):
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QTextBrowser
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl, QTimer, QEventLoop
import os
class MyWebWidgetPdf(QWebEngineView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def contextMenuEvent(self, event):
position_action = QAction("Position", self)
position_action.triggered.connect(self.get_current_position)
self.menu = self.page().createStandardContextMenu()
self.menu.addAction(position_action)
self.menu.popup(event.globalPos())
def get_current_position(self):
js_script = """
var pageIndex = PDFViewerApplication.pdfViewer.currentPageNumber - 1;
var page = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
var pageRect = page.canvas.getClientRects()[0];
var selection = window.getSelection();
var selectionRects = selection.getRangeAt(0).getClientRects();
var selectionRectsArray = Array.from(selectionRects);
var selectedText = selection.toString();
var viewport = page.viewport;
var selected = selectionRectsArray.map(function (r) {
return viewport.convertToPdfPoint(r.left - pageRect.x, r.top - pageRect.y).concat(
viewport.convertToPdfPoint(r.right - pageRect.x, r.bottom - pageRect.y)
);
});
var result = {
page: pageIndex + 1,
coords: selected,
selectedText: selectedText
};
result;
"""
result = self.execJavaScript(js_script)
print(result)
def execJavaScript(self, script):
"""This function executes a javascript script and returns the result.
:param script: The script to execute.
:return: The result of the script."""
result = None # initialize the result
def callback(data):
"""This function is called when the script is executed.
:param data: The result of the script."""
nonlocal result # use the result variable of the parent function
result = data # set the result
loop.quit() # quit the event loop
loop = QEventLoop() # create an event loop
QTimer.singleShot(0, lambda: self.page().runJavaScript(script, callback)) # execute the script
loop.exec() # start the event loop
return result # return the result
class PDFViewer(QMainWindow):
def __init__(self):
super().__init__()
self.browser = QTextBrowser()
self.setCentralWidget(self.browser)
self.pdf_viewer = MyWebWidgetPdf()
self.setCentralWidget(self.pdf_viewer)
path = "/Users/user/Desktop/3._SprengV.pdf"
PDF = f'file:{os.path.abspath(path)}'
self.PDFJS = 'file:////Users/user/PycharmProjects/legalref/pdfjs-3/web/viewer.html'
self.pdf_viewer.load(QUrl.fromUserInput(f'{self.PDFJS}?file={PDF}'))
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
dialog = PDFViewer()
dialog.show()
sys.exit(app.exec_())
我遇到一个问题,X 值是正确的,但 Y 值始终偏离很多。我用
PyMuPdf
控制了 x 和 y 值。
原生 PDF 内容就像 Y 方向向上的图表一样。通常“原点”位于左下角。高度通常使用点大小单位,名义上为 1/72"。
所有这些都可以通过
/UserUnit
和 C
当前 M
矩阵变换更改为不同的“向上”,如“从右到左”(右读)甚至“颠倒”。
通常(默认)我们看到信纸页的 /MediaBox 的高度为 72 x 11 = 792 个单位,但它可以是任意数量的单位,并且在打印/显示时仍然为 11 英寸高。
因此,在渲染时,“屏幕”原点被假定为左上角。许多 PDF 应用程序以这些向下的单位工作,然后在写入过程中转换为相反的方向。
在同一工作区中使用多个应用程序时,这会导致问题。但是,通过从 /Media 高度中减去当前高度并调整当前用户标量和/或位置,可以轻松解决此问题。
因此,我们可能会将 4.5 英寸高的图像放置在半高处(5.5 英寸,因此它们可以是上方 1 英寸的空隙),因此我们可以计算出它需要位于 792 - 396 - 324 =
72 Down
。