我正在尝试使用iTextSharper制作带有页脚的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,为什么它仍然重叠?
非常感谢任何帮助。
答案 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);
}