我使用iTextSharp和XMLWorker 5.5.12将HTML转换为PDF,我需要生成页眉,页脚和正文内容。
我能够使用页面事件生成所有文本,当我尝试在正文和页面事件中插入图像时,只要我在parser.Parse(reader);
行抛出错误{{ 1}}。
这是我到目前为止的代码:
Cannot access a closed Stream.
这是Page Event的代码:
protected ActionResult ViewPdf(string viewName, object model, ViewDataDictionary viewData = null,
iTextSharp.text.Rectangle size = null,
float marginLeft = 10f, float marginRight = 10f,
float marginTop = 10f, float marginBottom = 10f,
IEnumerable<PDFFragmentBaseViewModel> fragments = null)
{
if (size == null) size = iTextSharp.text.PageSize.LETTER;
using (iTextSharp.text.Document document = new iTextSharp.text.Document(size, marginLeft, marginRight, marginTop, marginBottom))
{
using (var outStream = new MemoryStream())
{
PdfWriter writer = PdfWriter.GetInstance(document, outStream);
writer.CloseStream = false;
// page event
//if (pageEvent != null)
// writer.PageEvent = pageEvent;
// css
ICSSResolver cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
//if (cssPath != null)
// cssResolver.AddCssFile(cssPath, true);
//Register Image Procesor
var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
tagProcessorFactory.AddProcessor(new ResourceImageHtmlTagProcessor(), new[] { "resimg" });
// html
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.SetTagFactory(tagProcessorFactory);
// pipelines
PdfWriterPipeline pdfPipeline = new PdfWriterPipeline(document, writer);
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, pdfPipeline);
CssResolverPipeline cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
// parse
XMLWorker worker = new XMLWorker(cssPipeline, true);
XMLParser parser = new XMLParser(worker);
writer.CloseStream = false;
List<PDFFragmentViewModel> _frags = null;
if (fragments != null)
{
_frags = new List<PDFFragmentViewModel>();
foreach (var frag in fragments)
{
_frags.Add(new PDFFragmentViewModel {
Content = REC0Utils.RenderRazorViewToString(frag.ViewName, ControllerContext, new object { }, viewData ?? ViewData),
Alignment = frag.Alignment,
Leading = frag.Leading,
LLX = frag.LLX,
LLY = frag.LLY,
URX = frag.URX,
URY = frag.URY
});
}
//string htmlHeader = "<!DOCTYPE html><html><body><table style=\"width: 100%; border: 1px solid black;\"><tr><td>A</td><td>B</td></tr></table></body></html>";
//string htmlHeader = REC0Utils.RenderRazorViewToString(headerViewName, ControllerContext, headerModel, viewData ?? ViewData);
writer.PageEvent = new HtmlPageEventHelper(_frags);
}
document.Open();
// Render the view xml to a string, then parse that string into an XML dom.
string xmltext = REC0Utils.RenderRazorViewToString(viewName, this.ControllerContext, model, viewData == null ? ViewData : viewData);
using (var reader = new StringReader(xmltext))
{
parser.Parse(reader);
}
// Close and get the resulted binary data.
document.Close();
// Send the binary data to the browser.
return new BinaryContentResult(outStream.ToArray(), "application/pdf");
}
}
// Parse the XML into the iTextSharp document.
//TextReader reader = new StringReader(xmltext);
//XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, reader);
//XMLParser textHandler = new XMLParser(doc);
//textHandler.Parse(xmldoc);
}
我一直在调查,我在某处找到了删除public class HtmlPageEventHelper : PdfPageEventHelper
{
List<PDFFragmentViewModel> _fragments;
public HtmlPageEventHelper(List<PDFFragmentViewModel> fragments)
{
this._fragments = fragments;
}
public override void OnEndPage(PdfWriter writer, iTextSharp.text.Document document)
{
base.OnEndPage(writer, document);
var _instance = XMLWorkerHelper.GetInstance();
// css
ICSSResolver cssResolver = _instance.GetDefaultCssResolver(false);
//Register Image Procesor
var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
tagProcessorFactory.AddProcessor(new ResourceImageHtmlTagProcessor(), new[] { "resimg" });
// html
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.SetTagFactory(tagProcessorFactory);
// pipelines
PdfWriterPipeline pdfPipeline = new PdfWriterPipeline(document, writer);
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, pdfPipeline);
CssResolverPipeline cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
// parse
XMLWorker worker = new XMLWorker(cssPipeline, true);
XMLParser parser = new XMLParser(worker);
foreach (var _frag in _fragments)
{
ColumnText ct = new ColumnText(writer.DirectContent);
//using (var reader = new StringReader(_frag.Content))
//{
// parser.Parse(reader);
//}
_instance.ParseXHtml(new ColumnTextElementHandler(ct), new StringReader(_frag.Content));
//ct.SetSimpleColumn(document.Left, document.Top, document.Right, document.GetTop(-20), 10, Element.ALIGN_MIDDLE);
ct.SetSimpleColumn(
_frag.LLX.HasValue ? document.GetLeft(_frag.LLX.Value) : document.Left,
_frag.LLY.HasValue ? document.GetTop(_frag.LLY.Value) : document.Top,
_frag.URX.HasValue ? document.GetRight(_frag.URX.Value) : document.Right,
_frag.URY.HasValue ? document.GetBottom(_frag.URY.Value) : document.Bottom,
_frag.Leading, _frag.Alignment);
ct.Go();
}
}
}
语句的建议,当我删除它们时,我得到了一个不同的错误:
using
任何人都可以对此有所了解吗?
更新
根据评论的要求,这是Can not find own context
错误的堆栈跟踪。
Can not find own context
这是内部异常的堆栈跟踪:
at iTextSharp.tool.xml.XMLWorker.EndElement(String tag, String ns)
at iTextSharp.tool.xml.parser.XMLParser.EndElement()
at iTextSharp.tool.xml.parser.state.ClosingTagState.Process(Char character)
at iTextSharp.tool.xml.parser.XMLParser.ParseWithReader(TextReader reader)
at iTextSharp.tool.xml.parser.XMLParser.Parse(TextReader reader)
at MvcREC0.WebUI.Controllers.BaseController.ViewPdf(String viewName, Object model, ViewDataDictionary viewData, Rectangle size, Single marginLeft, Single marginRight, Single marginTop, Single marginBottom, IEnumerable`1 fragments) in C:\Pr0g\MVCRec0\WebUI\Controllers\BaseController.cs:line 225
at MvcREC0.WebUI.Controllers.Crudere`6.<Index>d__8.MoveNext() in C:\Pr0g\MVCRec0\WebUI\Controllers\Cruder.cs:line 688
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<BeginInvokeAsynchronousActionMethod>b__36(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<>c__DisplayClass2b.<BeginInvokeAction>b__1c()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
at System.Web.HttpApplication.CallHandlerExecutionStep.InvokeEndHandler(IAsyncResult ar)
at System.Web.HttpApplication.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar)
答案 0 :(得分:2)
确实,XMLWorker
架构不支持您尝试执行的操作。 (我实际上对此感到有些惊讶;我想我甚至在此处或之前的一些评论声称它应该有用。)
XMLWorker
体系结构不允许来自同一线程的重叠使用。但它确实允许在任何线程情况下来自不同线程和非重叠用法的重叠使用。
由于您的页眉和页脚似乎不依赖于实际的页面内容,我建议您切换到两遍过程:在第一个过程中使用Document
和a创建文档正文PdfWriter
如上所述,仅仅没有事件监听器;在第二次传递中使用PdfReader
和PdfStamper
将页眉和页脚标记在其上。或者,您可以尝试在本答复结尾处发布的解决方法。
XMLWorker
为context
数据槽(在Thread
中的Java中)保留当前解析操作的ThreadLocal
。
当前线程中context
的内容在XMLParser.ParseWithReader
开始时初始化,当前线程的整个context
在其末尾被删除。
方法XMLParser.ParseWithReader
最终会被每个XMLParser.Parse
重载使用,也会被每个XMLWorkerHelper.parseXHtml
重载使用。
只要两次解析尝试使用XMLWorker
架构 - 例如解析页面事件监听器中的尝试和填充正文的解析尝试(除非后者明显限于单个页面) - 重叠,因此,它们相互进入并且尝试完成首先删除上下文另一方使用。
这个问题有一个解决方法,至少对于像手头那样的情况,如果可以使用反射,并且运行时环境允许:
每当切换到另一次尝试时,可以存储当前的context
值并将其替换为适合解析的值。当context
被声明为private
时,这需要反思。
在手头的情况下将是:
public class HtmlPageEventHelper : PdfPageEventHelper
{
List<PDFFragmentViewModel> _fragments;
FieldInfo context;
public HtmlPageEventHelper(List<PDFFragmentViewModel> fragments)
{
this._fragments = fragments;
context = typeof(XMLWorker).GetField("context", BindingFlags.NonPublic | BindingFlags.Static);
}
public override void OnEndPage(PdfWriter writer, iTextSharp.text.Document document)
{
[...]
// parse
XMLWorker worker = new XMLWorker(cssPipeline, true);
XMLParser parser = new XMLParser(worker);
LocalDataStoreSlot contextSlot = (LocalDataStoreSlot) context.GetValue(worker);
object contextData = Thread.GetData(contextSlot);
Thread.SetData(contextSlot, null);
try
{
foreach (var _frag in _fragments)
{
ColumnText ct = new ColumnText(writer.DirectContent);
//using (var reader = new StringReader(_frag.Content))
//{
// parser.Parse(reader);
//}
_instance.ParseXHtml(new ColumnTextElementHandler(ct), new StringReader(_frag.Content));
//ct.SetSimpleColumn(document.Left, document.Top, document.Right, document.GetTop(-20), 10, Element.ALIGN_MIDDLE);
ct.SetSimpleColumn(
_frag.LLX.HasValue ? document.GetLeft(_frag.LLX.Value) : document.Left,
_frag.LLY.HasValue ? document.GetTop(_frag.LLY.Value) : document.Top,
_frag.URX.HasValue ? document.GetRight(_frag.URX.Value) : document.Right,
_frag.URY.HasValue ? document.GetBottom(_frag.URY.Value) : document.Bottom,
_frag.Leading, _frag.Alignment);
ct.Go();
}
}
finally
{
Thread.SetData(contextSlot, contextData);
}
}
}