繁体   English   中英

如何使用 IText 7 从 PDF 中提取页面?

[英]How to Extract pages from a PDF using IText 7?

我尝试使用iText7库从PDF文件中提取一些页面以创建一个新页面。

    static void Splitter()
        {
        string file = @"C:\Users\Standard\Downloads\Merged\CK 2002989 $29,514.42 02.12.20.pdf";
        string range = "1, 4, 8";
        var pdfDocumentInvoiceNumber = new PdfDocument(new PdfReader(file));
        var split = new PdfSplitter(pdfDocumentInvoiceNumber);
        var result = split.ExtractPageRange(new PageRange(range));
        var numberOfPagesPdfDocumentInvoiceNumber = result.GetNumberOfPages();
        String toFile = @"C:\Users\Standard\Downloads\Result\Extracted.pdf";
        var pdfWriter = new PdfWriter(toFile);
        var pdfDocumentInvoiceMergeResult = new PdfDocument(pdfWriter);
        for (var i = 1; i <= numberOfPagesPdfDocumentInvoiceNumber; i++) 
            { 
            var pdfPage = result.GetPage(i).CopyTo(pdfDocumentInvoiceMergeResult);
            pdfDocumentInvoiceMergeResult.AddPage(pdfPage);
            }
        }

但是当我尝试使用CopyTo方法时出现错误

iText.Kernel.PdfException: 'Cannot copy indirect object from the document that is being written.'

这里的问题是PdfSplitter方法返回的文档,特别是ExtractPageRange ,是 iText 7 文档写入,即这些PdfDocument实例已经用PdfWriter实例化。

此类文档受到某些限制,特别是不能从中复制页面。 有关这方面的详细信息,请阅读此处此处的答案。

为了使这些结果文档(以及与它们一起的整个PdfSplitter class)具有任何价值,因此,您需要一种方法来定义这些文档的PdfWriter对象写入的位置。 还有一种方法,虽然不是一种直观的方法:您必须覆盖PdfSplitterGetNextPdfWriter方法,该方法最初如下所示:

/// <summary>This method is called when another split document is to be created.</summary>
/// <remarks>
/// This method is called when another split document is to be created.
/// You can override this method and return your own
/// <see cref="iText.Kernel.Pdf.PdfWriter"/>
/// depending on your needs.
/// </remarks>
/// <param name="documentPageRange">the page range of the original document to be included in the document being created now.
///     </param>
/// <returns>the PdfWriter instance for the document which is being created.</returns>
protected internal virtual PdfWriter GetNextPdfWriter(PageRange documentPageRange) {
    return new PdfWriter(new ByteArrayOutputStream());
}

在像您这样的用例中,您只期望最终要写入文件的单个返回文档,您可以这样做:

class MySplitter : PdfSplitter
{
    public MySplitter(PdfDocument pdfDocument) : base(pdfDocument)
    {
    }

    protected override PdfWriter GetNextPdfWriter(PageRange documentPageRange)
    {
        String toFile = @"C:\Users\Standard\Downloads\Result\Extracted.pdf";
        return new PdfWriter(toFile);
    }
}

随着PdfWriter实例化移动到该自定义拆分器中,您的主要代码减少到

string file = @"C:\Users\Standard\Downloads\Merged\CK 2002989 $29,514.42 02.12.20.pdf";
string range = "1, 4, 8";
var pdfDocumentInvoiceNumber = new PdfDocument(new PdfReader(file));
var split = new MySplitter(pdfDocumentInvoiceNumber);
var result = split.ExtractPageRange(new PageRange(range));
result.Close();

在像你这样的用例中,这看起来很奇怪,必须从 PdfSplitter 派生一个自定义PdfSplitter只是为了从源 PDF 提取几页到结果 ZBCD1B68617759B1DFCFF0403A6B5A8D1。 ExtractPageRange的附加PdfWriter参数不会使它更容易吗?

但请注意, PdfSplitter class 的主要目标是使用ExtractPageRangesSplitBy...方法将文档拆分为多个部分,在这种情况下,您需要提供更大的、可能不完全知道的PdfWriters ...一点也不轻松!

当然,更好的解决方案可能是注入一些 lambda 表达式或其他一些回调机制。 例如:

class ImprovedSplitter : PdfSplitter
{
    private Func<PageRange, PdfWriter> nextWriter;
    public ImprovedSplitter(PdfDocument pdfDocument, Func<PageRange, PdfWriter> nextWriter) : base(pdfDocument)
    {
        this.nextWriter = nextWriter;
    }

    protected override PdfWriter GetNextPdfWriter(PageRange documentPageRange)
    {
        return nextWriter.Invoke(documentPageRange);
    }
}

你可以这样使用

string file = @"C:\Users\Standard\Downloads\Merged\CK 2002989 $29,514.42 02.12.20.pdf";
string range = "1, 4, 8";
var pdfDocumentInvoiceNumber = new PdfDocument(new PdfReader(file));
var split = new ImprovedSplitter(pdfDocumentInvoiceNumber, pageRange => new PdfWriter(@"C:\Users\Standard\Downloads\Result\Extracted.pdf"));
var result = split.ExtractPageRange(new PageRange(range));
result.Close();

问题与Splitter有关; 但是没有它也可以提取!

以下代码替换您的代码而不会出现错误消息。

    Private Sub TestCopyTo()
        Dim pdfInput = New PdfDocument(New PdfReader(sPdfInputFile))
        Dim iPageRange As Integer() = {2, 4, 8}
        Dim iLastPage = iPageRange.Length - 1

        Using pdfNew = New PdfDocument(New PdfWriter("result.pdf"))
            For i = 0 To iLastPage
                Dim iPage = iPageRange(i)
                Dim oNewPage As PdfPage = pdfInput.GetPage(iPage).CopyTo(pdfNew)
                pdfNew.AddPage(oNewPage)
            Next i
            pdfNew.Close()
        End Using
    End Sub

这当然更简单......并完成工作!

供您参考,我在Visual Studio 2022 / Windows 11上使用Nuget工具安装了iText7版本7.2.5

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM