如何从QPdfDocument提取页面不转QImage?解决PDF合并后无法搜索问题
问题:合并PDF时保留可搜索文本(Qt环境)
我需要将多个PDF文档合并为一个,这样无需逐个文档搜索特定内容。我使用Qt Creator作为开发环境,希望通过Qt解决该问题。我已编写部分代码,但采用了QPdfDocument::render函数,该函数仅输出图片并复制到合并后的PDF中,导致合并后的PDF无法搜索文字。
原代码
void mergePDFs(const QStringList& fileList, const QString& outputFileName) { QPdfWriter pdfWriter(outputFileName); pdfWriter.setResolution(150); QPdfDocument firstFilePDF; firstFilePDF.load(fileList.first()); QPageSize pageSize = QPageSize(firstFilePDF.pagePointSize(1).toSize()); pdfWriter.setPageSize(pageSize); firstFilePDF.close(); QPainter painter(&pdfWriter); foreach(const QString& file, fileList) { QPdfDocument pdfDocument; pdfDocument.load(file); for(int i = 0; i < pdfDocument.pageCount(); i++) { QPdfDocumentRenderOptions renderOptions = QPdfDocumentRenderOptions(); renderOptions.setRenderFlags(QPdfDocumentRenderOptions::RenderFlag::Annotations); QPageSize pageSize = QPageSize(pdfDocument.pagePointSize(i).toSize()); pdfWriter.setPageSize(pageSize); QSize scaledSize = pdfDocument.pagePointSize(i).toSize()*=(2); QImage image = pdfDocument.render(i, scaledSize); painter.drawImage(QPoint(0, 0), image); pdfWriter.newPage(); } pdfDocument.close(); } painter.end(); } int main(int argc, char *argv[]) { QApplication app(argc, argv); QMessageBox selectFilesMsg; selectFilesMsg.setText("Please select your files"); selectFilesMsg.exec(); QStringList files; QFileDialog dialog = QFileDialog(); dialog.setFileMode(QFileDialog::ExistingFiles); dialog.setNameFilter("PDF Files (*.pdf)"); if (dialog.exec()) { files = dialog.selectedFiles(); if (files.isEmpty()) { QMessageBox emptyFile; emptyFile.setText("The file you wanted to open is empty"); emptyFile.exec(); return 0; } } else { QMessageBox canceledMsg; canceledMsg.setText("The process has been canceled by the user"); canceledMsg.exec(); return 0; } QString outputFileName = QFileDialog::getSaveFileName(nullptr, "Save Merged PDF", QDir::homePath(), "PDF Files (*.pdf)"); if (outputFileName.isEmpty()) { QMessageBox emptyFile; emptyFile.setText("The file you wanted to save is empty"); emptyFile.exec(); return 0; } mergePDFs(files, outputFileName); QMessageBox finishedMsg; finishedMsg.setText("The Merge has been completed"); finishedMsg.exec(); return app.exec(); }
解决方案
原代码的问题在于使用QPdfDocument::render()将PDF页面转换为图片后再绘制,导致合并后的PDF仅包含像素信息,丢失了文本的可搜索属性。我们可以改用QPdfPage::paint()方法直接在QPainter上绘制PDF页面的矢量/文本内容,从而保留文字的可搜索性。
修改后的mergePDFs函数如下:
void mergePDFs(const QStringList& fileList, const QString& outputFileName) { QPdfWriter pdfWriter(outputFileName); pdfWriter.setResolution(150); // 初始化第一个文档的页面尺寸(确保输出PDF首页尺寸正确) QPdfDocument firstDoc; if (firstDoc.load(fileList.first()) && firstDoc.pageCount() > 0) { QPageSize pageSize(firstDoc.pagePointSize(0).toSize()); pdfWriter.setPageSize(pageSize); firstDoc.close(); } QPainter painter(&pdfWriter); for (const QString& file : fileList) { QPdfDocument pdfDoc; if (!pdfDoc.load(file)) { continue; // 加载失败则跳过当前文件 } for (int i = 0; i < pdfDoc.pageCount(); ++i) { QPdfPage page = pdfDoc.page(i); QPageSize pageSize(page.pagePointSize().toSize()); pdfWriter.setPageSize(pageSize); // 直接绘制PDF页面内容,保留文本可搜索性 page.paint(&painter, page.pagePointSize().toSize()); // 仅在非最后一页时创建新页面,避免生成空白尾页 if (!(i == pdfDoc.pageCount() - 1 && &file == &fileList.last())) { pdfWriter.newPage(); } } pdfDoc.close(); } painter.end(); }
修改说明
- 替换了
render()转图片的逻辑,使用QPdfPage::paint()直接绘制原始PDF内容,保留文本的可搜索属性。 - 优化了新页面创建逻辑,避免在合并后的PDF末尾生成空白页。
- 增加了PDF加载失败的容错处理,跳过无法加载的文件。
- 修正了原代码中页面索引的问题(原代码使用
pagePointSize(1),但PDF页面索引从0开始)。
main函数无需修改,保持原有的文件选择和提示逻辑即可。
内容的提问来源于stack exchange,提问作者cptn lucky
相关产品推荐
相关产品推荐

