在 MVC 中使用 itext7 合并 Crystal 报告从流中生成未合并的 pdf
Merging Crystal Reports with itext7 in MVC produces unmerged pdf from stream
我正在尝试在 ASP.net MVC 项目中合并两个(或更多)Crystal 报告,为此我下载了 itext7 NuGet 包。我正在尝试整理一个简单的概念验证,其中我使用一种方法将 pdf 与自身连接起来:
var rpt1 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
var rpt2 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
rpt1.Load(Server.MapPath("~/Reports/MyReport.rpt");
rpt2.Load(Server.MapPath("~/Reports/MyReport.rpt");
DataTable table = GetDataMethod();
rpt1.SetDataSource(table);
rpt2.SetDataSource(table);
Stream stream = rpt.ExportToStream(ExportFormatType.PortableDocFormat);
var write = new PdfWriter(stream);
var doc = new PdfDocument(write);
var merger = new PdfMerger(doc);
var doc1 = new PdfDocument(new PdfReader(rpt1.ExportToStream(ExportFormatType.PortableDocFormat)));
var doc2 = new PdfDocument(new PdfReader(rpt2.ExportToStream(ExportFormatType.PortableDocFormat)));
merger.Merge(doc1, 1, doc1.GetNumberOfPages());
merger.Merge(doc2, 1, doc2.GetNumberOfPages());
doc.CopyPagesTo(1, doc2.GetNumberOfPages(), doc2);
stream.Flush();
stream.Position = 0;
return this.File(stream, "application/pdf", "DownloadName.pdf");
你可以看到我有点把所有东西都扔到墙上,看看有什么东西在我同时使用 PdfMerger.Merger()
和 PdfDocument.CopyPagesTo()
的范围内,我认为其中任何一个都应该足够了自己完成工作? (而且,当然,我 运行 代码单独或一起尝试每个代码。)但是当我 运行 上面的代码时,下载的 PDF 未合并,即报告只出现一次. (如果我 运行 它有两个不同的报告,那么只会出现第一个报告。)
现在,我正在 return 播放流,同时我正在使用 PdfMerger
和 PdfDocument
对象做所有有趣的事情,所以对我来说有意义的是流将保持不变。但是我发现 return 流或字节数组(例如 )的所有使用 iText 7 的示例,所以这似乎是它应该工作的方式。
我对代码所做的任何更改要么无效、抛出错误,要么导致浏览器无法读取下载的文件(即无法识别为 PDF)。例如,我尝试将流转换为字节数组并 returning 那个:
using (var ms = new MemoryStream()) {
stream.CopyTo(ms);
byte[] bytes = ms.ToArray();
return new FileContentResult(bytes, "application/pdf");
}
但是当时浏览器打不开下载。当我尝试在 returning 流之前关闭 PdfDocument
时发生了同样的事情(试图强制它将合并写入流)。
您的代码中存在很多与流混淆的地方。通常,流用于输入或输出。 MemoryStream
两者都可以使用,但您需要确保不要关闭它以便能够重新使用它。使用底层字节创建新实例通常比重用现有字节更简单、更清晰,尤其是考虑到它不会对性能产生太大影响,因为底层重数组结构无论如何都会被新实例重用。这是您如何区分流的示例。 ExportToStream
returns 你可以从中获取包含 PDF 文件字节的字节数组的流,然后将这些文档加载到 iText 中,同时创建第三个文档,你将合并这两个源文件成。然后你必须确保调用 PdfDocument#Close()
告诉 iText 完成你的文档,然后你可以获取合并文档的结果字节并传递它们,必要时将它们包装成流
var rpt1 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
var rpt2 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
rpt1.Load(Server.MapPath("~/Reports/MyReport.rpt");
rpt2.Load(Server.MapPath("~/Reports/MyReport.rpt");
DataTable table = GetDataMethod();
rpt1.SetDataSource(table);
rpt2.SetDataSource(table);
var report1Stream = (MemoryStream)rpt1.ExportToStream(ExportFormatType.PortableDocFormat);
var report2Stream = (MemoryStream)rpt2.ExportToStream(ExportFormatType.PortableDocFormat);
var doc1 = new PdfDocument(new PdfReader(new MemoryStream(report1Stream.ToArray())));
var doc2 = new PdfDocument(new PdfReader(new MemoryStream(report2Stream.ToArray())));
var outStream = new MemoryStream();
var write = new PdfWriter(outStream);
var doc = new PdfDocument(write);
var merger = new PdfMerger(doc);
merger.Merge(doc1, 1, doc1.GetNumberOfPages());
merger.Merge(doc2, 1, doc2.GetNumberOfPages());
doc.Close();
doc1.Close();
doc2.Close();
return this.File(new MemoryStream(outStream.ToArray()), "application/pdf", "DownloadName.pdf");
我正在尝试在 ASP.net MVC 项目中合并两个(或更多)Crystal 报告,为此我下载了 itext7 NuGet 包。我正在尝试整理一个简单的概念验证,其中我使用一种方法将 pdf 与自身连接起来:
var rpt1 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
var rpt2 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
rpt1.Load(Server.MapPath("~/Reports/MyReport.rpt");
rpt2.Load(Server.MapPath("~/Reports/MyReport.rpt");
DataTable table = GetDataMethod();
rpt1.SetDataSource(table);
rpt2.SetDataSource(table);
Stream stream = rpt.ExportToStream(ExportFormatType.PortableDocFormat);
var write = new PdfWriter(stream);
var doc = new PdfDocument(write);
var merger = new PdfMerger(doc);
var doc1 = new PdfDocument(new PdfReader(rpt1.ExportToStream(ExportFormatType.PortableDocFormat)));
var doc2 = new PdfDocument(new PdfReader(rpt2.ExportToStream(ExportFormatType.PortableDocFormat)));
merger.Merge(doc1, 1, doc1.GetNumberOfPages());
merger.Merge(doc2, 1, doc2.GetNumberOfPages());
doc.CopyPagesTo(1, doc2.GetNumberOfPages(), doc2);
stream.Flush();
stream.Position = 0;
return this.File(stream, "application/pdf", "DownloadName.pdf");
你可以看到我有点把所有东西都扔到墙上,看看有什么东西在我同时使用 PdfMerger.Merger()
和 PdfDocument.CopyPagesTo()
的范围内,我认为其中任何一个都应该足够了自己完成工作? (而且,当然,我 运行 代码单独或一起尝试每个代码。)但是当我 运行 上面的代码时,下载的 PDF 未合并,即报告只出现一次. (如果我 运行 它有两个不同的报告,那么只会出现第一个报告。)
现在,我正在 return 播放流,同时我正在使用 PdfMerger
和 PdfDocument
对象做所有有趣的事情,所以对我来说有意义的是流将保持不变。但是我发现 return 流或字节数组(例如
我对代码所做的任何更改要么无效、抛出错误,要么导致浏览器无法读取下载的文件(即无法识别为 PDF)。例如,我尝试将流转换为字节数组并 returning 那个:
using (var ms = new MemoryStream()) {
stream.CopyTo(ms);
byte[] bytes = ms.ToArray();
return new FileContentResult(bytes, "application/pdf");
}
但是当时浏览器打不开下载。当我尝试在 returning 流之前关闭 PdfDocument
时发生了同样的事情(试图强制它将合并写入流)。
您的代码中存在很多与流混淆的地方。通常,流用于输入或输出。 MemoryStream
两者都可以使用,但您需要确保不要关闭它以便能够重新使用它。使用底层字节创建新实例通常比重用现有字节更简单、更清晰,尤其是考虑到它不会对性能产生太大影响,因为底层重数组结构无论如何都会被新实例重用。这是您如何区分流的示例。 ExportToStream
returns 你可以从中获取包含 PDF 文件字节的字节数组的流,然后将这些文档加载到 iText 中,同时创建第三个文档,你将合并这两个源文件成。然后你必须确保调用 PdfDocument#Close()
告诉 iText 完成你的文档,然后你可以获取合并文档的结果字节并传递它们,必要时将它们包装成流
var rpt1 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
var rpt2 = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
rpt1.Load(Server.MapPath("~/Reports/MyReport.rpt");
rpt2.Load(Server.MapPath("~/Reports/MyReport.rpt");
DataTable table = GetDataMethod();
rpt1.SetDataSource(table);
rpt2.SetDataSource(table);
var report1Stream = (MemoryStream)rpt1.ExportToStream(ExportFormatType.PortableDocFormat);
var report2Stream = (MemoryStream)rpt2.ExportToStream(ExportFormatType.PortableDocFormat);
var doc1 = new PdfDocument(new PdfReader(new MemoryStream(report1Stream.ToArray())));
var doc2 = new PdfDocument(new PdfReader(new MemoryStream(report2Stream.ToArray())));
var outStream = new MemoryStream();
var write = new PdfWriter(outStream);
var doc = new PdfDocument(write);
var merger = new PdfMerger(doc);
merger.Merge(doc1, 1, doc1.GetNumberOfPages());
merger.Merge(doc2, 1, doc2.GetNumberOfPages());
doc.Close();
doc1.Close();
doc2.Close();
return this.File(new MemoryStream(outStream.ToArray()), "application/pdf", "DownloadName.pdf");