2

这是我拆分大型 PDF (144 mb) 的方法:

public int SplitAndSave(string inputPath, string outputPath)
{
    FileInfo file = new FileInfo(inputPath);
    string name = file.Name.Substring(0, file.Name.LastIndexOf("."));

    using (PdfReader reader = new PdfReader(inputPath))
    {
        for (int pagenumber = 1; pagenumber <= reader.NumberOfPages; pagenumber++)
        {
            string filename = pagenumber.ToString() + ".pdf";

            Document document = new Document();
            PdfCopy copy = new PdfCopy(document, new FileStream(outputPath + "\\" + filename, FileMode.Create));

            document.Open();

            copy.AddPage(copy.GetImportedPage(reader, pagenumber));

            document.Close();
        }
        return reader.NumberOfPages;
    }
}

对于大多数 PDF(小尺寸,我猜是旧格式),一切正常。但是对于更大的页面(可能使用 refstreams 之类的东西来获得更好的压缩),拆分页面作为一页打开,但其大小等于原始 PDF 的大小。我能做些什么?

4

1 回答 1

7

如果您的文档Top_Gear_Magazine_2012_09.pdf原因确实是我提到的原因:所有页面都将对象2 0 R称为/Resources,而2 0 obj中的字典又会引用 PDF 中的所有图像。

要将文档拆分为仅包含所需图像的部分文档,您应该通过首先找出哪些图像属于哪些页面然后为所有页面创建单独的/Resources字典来预处理文档。

由于您已经在此上下文中使用了 iText,因此您还可以使用它来找出哪些页面需要哪些图像。使用 iTextparser包最初使用一个实现逐页解析 PDF,该RenderListener实现的RenderImage方法只记住当前页面上使用了哪些图像对象。(作为一个特殊的转折点,iText 隐藏了相关图像 XObject 的名称;不过,您会获得间接对象,并且可以查询其对象和世代编号,这足以满足下一步的需求。)

在第二步中,您在 a 中打开文档PdfStamper并遍历页面。对于每个页面,您检索/Resources字典并复制它,但仅复制那些 XObjects 引用,这些引用引用了您在第一步中为相应页面记住其对象编号和世代的图像对象。最后,您将缩小的副本设置为相关页面的/Resources字典。

生成的 PDF 应该拆分得很好。

PS最近在 iText 邮件列表中出现了一个非常相似的问题。在该线程中,此处给出的解决方案已得到改进,为了解决 iText 隐藏 xobject 名称引起的困难,我现在建议通过使用不同ContentOperator的“Do”在名称丢失之前进行干预,这里是 Java 版本:

class Do implements ContentOperator 
{ 
    public void invoke(PdfContentStreamProcessor processor, PdfLiteral operator, ArrayList<PdfObject> operands) throws IOException 
    { 
        PdfName xobjectName = (PdfName)operands.get(0); 
        names.add(xobjectName); 
    } 

    final List<PdfName> names = new ArrayList<PdfName>(); 
} 

这个内容操作符简单地收集使用的xobjects 的名称,即为给定页面保留的xobject 资源。

于 2013-03-22T15:05:16.493 回答