复制时,页面在PDFBox中的新文档中被裁剪

时间:2016-05-30 13:27:54

标签: java pdfbox

我正在尝试将单个PDF拆分为多个。像10页文档一样成10页单页文档。

PDDocument source = PDDocument.load(input_file);
PDDocument output = new PDDocument();
PDPage page = source.getPages().get(0);
output.addPage(page);
output.save(file);
output.close();

问题在于,新文档的页面大小与原始文档不同。因此,新文档中的某些文本被裁剪或丢失。我正在使用PDFBox 2.0以及如何避免这种情况?

更新 谢谢@mkl。

斯普利特做了神奇的事。这是更新的工作部分,

public static void extractAndCreateDocument(SplitMeta meta, PDDocument source)
      throws IOException {

    File file = new File(meta.getFilename());

    Splitter splitter = new Splitter();
    splitter.setStartPage(meta.getStart());
    splitter.setEndPage(meta.getEnd());
    splitter.setSplitAtPage(meta.getEnd());

    List<PDDocument> docs = splitter.split(source);
    if(docs.size() > 0){
      PDDocument output = docs.get(0);
      output.save(file);
      output.close();
    }
  }

public class SplitMeta {

  private String filename;
  private int start;
  private int end;

  public SplitMeta() {
  }
}

1 个答案:

答案 0 :(得分:4)

不幸的是,OP没有提供样本文档来重现该问题。因此,我不得不猜测。

我认为问题是基于没有立即链接到页面对象但是从其父对象继承的对象。

在这种情况下使用PDDocument.addPage是错误的选择,因为此方法仅将给定的页面对象添加到目标文档页面树而不考虑继承的东西。

相反,应该使用PDDocument.importPage,其记录为:

/**
 * This will import and copy the contents from another location. Currently the content stream is stored in a scratch
 * file. The scratch file is associated with the document. If you are adding a page to this document from another
 * document and want to copy the contents to this document's scratch file then use this method otherwise just use
 * the {@link #addPage} method.
 * 
 * Unlike {@link #addPage}, this method does a deep copy. If your page has annotations, and if
 * these link to pages not in the target document, then the target document might become huge.
 * What you need to do is to delete page references of such annotations. See
 * <a href="http://stackoverflow.com/a/35477351/535646">here</a> for how to do this.
 *
 * @param page The page to import.
 * @return The page that was imported.
 * 
 * @throws IOException If there is an error copying the page.
 */
public PDPage importPage(PDPage page) throws IOException

实际上,即使这种方法可能还不够,因为它不考虑所有继承的属性,但是查看Splitter实用程序类可以得到一个人必须做的印象:

PDPage imported = getDestinationDocument().importPage(page);
imported.setCropBox(page.getCropBox());
imported.setMediaBox(page.getMediaBox());
// only the resources of the page will be copied
imported.setResources(page.getResources());
imported.setRotation(page.getRotation());
// remove page links to avoid copying not needed resources 
processAnnotations(imported);

使用辅助方法

private void processAnnotations(PDPage imported) throws IOException
{
    List<PDAnnotation> annotations = imported.getAnnotations();
    for (PDAnnotation annotation : annotations)
    {
        if (annotation instanceof PDAnnotationLink)
        {
            PDAnnotationLink link = (PDAnnotationLink)annotation;   
            PDDestination destination = link.getDestination();
            if (destination == null && link.getAction() != null)
            {
                PDAction action = link.getAction();
                if (action instanceof PDActionGoTo)
                {
                    destination = ((PDActionGoTo)action).getDestination();
                }
            }
            if (destination instanceof PDPageDestination)
            {
                // TODO preserve links to pages within the splitted result  
                ((PDPageDestination) destination).setPage(null);
            }
        }
        // TODO preserve links to pages within the splitted result  
        annotation.setPage(null);
    }
}

当您尝试将单个PDF拆分为多个,例如将10页文档拆分为10个单页文档时,您可能希望按原样使用此Splitter实用程序类

测试

为了测试这些方法,我使用了PDF Clown示例输出AnnotationSample.Standard.pdf的输出,因为该库在很大程度上取决于页面树值的继承。因此,我使用PDDocument.addPagePDDocument.importPageSplitter将其唯一页面的内容复制到新文档中:

PDDocument source = PDDocument.load(resource);
PDDocument output = new PDDocument();
PDPage page = source.getPages().get(0);
output.addPage(page);
output.save(new File(RESULT_FOLDER, "PageAddedFromAnnotationSample.Standard.pdf"));
output.close();

CopyPages.java test testWithAddPage

PDDocument source = PDDocument.load(resource);
PDDocument output = new PDDocument();
PDPage page = source.getPages().get(0);
output.importPage(page);
output.save(new File(RESULT_FOLDER, "PageImportedFromAnnotationSample.Standard.pdf"));
output.close();

CopyPages.java test testWithImportPage

PDDocument source = PDDocument.load(resource);
Splitter splitter = new Splitter();
List<PDDocument> results = splitter.split(source);
Assert.assertEquals("Expected exactly one result document from splitting a single page document.", 1, results.size());
PDDocument output = results.get(0);
output.save(new File(RESULT_FOLDER, "PageSplitFromAnnotationSample.Standard.pdf"));
output.close();

CopyPages.java test testWithSplitter

只有最终测试才会忠实地复制页面。