我想知道是否有人用iTextSharp完成了这项工作,但我想将多个PDF文件组合成一个但是让页面突然出现。例如,我想创建4个PDF文件,每个文件包含3行文本,因此我希望生成的文件在1页中包含所有12行。这可能吗?
答案 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字段,则必须
TextMarginFinder
表示的矩形,以包含窗口小部件注释的可视化矩形,以及PdfDenseMergeTool.merge(PdfReader, PdfReaderContentParser, int)
方法以复制这些小部件注释。我在上面写了
不幸的是
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
}
}