使用iTextsharp将PDF拆分成多个PDF

19
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文件按50页的间隔分成多个PDF文件。(例如,如果有400页的PDF,则需要8个PDF文件)。上述代码会将每一页都分割成一个PDF文件。请帮助我……我正在使用iTextSharp和asp.net。


1
提示:如果您只想每50页创建一个新文档,为什么要在每个循环迭代期间创建一个新文档? - Heinzi
4个回答

15

您正在遍历PDF并在每次翻页时创建一个新文档。您需要跟踪页面,以便仅在每50页时执行拆分操作。个人建议将此放在单独的方法中,并从循环中调用它。例如:

private void ExtractPages(string sourcePDFpath, string outputPDFpath, int startpage,  int endpage)
{
    PdfReader reader = null;
    Document sourceDocument = null;
    PdfCopy pdfCopyProvider = null;
    PdfImportedPage importedPage = null;

    reader = new PdfReader(sourcePDFpath);
    sourceDocument = new Document(reader.GetPageSizeWithRotation(startpage));
    pdfCopyProvider = new PdfCopy(sourceDocument, new System.IO.FileStream(outputPDFpath, System.IO.FileMode.Create));

    sourceDocument.Open();

    for (int i = startpage; i <= endpage; i++)
    {
        importedPage = pdfCopyProvider.GetImportedPage(reader, i);
        pdfCopyProvider.AddPage(importedPage);
    }
    sourceDocument.Close();
    reader.Close();
}

因此,在您的原始代码中,循环遍历您的PDF文件,并在每50页调用上述方法。您只需要在代码块中添加变量以跟踪起始/结束页面。


4

1
我使用了上面的CodeProject代码,但是出现了错误:“拒绝访问路径”。 - Billy
这意味着您没有权限写入正在写入PDF的文件夹。 - RohitWagh

2

这里有一个更短的解决方案。我没有测试哪种方法的性能更好。

private void ExtractPages(string sourcePDFpath, string outputPDFpath, int startpage, int endpage)
{
  var pdfReader = new PdfReader(sourcePDFpath);
  try
  {
    pdfReader.SelectPages($"{startpage}-{endpage}");
    using (var fs = new FileStream(outputPDFpath, FileMode.Create, FileAccess.Write))
    {
      PdfStamper stamper = null;
      try
      {
        stamper = new PdfStamper(pdfReader, fs);
      }
      finally
      {
        stamper?.Close();
      }
    }
  }
  finally
  {
    pdfReader.Close();
  }
}

1
你的解决方案最相关的优势是它保留了文档级别的数据(元数据、文档级别附件等),它更短只是一个不错的副作用。 - mkl
@mkl 我发现PDFCopy在保持XmpMetadata和其他所有内容完整方面更好。 - blaze_125
PdfCopyPdfStamper更好?这听起来不可信。只有在PdfCopy偶然修复了一些问题而PdfStamper保留了问题的情况下才可能如此。除非我漏看了什么... ;) - mkl

0
我遇到了同样的问题,但想要使用 iText7 for .NET。 在这个具体的案例中,以下代码对我有用:
第一步:实现自己的 PdfSplitter
 public class MyPdfSplitter : PdfSplitter
 {
    private readonly string _destFolder;
    private int _pageNumber;
    public MyPdfSplitter(PdfDocument pdfDocument, string destFolder) : base(pdfDocument)
    {
        _destFolder = destFolder;
    }

    protected override PdfWriter GetNextPdfWriter(PageRange documentPageRange)
    {
        _pageNumber++;
        return new PdfWriter(Path.Combine(_destFolder, $"p{_pageNumber}.pdf"));
    }
}

第二步:使用它来拆分您的PDF文件

using (var pdfDoc = new PdfDocument(new PdfReader(filePath)))
{
    var splitDocuments = new MyPdfSplitter(pdfDoc, targetFolder).SplitByPageCount(1);
    foreach (var splitDocument in splitDocuments)
    {
        splitDocument.Close();
    }
 }

从Java示例迁移的代码:https://itextpdf.com/en/resources/examples/itext-7/splitting-pdf-file

希望这对其他人有所帮助!


如果MyPdfSplitter创建了一个PdfWriter(新的MemoryStream),你知道如何获取流的内容吗? - M Akin
为了获取内存流,我在CustomSplitter上创建了一个属性来保存MemoryStream的列表,以便稍后可以访问它们。 - M Akin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接