简体   繁体   English

使用iTextSharp的页脚与PDF内容重叠

[英]Footer overlapping with PDF content using iTextSharp

I'm trying to make a PDF with a footer on it using iTextSharper. 我正在尝试使用iTextSharper制作带有页脚的PDF。 This is working fine, for the most part. 在大多数情况下,这工作正常。 I want to add a footer to each page. 我想在每个页面上添加页脚。

My code does add the footer correctly, however, the text is overlapping with the content of the PDF as you can see in the image: 我的代码确实正确添加了页脚,但是,如您在图像中所见,文本与PDF的内容重叠: pdf格式

The controller action: 控制器动作:

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

The HFPdfResult ( ViewResult ) class: 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);
        }
    }
}

The HFPdfView class: 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 view (it loads the Order object into this view, and generates a PDF based on that): 订单视图(它将“ 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>

I saw a SO post about setting the document's size, I do that, but it doesn't seem to work: 我看到了一篇关于设置文档大小的文章,我这样做了,但是似乎不起作用:

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

I gave it a margin of 120 user units on the bottom side, and I only use 110 so why is it still overlapping? 我在底部给了它120个用户单元的余量,而我只使用110个,为什么它仍然重叠?

Any help would be greatly appreciated. 任何帮助将不胜感激。

After some messing around I decided that it was indeed best to update my project to use a more recent version of iTextSharp. 经过一番混乱之后,我认为确实最好将项目更新为使用最新版本的iTextSharp。

I've completely gotten rid of the RazorPDF library and now work with iTS 5.5.8. 我已经完全摆脱了RazorPDF库,现在可以使用iTS 5.5.8。 I thought I'd share my updated code incase everyone ever runs into this problem. 我以为我会分享我的更新代码,以防每个人都遇到这个问题。

This has also fixed the problem in my OP about the footer overlapping with the PDF content. 这也解决了我的OP中有关页脚与PDF内容重叠的问题。

New code: 新代码:

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: 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;
        }
    }

Usage in controller: 控制器中的用法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM