Itextsharp - 检查添加元素是否会创建新页面

3
我正在使用ITextSharp将HTML文档转换为PDF。我使用HTMLWorker.ParseToList并逐个遍历每个项目。这很好用,但是第一页需要具有与后续页面不同的边距大小。我可以通过调用MyDocument.NewPage()并调用MyDocument.SetMargins()来实现此目的。

当尝试检测页面转换时,我的问题出现了。

我可以使用循环来跟踪页面转换,然后调用NewPage()并重置边距,但是,只有在我添加一个换行到新页面的段落之后,才能进行此操作,留下整个页面几乎为空白。

如果我添加某个段落对象,我需要一种预先检测页面是否会更改的方法。 我尝试使用ColumnText.Go(true)模拟它(如果结果为ColumnText.NO_MORE_COLUMN,则进行分页),不幸的是,它似乎最多只能检测错误的页面中断位置。

以下是我的当前代码:
            ColumnText simulation = new ColumnText(Writer.DirectContent);
            simulation.SetSimpleColumn(Writer.PageSize);   
            bool FirstPage = true;
            foreach (var item in ItemList)
            {
                var para = new Paragraph("", Normal);
                para.AddAll(item.Chunks);                    
                para.SpacingAfter = 10;
                foreach (Chunk c in item.Chunks)
                {
                    simulation.AddText(c);
                }
                if(FirstPage) {
                    int simresult = simulation.Go(true);
                    if(simresult == (int)ColumnText.NO_MORE_COLUMN)
                    {
                        textDocument.SetMargins(100,100,100,100);
                        textDocument.NewPage();    
                        FirstPage = false;                 
                    }
                }

                textDocument.Add(para);
            }

这会导致在第二页结束之前无法检测到分页,这是不好的。

我找到的唯一解决办法是将传递到simulation.SetSimpleColumn中的高度减半。

虽然这样可以解决问题,但我不知道为什么。如果有人能给我任何见解,那就太好了。



感谢Alexis的帮助,我已经弄清楚了。ITextSharp非常严格地遵循Java事件模型,这很麻烦,因为我一直在寻找Writer和Document中的事件。首先我必须创建一个类来覆盖PdfPageEventHelper:
internal class MainTextEventsHandler : PdfPageEventHelper
{
    public override void OnStartPage(PdfWriter writer, Document document)
    {
        document.SetMargins(document.LeftMargin, document.LeftMargin, document.TopMargin, document.BottomMargin); //Mirror the horizontal margins
        document.NewPage(); //do this otherwise the margins won't take
    }
}

接下来,我设置了 Writer 对象的 PageEvent 属性,并修改了循环以移除模拟。
        Writer.PageEvent = new MainTextEventsHandler();
        foreach (var item in ItemList)
        {
            var para = new Paragraph("", Normal);
            para.AddAll(item.Chunks);
            /* per-paragraph stuff here */
            para.SpacingAfter = 10;                    
            textDocument.Add(para);
        }
3个回答

2
请查看页面事件,尤其是onStartPage和/或onEndPage,以确定是否需要更改文档的边距。请注意,这些示例适用于Java版本,但转换为iTextSharp应该很简单。

看起来他们只是直接将Java移植到C#,并忽略了C#的事件模型。我不得不创建一个单独的小类,在其中创建一个函数(覆盖OnStartPage),该函数继承PdfPageEventHelper,并在其中放置我的.SetMargins和.NewPage()调用。现在运行良好,甚至不需要模拟,但是为什么不能直接给对象本身事件呢? - Big The Dave
@Canazza 我不是iText的贡献者,所以我真的无法回答。也许你可以在iText邮件列表上提问。请注意,您需要订阅该列表才能在那里发布。 - Alexis Pigeon

2

尝试这段代码:

public const string pageBreakHtmlMarker = "<!-- pageBreak -->";
public MemoryStream htmlToPdf(string html)
{
    MemoryStream msOutput = new MemoryStream();
    string[] sep = new string[] { pageBreakHtmlMarker };
    string[] arrHtml = html.Split(sep, 9999, StringSplitOptions.RemoveEmptyEntries);
    htmlToPdf(arrHtml, ref msOutput);
    return msOutput;
}
private void htmlToPdf(string[] arrHtmlPages, ref MemoryStream msOutput)
{
    using (Document document = new Document(PageSize.A4, 30, 30, 30, 30))
    {
        using (HTMLWorker worker = new HTMLWorker(document))
        {
            PdfWriter writer = PdfWriter.GetInstance(document, msOutput); // writer to listen doc ad direct a XML-stream to a file            
            document.Open();
            worker.StartDocument();
            foreach (string html in arrHtmlPages)
            {
                TextReader reader = new StringReader(html); // parse the html into the document
                worker.Parse(reader);
                document.Add(Chunk.NEXTPAGE);
            }
            worker.EndDocument();
        }
    }
}

你能解释一下这个答案吗?我不明白它怎么解决OP的问题。 - Jim G.

0

Visual Basic 中的示例代码片段

LoadPage 中只需使用:

Dim pdfPageEvents As pdfPageEvents = New pdfPageEvents
writer = PdfWriter.GetInstance(doc, memMemoryStream)
writer.CloseStream = False
writer.PageEvent = pdfPageEvents
doc.Open()

将这个类放在同一个文件或命名空间中。
Public Class pdfPageEvents
    Inherits iTextSharp.text.pdf.PdfPageEventHelper
    Private _strTitle As String, _strPrintFeatures As String

    Public Sub New(ByVal Title As String, ByVal PrintFeatures As String)
        _strTitle = Title
        _strPrintFeatures = PrintFeatures
    End Sub

    Public Overrides Sub OnStartPage(ByVal writer As PdfWriter, ByVal doc As Document)
        If InStr(_strPrintFeatures, "header") > 0 Then
            Dim fntFont As Font = FontFactory.GetFont("Tahoma", BaseFont.CP1250, True, 10, Font.NORMAL, New BaseColor(128, 128, 128))
            Dim imgImage As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(HttpContext.Current.Server.MapPath("../LocalResources/Images/print_company_logo_medium.png"))
            Dim tblTable As New PdfPTable(2)
            Dim celRightCell As PdfPCell

            tblTable.WidthPercentage = 100
            tblTable.HorizontalAlignment = Element.ALIGN_CENTER
            imgImage.ScalePercent(70)

            Dim celLeftCell As New PdfPCell(New Phrase(_strTitle, fntFont))
            celLeftCell.HorizontalAlignment = Element.ALIGN_LEFT
            celLeftCell.Border = 0
            celLeftCell.BorderWidthBottom = 0.5
            celLeftCell.BorderColorBottom = New BaseColor(128, 128, 128)
            celLeftCell.VerticalAlignment = Element.ALIGN_BOTTOM
            celLeftCell.PaddingBottom = 3
            tblTable.AddCell(celLeftCell)

            If InStr(_strPrintFeatures, "logo") > 0 Then
                celRightCell = New PdfPCell(imgImage)
            Else
                celRightCell = New PdfPCell(New Paragraph(""))
            End If

            celRightCell.HorizontalAlignment = Element.ALIGN_RIGHT
            celRightCell.Border = 0
            celRightCell.BorderWidthBottom = 0.5
            celRightCell.BorderColorBottom = New BaseColor(128, 128, 128)
            celRightCell.VerticalAlignment = Element.ALIGN_BOTTOM
            celRightCell.PaddingBottom = 3
            tblTable.AddCell(celRightCell)

            doc.Add(tblTable)
            doc.Add(New Paragraph(vbNewLine))
        End If
    End Sub

    Public Overrides Sub OnEndPage(ByVal writer As PdfWriter, ByVal doc As Document)
        If InStr(_strPrintFeatures, "footer") > 0 Then
            Dim fntFont As Font = FontFactory.GetFont("Tahoma", BaseFont.CP1250, True, 10, Font.NORMAL, New BaseColor(128, 128, 128))
            Dim tblTable As New PdfPTable(2)
            Dim strDate As String = IIf(InStr(_strPrintFeatures, "date") > 0, FormatDateTime(Date.Today, DateFormat.GeneralDate), "")

            tblTable.TotalWidth = doc.PageSize.Width - doc.LeftMargin - doc.RightMargin
            tblTable.HorizontalAlignment = Element.ALIGN_CENTER

            Dim celLeftCell As New PdfPCell(New Phrase(strDate, fntFont))
            celLeftCell.HorizontalAlignment = Element.ALIGN_LEFT
            celLeftCell.Border = 0
            celLeftCell.BorderWidthTop = 0.5
            celLeftCell.BorderColorTop = New BaseColor(128, 128, 128)
            celLeftCell.VerticalAlignment = Element.ALIGN_BOTTOM
            tblTable.AddCell(celLeftCell)

            Dim celRightCell As New PdfPCell(New Phrase(CStr(doc.PageNumber), fntFont))
            celRightCell.HorizontalAlignment = Element.ALIGN_RIGHT
            celRightCell.Border = 0
            celRightCell.BorderWidthTop = 0.5
            celRightCell.BorderColorTop = New BaseColor(128, 128, 128)
            celRightCell.VerticalAlignment = Element.ALIGN_BOTTOM
            tblTable.AddCell(celRightCell)
            tblTable.WriteSelectedRows(0, -1, doc.LeftMargin, (doc.BottomMargin), writer.DirectContent)
        End If
    End Sub
End Class

你能解释一下这个答案吗?我不明白它是如何解决 OP 的问题的。 - Jim G.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接