使用iTextSharp

时间:2015-11-26 16:26:53

标签: c# asp.net-mvc itextsharp razorpdf

我正在尝试使用iTextSharper制作带有页脚的PDF。在大多数情况下,这工作正常。我想在每个页面添加一个页脚。

我的代码确实正确地添加了页脚,但是,正如您在图像中看到的那样,文本与PDF的内容重叠: pdf

控制器操作:

public ActionResult GeneratePDF(int id)
{
    Order order = db.Orders.Where(x => x.ID == id).SingleOrDefault();
    return new HFPdfResult(order, "OrderPDF");
}

HFPdfResult(ViewResult)类:

using System.Web.Mvc;
using RentproDC.Models.RazorPDF;

namespace RentproDC.Models.RazorPDF
{
    public class HFPdfResult : ViewResult
    {
        //Constructors
        public HFPdfResult(object model, string name)
        {
            ViewData = new ViewDataDictionary(model);
            ViewName = name;
        }

        public HFPdfResult() : this(new ViewDataDictionary(), "Pdf")
        {
        }

        public HFPdfResult(object model) : this(model, "Pdf")
        {
        }

        //Override FindView to load PdfView
        protected override ViewEngineResult FindView(ControllerContext context)
        {
            var result = base.FindView(context);
            if (result.View == null)
                return result;

            var pdfView = new HFPdfView(result);
            return new ViewEngineResult(pdfView, pdfView);
        }
    }
}

HFPdfView类:

using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Web.Mvc;
using System.Xml;
using iTextSharp.text;
using iTextSharp.text.html;
using iTextSharp.text.pdf;
using iTextSharp.text.xml;
using iTextSharp.text.html.simpleparser;
using System.Collections.Generic;

namespace RentproDC.Models.RazorPDF
{
    public class HFPdfView : IView, IViewEngine
    {
        private readonly ViewEngineResult _result;

        public HFPdfView(ViewEngineResult result)
        {
            _result = result;
        }

        public void Render(ViewContext viewContext, TextWriter writer)
        {
            // generate view into string
            var sb = new System.Text.StringBuilder();
            TextWriter tw = new System.IO.StringWriter(sb);
            _result.View.Render(viewContext, tw);
            var resultCache = sb.ToString();

            // detect itext (or html) format of response
            XmlParser parser;
            using (var reader = GetXmlReader(resultCache))
            {
                while (reader.Read() && reader.NodeType != XmlNodeType.Element)
                {
                    // no-op
                }

                if (reader.NodeType == XmlNodeType.Element && reader.Name == "itext")
                    parser = new XmlParser();
                else
                    parser = new HtmlParser();
            }

            // Create a document processing context
            var document = new Document(PageSize.A4, 36, 36, 36, 120);
            document.Header = new HeaderFooter(new Phrase("Test header"), false);
            document.Open();

            // associate output with response stream
            var pdfWriter = PdfWriter.GetInstance(document, viewContext.HttpContext.Response.OutputStream);
            pdfWriter.PageEvent = new PdfFileEvents();
            pdfWriter.CloseStream = false;

            // this is as close as we can get to being "success" before writing output
            // so set the content type now
            viewContext.HttpContext.Response.ContentType = "application/pdf";

            // parse memory through document into output
            using (var reader = GetXmlReader(resultCache))
            {
                parser.Go(document, reader);
            }

            pdfWriter.Close();
        }

        private static XmlTextReader GetXmlReader(string source)
        {
            byte[] byteArray = Encoding.UTF8.GetBytes(source);
            MemoryStream stream = new MemoryStream(byteArray);

            var xtr = new XmlTextReader(stream);
            xtr.WhitespaceHandling = WhitespaceHandling.None; // Helps iTextSharp parse 
            return xtr;
        }

        public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName,
            bool useCache)
        {
            throw new System.NotImplementedException();
        }

        public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName,
            bool useCache)
        {
            throw new System.NotImplementedException();
        }

        public void ReleaseView(ControllerContext controllerContext, IView view)
        {
            _result.ViewEngine.ReleaseView(controllerContext, _result.View);
        }
    }

    public class PdfFileEvents : PdfPageEventHelper
    {
        public override void OnEndPage(PdfWriter pi, Document doc)
        {
            PdfContentByte cb = pi.DirectContent;
            ColumnText ct = new ColumnText(cb);

            List list = new List(List.ORDERED);
            string text = "<ol><li><span style='color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 16.12px; orphans: auto; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; display: inline !important; float: none; background-color: rgb(255, 255, 255); font-size: 9px;'>"+RentProModels.Models.Settings.Get("CompanyName") + "<br />" + RentProModels.Models.Settings.Get("CompanyTelephone") + "<br />" +
                RentProModels.Models.Settings.Get("CompanyEmail") + "<br />" + 
                "KVK " + "1234568789" + "<br />" +
                "Bank ABN01Blahh12341</span></li></ol>";
            ArrayList htmlarraylist = HTMLWorker.ParseToList(new StringReader(text), null);
            for (int k = 0; k < htmlarraylist.Count; k++)
            {
                list.Add((IElement)htmlarraylist[k]);
            }
            ct.AddElement(list);
            ct.SetSimpleColumn(500, 79, 900, 5); //curPos = verder naar boven
            ct.Go();
        }

        public override void OnStartPage(PdfWriter pi, Document doc)
        {
            PdfContentByte cb = pi.DirectContent;
            ColumnText ct = new ColumnText(cb);

            cb.BeginText();
            cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 12.0f);
            cb.SetTextMatrix(doc.LeftMargin, doc.PageSize.Height - doc.TopMargin);
            cb.ShowText(String.Format("{0} {1}", "Dit is een", "Header"));
            cb.EndText();
        }

    }
}

订单视图(它将Order对象加载到此视图中,并根据该视图生成PDF):

@model RentPro.Models.Tables.Order
@using RentProModels.Models
@using RentPro.Models.Tables
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
<body style="font-size: 12px;">
    <table width="100%" widths="60;40">
        <row>
            <td>
                <newline />
                <newline />
                <h2 style="text-decoration:underline;">Pakbon</h2>
            </td>
            <td>
                @*                <img url="@System.Web.Hosting.HostingEnvironment.MapPath("/")@Settings.Get("PicturesPath") /../Images/@Settings.Get("LogoFile")" width="239" height="83" />*@
                <newline />
                <newline />
            </td>
        </row>
    </table>
    <table width="100%" cellpadding="0.0" widths="50;17;30">
        @if (@Model.Delivery.Company != "nvt")
        {
            <row>
                <cell>
                    <p style="font-weight:bold;">@Model.Delivery.Company</p>
                </cell>
                <cell></cell>
                <cell></cell>
            </row>
        }
        <row>
            <cell><p style="font-weight:bold;">@Model.Delivery.FirstName @Model.Delivery.LastName</p></cell>
            <cell>Order Nr:</cell>
            <cell>@Model.ID</cell>
        </row>
        <row>
            <cell><p style="font-weight:bold;">@Model.Delivery.StreetName @Model.Delivery.HouseNumber</p></cell>
            <cell>Order Datum:</cell>
            <cell>@Model.PlaceDate.ToShortDateString()</cell>
        </row>
        <row>
            <cell><p style="font-weight:bold;">@Model.Delivery.ZipCode, @Model.Delivery.City</p></cell>
            <cell>Transport:</cell>
            <cell>@Model.TransportCarrier.Name</cell>
        </row>
        <row>
            <cell><p style="font-weight:bold;">@Model.Phonenumber</p></cell>
            <cell>Start Datum:</cell>
            <cell>@Model.StartDate.ToShortDateString()</cell>
        </row>
        <row>
            @{  string KVKofBTW;
              if (Model.KVKnummer != null && Model.KVKnummer != "")
              {
                  if (Model.Billing.Country.Name == "Nederland")
                  {
                      KVKofBTW = "KVK:";
                  }
                  else
                  {
                      KVKofBTW = "BTW:";
                  }
              }
              else
              {
                  KVKofBTW = "";
              }
            }
            <cell><p style="font-weight:bold;">@KVKofBTW @Model.KVKnummer</p></cell>
            <cell>Eind Datum:</cell>
            <cell>@Model.EndDate.ToShortDateString()</cell>
        </row>
        <row>
            <cell></cell>
            <cell>Aantal Dagen:</cell>
            <cell>@((Model.EndDate.Date - Model.StartDate.Date).Days + 1)</cell>
        </row>
        <row>
            <cell>Opmerkingen:</cell>
            <cell></cell>
            <cell></cell>
        </row>
        <row>
            <cell colspan="3">@Model.Note</cell>
        </row>
    </table>
    <table width="100%" widths="10;60" cellpadding="2">
        <row>
            <cell>
                <newline />
            </cell>
            <cell></cell>
        </row>
        <row>
            <cell><p style="font-style:italic;">Aantal</p></cell>
            <cell><p style="font-style:italic;">Artikel</p></cell>
        </row>
        @foreach (var item in Model.Items)
        {
            <row>
                <cell>@item.ProductCode</cell>
                <cell>@item.Amount</cell>
                <cell>@item.ProductTitle</cell>
                <cell>    [  ]</cell>
                <cell>    [  ]</cell>
                <cell>    [  ]</cell>
            </row>
            if (RentProModels.Models.Settings.GetBool("PakBonAccessory"))
            {
                foreach (RentPro.Models.Tables.Accessory accesory in item.Product.Accessories)
                {
                    <row>
                        <cell></cell>
                        <cell></cell>
                        <cell>@accesory.Name</cell>
                        <cell>    [  ]</cell>
                        <cell>    [  ]</cell>
                        <cell>    [  ]</cell>
                    </row>
                }

            }

        }
    </table>
    <table width="100%" widths="60;50">
        <row>
            <cell>
                <newline />
                <newline />
                <newline />
                <newline />
                <newline />
                <newline />
            </cell>
            <cell></cell>
        </row>
        <row>
            <cell>Handtekening voor ontvangst:</cell>
            <cell>Retour ontvangen door:</cell>
        </row>
        <row>
            <cell>Naam Klant:</cell>
            <cell>Naam:</cell>
        </row>
        <row>
            <cell>Handtekening:</cell>
            <cell>Handtekening:</cell>
        </row>
    </table>
</body>
</html>

我看到一篇关于设置文档大小的SO帖子,我这样做,但它似乎不起作用:

var document = new Document(PageSize.A4, 36, 36, 36, 120);

我在底部给了它120个用户单位的边距,我只使用110,为什么它仍然重叠?

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

经过一番捣乱后我决定更新我的项目以使用更新版本的iTextSharp确实是最好的。

我完全摆脱了RazorPDF库,现在正在使用iTS 5.5.8。我以为我会分享我的更新代码,因为每个人都遇到过这个问题。

这也解决了我的OP中关于页脚与PDF内容重叠的问题。

新代码:

public class RazorPdf
{
    public static byte[] GeneratePdf(string html,
        System.Collections.Generic.List<PdfPageContent> headerAndFooterContent = null)
    {
        Byte[] bytes;
        using (var ms = new MemoryStream())
        {
            using (var doc = new Document(PageSize.A4, 40f, 40f, 30f, 50f))
            {
                using (var writer = PdfWriter.GetInstance(doc, ms))
                {
                    doc.Open();
                    var example_css = @".headline{font-size:200%}"; //incase you want to parse css
                    writer.PageEvent = new PageEventHelper(headerAndFooterContent);
                    using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_css)))
                    {
                        using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(html)))
                        {
                            iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHtml, msCss);
                        }
                    }

                    doc.Close();
                }
            }
            bytes = ms.ToArray();
        }
        return bytes;
    }
}

public class PageEventHelper : PdfPageEventHelper
{
    private PdfContentByte _cb;
    private PdfTemplate _template;

    private readonly System.Collections.Generic.List<PdfPageContent> _content = null;

    public PageEventHelper(System.Collections.Generic.List<PdfPageContent> content)
    {
        _content = content;
    }

    public override void OnOpenDocument(PdfWriter writer, Document document)
    {
        _cb = writer.DirectContent;
        _template = _cb.CreateTemplate(50, 50);
    }

    public override void OnEndPage(PdfWriter writer, Document document)
    {
        base.OnEndPage(writer, document);

        /* Contents */
        if (_content != null)
        {
            foreach (PdfPageContent ppc in _content)
            {
                ColumnText ct = new ColumnText(GetCb(writer));
                Phrase phrase = new Phrase(new Chunk(ppc.Content, FontFactory.GetFont(FontFactory.HELVETICA, 12, Font.NORMAL)));
                switch (ppc.Location)
                {
                    case PdfPageLocation.Header:
                        ct.SetSimpleColumn(phrase, 40, 700, 530, 840, 25, ppc.Alignment);
                        break;
                    case PdfPageLocation.Footer:
                        ct.SetSimpleColumn(phrase, 40, 100, 530, 20, 25, ppc.Alignment);
                        break;
                }
                ct.Go();
            }
        }

        /* Page number */
        string text = writer.PageNumber.ToString();
        BaseFont font = BaseFont.CreateFont();
        float len = font.GetWidthPoint(text, 12);

        Rectangle pageSize = document.PageSize;

        GetCb(writer).SetRGBColorFill(100, 100, 100);

        GetCb(writer).BeginText();
        GetCb(writer).SetFontAndSize(font, 12);
        GetCb(writer).SetTextMatrix(document.RightMargin, pageSize.GetBottom(document.BottomMargin));
        GetCb(writer).ShowText(text);
        GetCb(writer).EndText();

        GetCb(writer).AddTemplate(GetTemplate(writer), document.RightMargin - len, 0);
    }

    private PdfContentByte GetCb(PdfWriter writer)
    {
        return _cb ?? (_cb = writer.DirectContent);
    }

    private PdfTemplate GetTemplate(PdfWriter writer)
    {
        return _template ?? (_template = GetCb(writer).CreateTemplate(50, 50));
    }
}

public class PdfPageContent
{
    public PdfPageLocation Location { get; set; }
    public int Alignment { get; set; }
    public string Content { get; set; }
}

public enum PdfPageLocation
{
    Footer = 1,
    Header = 2
}

ControllerExtension:

    public class Controller : System.Web.Mvc.Controller
    {
        public FileContentResult PdfFileResult(string viewPath, object model = null)
        {
            List<PdfPageContent> content = new List<PdfPageContent>();
            content.Add(new PdfPageContent() { Location = PdfPageLocation.Footer, Alignment = Element.ALIGN_LEFT, Content = "FOOTER LEFT" });
            content.Add(new PdfPageContent() { Location = PdfPageLocation.Footer, Alignment = Element.ALIGN_RIGHT, Content = "FOOTER RIGHT" });
            content.Add(new PdfPageContent() { Location = PdfPageLocation.Header, Alignment = Element.ALIGN_LEFT, Content = "HEADER LEFT" });
            content.Add(new PdfPageContent() { Location = PdfPageLocation.Header, Alignment = Element.ALIGN_RIGHT, Content = "HEADER RIGHT" });
            return new FileContentResult(RazorPdf.GeneratePdf(RenderViewToString(viewPath, model), content), "application/pdf");

        }

        public bool SavePdfFileResult(string viewPath, string relativeFilePath, object model = null)
        {
            byte[] data = RazorPdf.GeneratePdf(RenderViewToString(viewPath, model));
            if (!string.IsNullOrWhiteSpace(relativeFilePath))
            {
                try
                {
                    System.IO.File.WriteAllBytes(Server.MapPath(relativeFilePath), data);
                }
                catch (Exception e)
                { //In case of exception, file write has failed
                    return false;
                }
                return true;
            }
            return false;
        }

        public string RenderViewToString(string viewPath, object model = null, bool partial = false)
        {
            ViewEngineResult viewEngineResult = partial ? ViewEngines.Engines.FindPartialView(ControllerContext, viewPath) :
                ViewEngines.Engines.FindView(ControllerContext, viewPath, null);

            if (viewEngineResult == null)
                throw new FileNotFoundException("View cannot be found.");

            var view = viewEngineResult.View;
            ControllerContext.Controller.ViewData.Model = model;

            string result = null;

            using (var sw = new StringWriter())
            {
                var ctx = new ViewContext(ControllerContext, view, ControllerContext.Controller.ViewData, ControllerContext.Controller.TempData, sw);
                view.Render(ctx, sw);
                result = sw.ToString();
            }
            return result;
        }
    }

控制器中的用法:

    public ActionResult GeneratePDF(int id)
    {
        Order order = db.Orders.SingleOrDefault(x => x.ID == id);
        return PdfFileResult("/Views/Order/OrderPDF.cshtml", order);
    }