You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:37:26