将使用 ITextSharp 从 html 创建的 N 个 pdf 文件合并到另一个空白 pdf 文件
Merging N pdf files, created from html using ITextSharp, to another blank pdf file
我需要将 N 个 PDF 文件合并为一个。我先创建一个空白文件
byte[] pdfBytes = null;
var ms = new MemoryStream();
var doc = new iTextSharp.text.Document();
var cWriter = new PdfCopy(doc, ms);
稍后我循环 html 字符串数组
foreach (NBElement htmlString in someElement.Children())
{
byte[] msTempDoc = getPdfDocFrom(htmlString.GetString(), cssString.GetString());
addPagesToPdf(cWriter, msTempDoc);
}
在 getPdfDocFrom 中,我使用 XMLWorkerHelper 创建 pdf 文件,return 它作为字节数组
private byte[] getPdfDocFrom(string htmlString, string cssString)
{
var tempMs = new MemoryStream();
byte[] tempMsBytes;
var tempDoc = new iTextSharp.text.Document();
var tempWriter = PdfWriter.GetInstance(tempDoc, tempMs);
tempDoc.Open();
using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(cssString)))
{
using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(htmlString)))
{
//Parse the HTML
iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(tempWriter, tempDoc, msHtml, msCss);
tempMsBytes = tempMs.ToArray();
}
}
tempDoc.Close();
return tempMsBytes;
}
稍后我尝试将此 PDF 文件中的页面添加到空白文件中。
private static void addPagesToPdf(PdfCopy mainDocWriter, byte[] sourceDocBytes)
{
using (var msOut = new MemoryStream())
{
PdfReader reader = new PdfReader(new MemoryStream(sourceDocBytes));
int n = reader.NumberOfPages;
PdfImportedPage page;
for (int i = 1; i <= n; i++)
{
page = mainDocWriter.GetImportedPage(reader, i);
mainDocWriter.AddPage(page);
}
}}
当它试图从我传递给函数的字节数组创建 PdfReader 时,它中断了。 "Rebuild failed: trailer not found.; Original message: PDF startxref not found."
我以前使用另一个库来处理 PDF。我将 2 个 PdfDocuments 作为对象传递,并循环地从一个页面添加到另一个页面。但是它不支持 Css,所以我不得不切换到 ITextSharp。
我不太明白 PdfWriter 和 PdfCopy 之间的区别。
您的代码中存在逻辑错误。当您像在 getPdfDocFrom()
方法中那样从头开始创建文档时,在您触发 Close()
方法之前文档是不完整的。在此 Close()
方法中,创建了预告片以及交叉引用 (xref) table。该错误告诉您缺少这些。
的确,你调用了Close()
方法:
tempDoc.Close();
但是当您 Close()
文档时,为时已晚:您已经创建了 tempMsBytes
数组。您需要在关闭文档后创建该数组。
编辑: 我对 C# 一无所知,但是如果 MemoryStream
在关闭后清除它的缓冲区,你可以使用 mainDocWriter.CloseStream = false;
这样关闭文档时 MemoryStream
并未关闭。
在 Java 中,将 "close stream" 参数设置为 false 是个坏主意。当我阅读问题 Create PDF in memory instead of physical file 的答案时,我发现 C# 可能并不总是需要这一行。
备注: 通过将 PdfImportedPage
个实例添加到 PdfWriter
来合并文件是一个低级趣味的例子。如果您使用的是 iTextSharp 5 或更早版本,则应使用 PdfCopy
或 PdfSmartCopy
来执行此操作。如果你使用 PdfWriter
,你会丢掉很多信息(例如 link 注释)。
我需要将 N 个 PDF 文件合并为一个。我先创建一个空白文件
byte[] pdfBytes = null;
var ms = new MemoryStream();
var doc = new iTextSharp.text.Document();
var cWriter = new PdfCopy(doc, ms);
稍后我循环 html 字符串数组
foreach (NBElement htmlString in someElement.Children())
{
byte[] msTempDoc = getPdfDocFrom(htmlString.GetString(), cssString.GetString());
addPagesToPdf(cWriter, msTempDoc);
}
在 getPdfDocFrom 中,我使用 XMLWorkerHelper 创建 pdf 文件,return 它作为字节数组
private byte[] getPdfDocFrom(string htmlString, string cssString)
{
var tempMs = new MemoryStream();
byte[] tempMsBytes;
var tempDoc = new iTextSharp.text.Document();
var tempWriter = PdfWriter.GetInstance(tempDoc, tempMs);
tempDoc.Open();
using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(cssString)))
{
using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(htmlString)))
{
//Parse the HTML
iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(tempWriter, tempDoc, msHtml, msCss);
tempMsBytes = tempMs.ToArray();
}
}
tempDoc.Close();
return tempMsBytes;
}
稍后我尝试将此 PDF 文件中的页面添加到空白文件中。
private static void addPagesToPdf(PdfCopy mainDocWriter, byte[] sourceDocBytes)
{
using (var msOut = new MemoryStream())
{
PdfReader reader = new PdfReader(new MemoryStream(sourceDocBytes));
int n = reader.NumberOfPages;
PdfImportedPage page;
for (int i = 1; i <= n; i++)
{
page = mainDocWriter.GetImportedPage(reader, i);
mainDocWriter.AddPage(page);
}
}}
当它试图从我传递给函数的字节数组创建 PdfReader 时,它中断了。 "Rebuild failed: trailer not found.; Original message: PDF startxref not found."
我以前使用另一个库来处理 PDF。我将 2 个 PdfDocuments 作为对象传递,并循环地从一个页面添加到另一个页面。但是它不支持 Css,所以我不得不切换到 ITextSharp。
我不太明白 PdfWriter 和 PdfCopy 之间的区别。
您的代码中存在逻辑错误。当您像在 getPdfDocFrom()
方法中那样从头开始创建文档时,在您触发 Close()
方法之前文档是不完整的。在此 Close()
方法中,创建了预告片以及交叉引用 (xref) table。该错误告诉您缺少这些。
的确,你调用了Close()
方法:
tempDoc.Close();
但是当您 Close()
文档时,为时已晚:您已经创建了 tempMsBytes
数组。您需要在关闭文档后创建该数组。
编辑: 我对 C# 一无所知,但是如果 MemoryStream
在关闭后清除它的缓冲区,你可以使用 mainDocWriter.CloseStream = false;
这样关闭文档时 MemoryStream
并未关闭。
在 Java 中,将 "close stream" 参数设置为 false 是个坏主意。当我阅读问题 Create PDF in memory instead of physical file 的答案时,我发现 C# 可能并不总是需要这一行。
备注: 通过将 PdfImportedPage
个实例添加到 PdfWriter
来合并文件是一个低级趣味的例子。如果您使用的是 iTextSharp 5 或更早版本,则应使用 PdfCopy
或 PdfSmartCopy
来执行此操作。如果你使用 PdfWriter
,你会丢掉很多信息(例如 link 注释)。