【问题标题】:Multipage PDF document from predefined template来自预定义模板的多页 PDF 文档
【发布时间】:2012-01-20 22:40:26
【问题描述】:

我需要使用一些预定义的公司模板生成 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();
    }
}

【问题讨论】:

  • 您是对每个页面重复使用 same 模板,还是对第二个页面使用 不同 模板?
  • 我对每个页面都使用相同的模板。

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


【解决方案1】:

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

由于您为每个页面使用相同的 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;
    }
  }
}

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

【讨论】:

  • 只有一个问题:当我调用方法 public void ProcessRequest (HttpContext context) 时,我应该为 context 传递什么;你能粘贴调用这个方法的方法吗?
  • ProcessRequest 特定于实现IHttpHandler 接口的HTTP 处理程序(.ashx)。因此,如果您没有通过 HTTP 处理程序在 Web 上下文中提供 PDF,则您不能调用此方法。只需使用上面的部分,包括using (Document document... 块/语句。如果您正在运行 Windows 窗体/桌面应用程序,则需要将 Response.OutputStream 替换为 FileStream
  • 作为 .NET 的初学者,无法理解您上面的评论。我只在网络应用程序中使用它。我已经编辑了我的代码,以提供有关我的应用程序的更多详细信息。我正在使用 MVC3,所以我的类继承了控制器类。我知道您的代码可以为我工作,只需将各个部分放在一起。 Helo 我在这里找出 hhtp 上下文对象
  • 我可以做到...@kuujinbo 你是个明星,非常感谢你的回答...... 5 星给你的回答,再次感谢。 :)
  • 没问题,每个人都曾经是初学者 :) 问题是我不做 MVC3(或根本不做 MVC)。我编辑了上面的代码示例,将 COPY FROM HERE 之间的部分复制到 COPY TO HERE 并将其放入您的 WriteInTemplate 方法中。此外,进行内联 cmets 中注明的替换。 (您可能需要尝试一下)您不需要复制上面的整个ProcessRequest 方法。
【解决方案2】:

虽然最后一个答案非常好,帮助我解决了我的问题,但我把它放在这里是为了总结问题。

问题:我有一个场景是在公司提供的模板中生成多页 pdf 文档。需要通过 Microsoft Outlook 电子邮件客户端生成发票报表并将其附加到电子邮件中。

我使用 MVC3、ASP.NET 4.0、实体框架

解决方案:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Hosting;
using System.Web.Mvc;
using System.Data;
using System.Data.Objects;
using System.IO;
using iTextSharp;
using iTextSharp.text;
using iTextSharp.text.html;
using iTextSharp.text.pdf;
using iTextSharp.text.xml;

namespace InvoiceSearchTool.Controllers

{


 public class pdfStatementController : Controller
{
    Models.DYNAMICS_EXTEntities _db = new Models.DYNAMICS_EXTEntities();
    //
    // GET: /pdfStatement/

    public ActionResult SendPdfStatement(string InvoiceNumber)
    {
        try
        {

            InvoiceNumber = InvoiceNumber.Trim();


            List<Models.Statement> statementList = new List<Models.Statement>();
            //this is if you use entity framework
            {  
               ObjectParameter[] parameters = new ObjectParameter[1];
            parameters[0] = new ObjectParameter("InvoiceNumber", InvoiceNumber);

               statementList = _db.ExecuteFunction<Models.Statement>("uspInvoiceStatement", parameters).ToList<Models.Statement>();
             }

            //others can simply use line like
            //statementList = GetStatementList(inviceNumber);

            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)
    {

        try

        {

            string invoiceNumber = statementList.FirstOrDefault().Invoice.ToString().Trim();

            using (Document document = new Document())
            {
                FileStream fileStream = new FileStream(HostingEnvironment.MapPath("~/Content/reports/" + invoiceNumber + ".pdf"), FileMode.Create);
                using (PdfSmartCopy smartCopy = new PdfSmartCopy(document, fileStream))
                {
                    document.Open();

                    PdfReader pdfReader = new PdfReader(HostingEnvironment.MapPath("~/Content/InvoiceTemplate/invoiceTemplate.pdf"));
                            using (var memoryStream = new MemoryStream())
                            {
                                using (PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream))
                                {
                                    string month = null;
                                    string day = null;
                                    string year = null;

                                    AcroFields pdfFields = pdfStamper.AcroFields;
                                    {//billing address
                                        pdfFields.SetField("BillToCompany", statementList.FirstOrDefault().BillToCompany.ToString().Trim().ToUpper());
                                        pdfFields.SetField("BillToContact", statementList.FirstOrDefault().BillToContact.ToString().Trim().ToUpper());

                                        pdfFields.SetField("ShipToCompany", statementList.FirstOrDefault().ShipToCompany.ToString().Trim().ToUpper());
                                        pdfFields.SetField("ShipToContact", statementList.FirstOrDefault().ShipToContact.ToString().Trim().ToUpper());
                                        pdfFields.SetField("PONumber", statementList.FirstOrDefault().PurchaseOrderNo.ToString().Trim());
                                        pdfFields.SetField("OrderNumber", statementList.FirstOrDefault().Order_Number.ToString().Trim());
                                        pdfFields.SetField("ShippingMethod", statementList.FirstOrDefault().Shipping_Method.ToString().Trim());
                                        pdfFields.SetField("PaymentTerms", statementList.FirstOrDefault().Payment_Terms.ToString().Trim());
                                   }
                                   pdfStamper.FormFlattening = true; // generate a flat PDF 

                                }
                                pdfReader = new PdfReader(memoryStream.ToArray());
                                smartCopy.AddPage(smartCopy.GetImportedPage(pdfReader, 1));
                            }
                }
            }

            emailController.CreateMessageWithAttachment(invoiceNumber);
        }
        catch (Exception e)
        {
        }

    }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Net;
using System.Net.Mail;
using System.Web.Hosting;
using System.Net.NetworkInformation;
using System.Data.Objects;

namespace InvoiceSearchTool.Controllers
{


 public class emailController : Controller

 {
    //
    // GET: /email/
    public static void CreateMessageWithAttachment(string invoiceNumber)
    {
        try
        {
            Outlook.Application oApp = new Outlook.Application();
            Outlook.MailItem email = (Outlook.MailItem)(oApp.CreateItem(Outlook.OlItemType.olMailItem));

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

            string recipient = null;
            string messageBody = null;
            #region set email recipients
            {
                ObjectParameter[] parameters = new ObjectParameter[1];
                parameters[0] = new ObjectParameter("InvoiceNumber", invoiceNumber);

                List<Models.EmailAddress> emailList = _db.ExecuteFunction<Models.EmailAddress>("uspGetEmailAddress", parameters).ToList<Models.EmailAddress>();
                if(!string.IsNullOrEmpty(emailList[0].Email.ToString()))
                    recipient = emailList[0].Email.ToString().Trim();
                else
                    recipient = " ";
                email.Recipients.Add(recipient);
            }
            #endregion

            //email subject                 
            email.Subject = "Invoice # " + invoiceNumber;

            #region set email Text
            {
                Models.EmailText emailText = _db.ExecuteFunction<Models.EmailText>("uspEmailText").SingleOrDefault();

                messageBody = emailText.EmailTextLine1.ToString().Trim() + "\n\n\n\n\n\n\n\n\n";
                messageBody += emailText.EmailTextLine2.ToString().Trim() + "\n";
                messageBody += emailText.EmailTextLine3.ToString().Trim();

                email.Body = messageBody;
            }
            #endregion

            #region email attachment
            {
                string fileName = invoiceNumber.Trim();
                string filePath = HostingEnvironment.MapPath("~/Content/reports/");
                filePath = filePath + fileName + ".pdf";
                fileName += ".pdf";
                int iPosition = (int)email.Body.Length + 1;
                int iAttachType = (int)Outlook.OlAttachmentType.olByValue;
                Outlook.Attachment oAttach = email.Attachments.Add(filePath, iAttachType, iPosition, fileName);
            }
            #endregion

            email.Display();
            //uncomment below line to SendAutomatedEmail emails atomaticallly
            //((Outlook.MailItem)email).Send(); 
        }
        catch (Exception e)
        {

        }

    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-15
    • 2018-10-07
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多