[英]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
对象写入的位置。 还有一种方法,虽然不是一种直观的方法:您必须覆盖PdfSplitter
的GetNextPdfWriter
方法,该方法最初如下所示:
/// <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 的主要目标是使用ExtractPageRanges
和SplitBy...
方法将文档拆分为多个部分,在这种情况下,您需要提供更大的、可能不完全知道的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.