【问题标题】:Split PDF into separate files based on text根据文本将 PDF 拆分为单独的文件
【发布时间】:2013-05-03 11:35:29
【问题描述】:

我有一个 大型单个 pdf 文档,其中包含 多条记录。每条记录通常占用一页,但有些记录使用 2 页。记录以定义的文本开头,始终相同。

我的目标是将此 pdf 文件拆分为单独的 pdf 文件,并且拆分应始终在找到“标题文本”之前进行。

注意:我正在寻找使用 java 或 python 的工具或库。必须在Win 7 上免费提供。

有什么想法吗? AFAIK imagemagick 不会为此工作。可以itext 这样做吗?我从来没有用过,它的 相当复杂,所以需要一些提示。

编辑:

标记的答案使我找到了解决方案。为了完整起见,我的确切实现是:

public void splitByRegex(String filePath, String regex,
        String destinationDirectory, boolean removeBlankPages) throws IOException,
        DocumentException {

    logger.entry(filePath, regex, destinationDirectory);
    destinationDirectory = destinationDirectory == null ? "" : destinationDirectory;
    PdfReader reader = null;
    Document document = null;
    PdfCopy copy = null;
    Pattern pattern = Pattern.compile(regex);        

    try {
        reader = new PdfReader(filePath);
        final String RESULT = destinationDirectory + "/record%d.pdf";
        // loop over all the pages in the original PDF
        int n = reader.getNumberOfPages();
        for (int i = 1; i < n; i++) {

            final String text = PdfTextExtractor.getTextFromPage(reader, i);
            if (pattern.matcher(text).find()) {
                if (document != null && document.isOpen()) {
                    logger.debug("Match found. Closing previous Document..");
                    document.close();
                }
                String fileName = String.format(RESULT, i);
                logger.debug("Match found. Creating new Document " + fileName + "...");
                document = new Document();
                copy = new PdfCopy(document,
                        new FileOutputStream(fileName));
                document.open();
                logger.debug("Adding page to Document...");
                copy.addPage(copy.getImportedPage(reader, i));

            } else if (document != null && document.isOpen()) {
                logger.debug("Found Open Document. Adding additonal page to Document...");
                if (removeBlankPages && !isBlankPage(reader, i)){
                    copy.addPage(copy.getImportedPage(reader, i));
                }
            }
        }
        logger.exit();
    } finally {
        if (document != null && document.isOpen()) {
            document.close();
        }
        if (reader != null) {
            reader.close();
        }
    }
}

private boolean isBlankPage(PdfReader reader, int pageNumber)
        throws IOException {

    // see http://itext-general.2136553.n4.nabble.com/Detecting-blank-pages-td2144877.html
    PdfDictionary pageDict = reader.getPageN(pageNumber);
    // We need to examine the resource dictionary for /Font or
    // /XObject keys.  If either are present, they're almost
    // certainly actually used on the page -> not blank.
    PdfDictionary resDict = (PdfDictionary) pageDict.get(PdfName.RESOURCES);
    if (resDict != null) {
        return resDict.get(PdfName.FONT) == null
                && resDict.get(PdfName.XOBJECT) == null;
    } else {
        return true;
    }
}

【问题讨论】:

  • iText 如果可以正确解析 PDF 中的文本,则可以执行您想要的操作。你说,图书馆一定是免费的。 iText 作为免费软件要求您遵守 AGPL 许可。
  • 这是一次性的,所以 AGPl 不是问题。文本是可选的(例如文本),因此应该可以工作。但是,如果您知道的话,我对代码示例很感兴趣。
  • 目前我只能通过智能手机上网。稍后我会尝试找到一些示例代码。

标签: pdf split


【解决方案1】:

您可以使用 iText 创建满足您要求的工具。

当您在寻找有关 iText 库(当前版本)的代码示例时,您应该咨询iText in Action — 2nd Edition 在线代码示例,并且可以通过来自here 的关键字进行搜索。

在您的情况下,相关示例是 Burst.javaExtractPageContentSorted2.java

Burst.java 展示了如何将一个 PDF 拆分为多个较小的 PDF。中心代码:

PdfReader reader = new PdfReader("allrecords.pdf");
final String RESULT = "record%d.pdf";

// We'll create as many new PDFs as there are pages
Document document;
PdfCopy copy;
// loop over all the pages in the original PDF
int n = reader.getNumberOfPages();
for (int i = 0; i < n; ) {
    // step 1
    document = new Document();
    // step 2
    copy = new PdfCopy(document,
            new FileOutputStream(String.format(RESULT, ++i)));
    // step 3
    document.open();
    // step 4
    copy.addPage(copy.getImportedPage(reader, i));
    // step 5
    document.close();
}
reader.close();

此示例将 PDF 拆分为单页 PDF。在您的情况下,您需要按不同的标准进行拆分。但这仅意味着在循环中您有时必须添加多个导入的页面(从而将要导入的循环索引和页码解耦)。

要识别新数据集从哪些页面开始,请受 ExtractPageContentSorted2.java 的启发。此示例显示如何将页面的文本内容解析为字符串。中心代码:

PdfReader reader = new PdfReader("allrecords.pdf");
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
    System.out.println("\nPage " + i);
    System.out.println(PdfTextExtractor.getTextFromPage(reader, i));
}
reader.close();

只需搜索记录开始文本:如果页面中的文本包含它,则从那里开始一条新记录。

【讨论】:

  • 谢谢,这很方便。不过,您的 for 循环需要一直持续到 i
  • 这应该没有必要。由于 i 在循环体内递增,这本质上已经是从 1 到 n 的循环,就 getImportedPage 而言。
【解决方案2】:

Apache PDFBox 有一个PDFSplit 实用程序,您可以从命令行运行它。

【讨论】:

    【解决方案3】:

    如果你喜欢 Python,这里有一个不错的库:PyPDF2。该库是纯python2,类似BSD的许可证。

    示例代码:

    from PyPDF2 import PdfFileWriter, PdfFileReader
    
    input1 = PdfFileReader(open("C:\\Users\\Jarek\\Documents\\x.pdf", "rb"))
    
    # analyze pdf data
    print input1.getDocumentInfo()
    print input1.getNumPages()
    text = input1.getPage(0).extractText()
    print text.encode("windows-1250", errors='backslashreplacee')
    
    # create output document
    output = PdfFileWriter()
    output.addPage(input1.getPage(0))
    fout = open("c:\\temp\\1\\y.pdf", "wb")
    output.write(fout)
    fout.close()
    

    【讨论】:

      【解决方案4】:

      对于非编码人员而言,PDF 内容拆分可能是最简单的方法,无需重新发明轮子,并且界面易于使用:http://www.traction-software.co.uk/pdfcontentsplitsa/index.html

      希望有帮助。

      【讨论】:

      • 你的回答断章取义,不是代码而是软件,这里不合适。
      猜你喜欢
      • 1970-01-01
      • 2016-01-07
      • 2022-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多