如何使用iTextSharp组合多个PDF文件,不包括分页符?

时间:2015-01-16 16:33:45

标签: itextsharp itext

我想知道是否有人用iTextSharp完成了这项工作,但我想将多个PDF文件组合成一个但是让页面突然出现。例如,我想创建4个PDF文件,每个文件包含3行文本,因此我希望生成的文件在1页中包含所有12行。这可能吗?

2 个答案:

答案 0 :(得分:2)

由于OP还用[iText]标记了这个问题,而且我在Java上比.Net更多,这里是iText / Java的答案。它应该很容易翻译成iTextSharp / C#。

原始问题

  

我想将多个PDF文件合并为一个,但请将页面分开。例如,我想创建4个包含3行文本的PDF文件,因此我希望生成的文件在1页中包含所有12行。

对于PDF文件,如该示例所示,您可以使用此简单实用程序类:

public class PdfDenseMergeTool
{
    public PdfDenseMergeTool(Rectangle size, float top, float bottom, float gap)
    {
        this.pageSize = size;
        this.topMargin = top;
        this.bottomMargin = bottom;
        this.gap = gap;
    }

    public void merge(OutputStream outputStream, Iterable<PdfReader> inputs) throws DocumentException, IOException
    {
        try
        {
            openDocument(outputStream);
            for (PdfReader reader: inputs)
            {
                merge(reader);
            }
        }
        finally
        {
            closeDocument();
        }

    }

    void openDocument(OutputStream outputStream) throws DocumentException
    {
        final Document document = new Document(pageSize, 36, 36, topMargin, bottomMargin);
        final PdfWriter writer = PdfWriter.getInstance(document, outputStream);
        document.open();
        this.document = document;
        this.writer = writer;
        newPage();
    }

    void closeDocument()
    {
        try
        {
            document.close();
        }
        finally
        {
            this.document = null;
            this.writer = null;
            this.yPosition = 0;
        }
    }

    void newPage()
    {
        document.newPage();
        yPosition = pageSize.getTop(topMargin);
    }

    void merge(PdfReader reader) throws IOException
    {
        PdfReaderContentParser parser = new PdfReaderContentParser(reader);
        for (int page = 1; page <= reader.getNumberOfPages(); page++)
        {
            merge(reader, parser, page);
        }
    }

    void merge(PdfReader reader, PdfReaderContentParser parser, int page) throws IOException
    {
        TextMarginFinder finder = parser.processContent(page, new TextMarginFinder());
        Rectangle pageSizeToImport = reader.getPageSize(page);
        float heightToImport = finder.getHeight();
        float maxHeight = pageSize.getHeight() - topMargin - bottomMargin;
        if (heightToImport > maxHeight)
        {
            throw new IllegalArgumentException(String.format("Page %s content too large; height: %s, limit: %s.", page, heightToImport, maxHeight));
        }

        if (heightToImport > yPosition - pageSize.getBottom(bottomMargin))
        {
            newPage();
        }
        else if (!writer.isPageEmpty())
        {
            heightToImport += gap;
        }
        yPosition -= heightToImport;

        PdfImportedPage importedPage = writer.getImportedPage(reader, page);
        writer.getDirectContent().addTemplate(importedPage, 0, yPosition - (finder.getLly() - pageSizeToImport.getBottom()));
    }

    Document document = null;
    PdfWriter writer = null;
    float yPosition = 0; 

    final Rectangle pageSize;
    final float topMargin;
    final float bottomMargin;
    final float gap;
}

如果您有PdfReader个实例inputs的列表,则可以将它们合并为OutputStream output

PdfDenseMergeTool tool = new PdfDenseMergeTool(PageSize.A4, 18, 18, 5);
tool.merge(output, inputs);

使用A4页面大小创建合并文档,每个页面大小为18/72“,不同PDF页面内容之间的间距为5/72”。

评论

iText TextMarginFinder(在上面PdfDenseMergeTool中使用)仅考虑文字。如果还要考虑其他内容类型,则必须稍微扩展此类。

  

每个PDF只有几行,可能是表格或图像,但我希望最终结果在一个页面中。

如果表格包含的文字内容高于或低于文本内容(例如线条或彩色背景),则应使用较大的间隙值。不幸的是,TextMarginFinder使用的解析框架不会将矢量图形命令转发给查找程序。

如果图像是位图图像,则应通过实施TextMarginFinder方法来扩展renderImage,以便将图像区域考虑在内。

  

此外,某些PDF可能包含字段,因此我希望将这些字段保留在生成的合并PDF中。

如果还要考虑AcroForm字段,则必须

  1. 扩展由TextMarginFinder表示的矩形,以包含窗口小部件注释的可视化矩形,以及
  2. 扩展PdfDenseMergeTool.merge(PdfReader, PdfReaderContentParser, int)方法以复制这些小部件注释。
  3. 更新

    我在上面写了

      

    不幸的是TextMarginFinder使用的解析框架没有将矢量图形命令转发给查找器。

    同时(在版本5.5.6中)解析框架已经扩展为转发矢量图形命令。

    如果替换

    TextMarginFinder finder = parser.processContent(page, new TextMarginFinder());
    

    通过

    MarginFinder finder = parser.processContent(page, new MarginFinder());
    

    使用MarginFinder class底部显示的this answer,系统会考虑所有内容,而不仅仅是文字。

答案 1 :(得分:1)

对于那些想要在C#中使用上述代码的人,请转到此处。

using System;
using System.Collections.Generic;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;

namespace Test.WebService.Support {

  public class PDFMerge {

    private Rectangle PageSize;
    private float TopMargin;
    private float BottomMargin;
    private float Gap;
    private Document Document = null;
    private PdfWriter Writer = null;
    private float YPosition = 0;

    public PDFMerge(Rectangle size, float top, float bottom, float gap) {
      this.PageSize = size;
      this.TopMargin = top;
      this.BottomMargin = bottom;
      this.Gap = gap;
    } // PDFMerge

    public void Merge(MemoryStream outputStream, List<PdfReader> inputs) {
      try {
        this.OpenDocument(outputStream);

        foreach (PdfReader reader in inputs) {
          this.Merge(reader);
        }
      } finally {
        this.CloseDocument();
      }
    } // Merge

    private void Merge(PdfReader reader) {
      PdfReaderContentParser parser = new PdfReaderContentParser(reader);

      for (int p = 1; p <= reader.NumberOfPages; p++) {
        this.Merge(reader, parser, p);
      }
    } // Merge

    private void Merge(PdfReader reader, PdfReaderContentParser parser, int pageIndex) {
      TextMarginFinder Finder = parser.ProcessContent(pageIndex, new TextMarginFinder());
      Rectangle PageSizeToImport = reader.GetPageSize(pageIndex);
      float HeightToImport = Finder.GetHeight();
      float MaxHeight = PageSize.Height - TopMargin - BottomMargin;

      if (HeightToImport > MaxHeight) {
        throw new ArgumentException(string.Format("Page {0} content too large; height: {1}, limit: {2}.", pageIndex, HeightToImport, MaxHeight));
      }

      if (HeightToImport > YPosition - PageSize.GetBottom(BottomMargin)) {
        this.NewPage();
      } else if (!Writer.PageEmpty) {
        HeightToImport += Gap;
      }

      YPosition -= HeightToImport;

      PdfImportedPage ImportedPage = Writer.GetImportedPage(reader, pageIndex);
      Writer.DirectContent.AddTemplate(ImportedPage, 0, YPosition - (Finder.GetLly() - PageSizeToImport.Bottom));
    } // Merge

    private void OpenDocument(MemoryStream outputStream) {
      Document Document = new Document(PageSize, 36, 36, this.TopMargin, BottomMargin);
      PdfWriter Writer = PdfWriter.GetInstance(Document, outputStream);
      Document.Open();
      this.Document = Document;
      this.Writer = Writer;
      this.NewPage();
    } // OpenDocument

    private void CloseDocument() {
      try {
        Document.Close();
      } finally {
        this.Document = null;
        this.Writer = null;
        this.YPosition = 0;
      }
    } // CloseDocument

    private void NewPage() {
      Document.NewPage();
      YPosition = PageSize.GetTop(TopMargin);
    } // NewPage

  }
}