c# - 来自预定义模板的多页 PDF 文档

标签 c# pdf .net-4.0 pdf-generation itextsharp

我需要使用一些预定义的公司模板生成 PDF 格式的发票报告。我能够使用 iTextSharp 创建/生成单页 PDF 报告。

问题:当发票声明跨越多页时,问题就来了。我无法将报告(发票报表)扩展到下一页(第二页)。如果一页无法写完所有数据,则应写在第二页,同时仍使用公司模板。

模板存在于以下路径:

HostingEnvironment.MapPath("~/Content/InvoiceTemplate/invoiceTemplate.pdf")

我正在使用 iTextSharp 库创建文档。以下是用于生成 PDF 的代码:

public class pdfStatementController : Controller {

        Models.DYNAMICS_EXTEntities _db = new Models.DYNAMICS_EXTEntities();

        //
        // GET: /pdfStatement/


        public ActionResult SendPdfStatement(string InvoiceNumber) {
            try {
                InvoiceNumber = InvoiceNumber.Trim();

                ObjectParameter[] parameters = new ObjectParameter[1];
                parameters[0] = new ObjectParameter("InvoiceNumber", InvoiceNumber);

                List<Models.Statement> statementList = new List<Models.Statement>();
                statementList = _db.ExecuteFunction<Models.Statement>("uspInvoiceStatement", parameters).ToList<Models.Statement>();
                pdfStatementController.WriteInTemplate(statementList);

                return RedirectToAction("Invoice", "Invoice", new { id = statementList.FirstOrDefault().Customer_ID.ToString().Trim() });
            } catch (Exception e) {
                return View("Error");
            }
        } 

    public static void WriteInTemplate(List<Models.Statement> statementList) {
        string invoiceNumber = statementList.FirstOrDefault().Invoice.ToString().Trim();
        string month = null;
        string day = null;
        string year = null;

        PdfReader pdfReader = new PdfReader(
                                  HostingEnvironment.MapPath(
                                       "~/Content/InvoiceTemplate/invoiceTemplate.pdf"));
        FileStream fileStream = new FileStream(
                                   HostingEnvironment.MapPath(
                                      "~/Content/reports/" + invoiceNumber + ".pdf"),
                                      FileMode.Create);
        PdfStamper pdfStamper = new PdfStamper(pdfReader, fileStream);
        AcroFields pdfFields = pdfStamper.AcroFields;

        pdfFields.SetField("BillToCompany", statementList.FirstOrDefault().BillToCompany.ToString().Trim().ToUpper());
        pdfFields.SetField("BillToContact", statementList.FirstOrDefault().BillToContact.ToString().Trim().ToUpper());
        pdfFields.SetField("CustomerId", statementList.FirstOrDefault().Customer_ID);
        pdfFields.SetField("InvoiceNumber", statementList.FirstOrDefault().Invoice.ToString().Trim());
        pdfFields.SetField("JobNumber", statementList.FirstOrDefault().JobNumber.ToString().Trim());
        pdfFields.SetField("Caller", statementList.FirstOrDefault().Caller.ToString().Trim());

        pdfStamper.FormFlattening = true; // generate a flat PDF 
        pdfStamper.Close();
        pdfReader.Close();
    }
}

最佳答案

您的代码看起来不错,只是缺少几个中间步骤。

由于您为每个页面使用相同的 PDF 模板(当需要生成两个或更多页面时),而不是使用 PdfStamper 将内容直接添加到 Document,您使用 PdfSmartCopyPdfCopy 对象。

PdfStamper 仍然需要。但是,在这种情况下,它用于在您迭代 Models.Statement 集合时创建一个充满数据的内存(单个)页面。

换句话说,PdfSmartCopy/PdfCopy 将您的语句作为一个整体(总页数)维护,PdfStamper 用作逐页添加您的单个语句的缓冲区-页面到您的 PDF。这是一个简单的工作示例 HTTP 处理程序 (.ashx):

<%@ WebHandler Language="C#" Class="copyFillTemplate" %>
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using iTextSharp.text;
using iTextSharp.text.pdf;

public class copyFillTemplate : IHttpHandler {
  public void ProcessRequest (HttpContext context) {
    HttpServerUtility Server = context.Server;
    HttpResponse Response = context.Response;
    Response.ContentType = "application/pdf";
// template used to test __this__ example;
// replace with __your__ PDF template
    string pdfTemplatePath = Server.MapPath(
      "~/app_data/template.pdf"
    );
// this example's test data; replace with __your__ data collection   
    List<Statement> statementList = Statement.GetStatements();

// COPY FROM HERE

    using (Document document = new Document()) {
// PdfSmartCopy reduces PDF file size by reusing parts
// of the PDF template, but uses more memory. you can
// replace PdfSmartCopy with PdfCopy if memory is an issue
      using (PdfSmartCopy copy = new PdfSmartCopy(
        document, Response.OutputStream)
      ) 
      {
        document.Open();
// used to test this example
        int counter = 0;
// generate one page per statement        
        foreach (Statement statment in statementList) {
          ++counter;
// replace this with your PDF form template          
          PdfReader reader = new PdfReader(pdfTemplatePath);
          using (var ms = new MemoryStream()) {
            using (PdfStamper stamper = new PdfStamper(reader, ms)) {
              AcroFields form = stamper.AcroFields;
// replace this with your field data for each page
              form.SetField("title", counter.ToString());
              stamper.FormFlattening = true;
            }
            reader = new PdfReader(ms.ToArray());
// add one page at a time; assumes your template is only one page.
// if your template is more than one page you will need to 
// call GetImportedPage() for each page in your template
            copy.AddPage(copy.GetImportedPage(reader, 1));
          }
        }
      }

// COPY TO HERE

    }
  }
  public bool IsReusable { get { return false; } }

  public class Statement {
    public string FieldName, FieldValue;
    public static List<Statement> GetStatements() {
      List<Statement> s = new List<Statement>();
      for (int i = 0; i < 5; ++i) {s.Add(new Statement());}
      return s;
    }
  }
}

希望行内评论有所帮助。你显然需要删除替换我用来测试示例代码的一些部分。

关于c# - 来自预定义模板的多页 PDF 文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8516631/

相关文章:

c# - 如何在不使用PrinterSettings的情况下更改打印机的纸张尺寸?

php - Laravel View 不适合 dompdf 生成的 pdf

python - 如何将多个 seaborn 图保存到同一个 pdf/png 文件?

pdf - 读取 MS Office 生成的 PDF 文件时出错

data-structures - 存储需要在.Net中大量查找的整数列表的最有效数据结构是什么?

c# - 使用关系更新数据表

c# - C# 中的 WinRT 数据虚拟化实现

c# - 条件 XAML (WPF)

c# - 静态方法与单例

.net - 什么是都柏林?它与 WCF 有何关系?