【问题标题】:itext7 end_page events are called when document is closed文档关闭时调用 itext7 end_page 事件
【发布时间】:2018-05-21 09:11:21
【问题描述】:

我正在尝试按照https://developers.itextpdf.com/examples/page-events/clone-page-events-headers-and-footers#2656-variableheader.java 中给出的示例创建带有可变标题的 PDF 文档。但是事件没有正确触发。这是我测试过的代码 -

class Program
{
    public static String DEST = "test.pdf";
    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");

        manipulatePdf(DEST);
    }


    public static List<int> getFactors(int n)
    {
        List<int> factors = new List<int>();
        for (int i = 2; i <= n; i++)
        {
            while (n % i == 0)
            {
                factors.Add(i);
                n /= i;
            }
        }
        return factors;
    }

    protected static void manipulatePdf(String dest)
    {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST));
        Document doc = new Document(pdfDoc, PageSize.A4, true);
        VariableHeaderEventHandler handler = new VariableHeaderEventHandler();
        pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, handler);
        List<int> factors;
        for (int i = 2; i < 4; i++)
        {
            factors = getFactors(i);
            if (factors.Count == 1)
            {
                doc.Add(new Paragraph("This is a prime number!"));
            }
            foreach (int factor in factors)
            {
                doc.Add(new Paragraph("Factor: " + factor));
            }

            handler.setHeader(String.Format("THE FACTORS OF {0}", i));
            if (300 != i)
            {
                doc.Add(new AreaBreak());
            }
        }
        doc.Close();
    }


    protected class VariableHeaderEventHandler : IEventHandler
    {
        protected String header;

        public void setHeader(String header)
        {
            this.header = header;
        }

        public void HandleEvent(Event @event)
        {
            PdfDocumentEvent documentEvent = (PdfDocumentEvent)@event;
            try
            {
                new PdfCanvas(documentEvent.GetPage())
                        .BeginText()
                        .SetFontAndSize(PdfFontFactory.CreateFont(StandardFonts.HELVETICA), 12)
                        .MoveText(450, 806)
                        .ShowText(header)
                        .EndText()
                        .Stroke();
            }
            catch (IOException e)
            {
            }
        }
    }
}

如果我运行此代码,所有页面都将标题显示为“3 的因素”。但他们应该在第一页显示“2 的因素”,在第二页显示“3 的因素”,在第三页显示“4 的因素”。我不知道如何解决它。有什么建议吗?

【问题讨论】:

  • 是的,itext 7 页面事件可能会有一些延迟。您可能需要像this answer 这样的解决方法,它是关于最后一页上的特殊页脚。
  • 我已经检查了那个答案。但是我需要每个页面都有唯一的标题,由于页面事件延迟而无法正常工作。

标签: c# itext itext7


【解决方案1】:

正如earlier answer 中已经提到的那样,iText 7 页面事件会延迟触发 - 通常不会在文档关闭之前,正如您在问题标题中所假设的那样,但是页面 n+1 在处理页面 n 的事件之前可能确实已经接近完成。

因此,将新页眉设置为事件处理程序的属性是不够的,还必须告诉事件处理程序何时开始使用它。所以...

改进的处理程序

protected class ImprovedVariableHeaderEventHandler : IEventHandler
{
    Dictionary<PdfPage, String> headers = new Dictionary<PdfPage, string>();
    protected String header = "";

    public void setHeaderFor(String header, PdfPage page)
    {
        headers[page] = header;
    }

    public void HandleEvent(Event @event)
    {
        PdfDocumentEvent documentEvent = (PdfDocumentEvent)@event;
        PdfPage page = documentEvent.GetPage();
        if (headers.ContainsKey(page))
        {
            header = headers[page];
            headers.Remove(page);
        }
        new PdfCanvas(page)
                .BeginText()
                .SetFontAndSize(PdfFontFactory.CreateFont(StandardFonts.HELVETICA), 12)
                .MoveText(450, 806)
                .ShowText(header)
                .EndText()
                .Stroke();
    }
}

这个改进的处理程序可以这样使用:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc, PageSize.A4, true);
ImprovedVariableHeaderEventHandler handler = new ImprovedVariableHeaderEventHandler();
pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, handler);
List<int> factors;
for (int i = 2; i < 40; i++)
{
    if (2 != i)
    {
        doc.Add(new AreaBreak());
    }

    factors = getFactors(i);
    if (factors.Count == 1)
    {
        doc.Add(new Paragraph("This is a prime number!"));
    }
    foreach (int factor in factors)
    {
        doc.Add(new Paragraph("Factor: " + factor));
    }

    handler.setHeaderFor(String.Format("THE FACTORS OF {0}", i), pdfDoc.GetLastPage());
}
doc.Close();

结果是你期望的输出。

具有多个标题元素的变体

我们可能不想为这么少的内容浪费这么多页面。在这种情况下,多个数字的因式分解应该放在一个页面上,我们希望在标题中提到所有这些。这可以使用像这样的替代事件侦听器来实现:

protected class ImprovedVariableHeaderEventHandlerAlt : IEventHandler
{
    Dictionary<PdfPage, String> headers = new Dictionary<PdfPage, string>();
    protected String header = "";

    public void addHeaderDetailFor(string header, PdfPage page)
    {
        if (headers.ContainsKey(page))
            headers[page] += ", " + header;
        else
            headers[page] = header;
    }

    public void HandleEvent(Event @event)
    {
        PdfDocumentEvent documentEvent = (PdfDocumentEvent)@event;
        PdfPage page = documentEvent.GetPage();
        if (headers.ContainsKey(page))
        {
            header = String.Format("THE FACTORS OF {0}", headers[page]);
            headers.Remove(page);
        }
        new PdfCanvas(page)
                .BeginText()
                .SetFontAndSize(PdfFontFactory.CreateFont(StandardFonts.HELVETICA), 12)
                .MoveText(150, 806)
                .ShowText(header)
                .EndText()
                .Stroke();
    }
}

使用此代码:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc, PageSize.A4, true);
ImprovedVariableHeaderEventHandlerAlt handler = new ImprovedVariableHeaderEventHandlerAlt();
pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, handler);
List<int> factors;
for (int i = 2; i < 40; i++)
{
    doc.Add(new Paragraph(String.Format("The factors of {0}", i)).SetBold());
    handler.addHeaderDetailFor(i.ToString(), pdfDoc.GetLastPage());

    factors = getFactors(i);
    if (factors.Count == 1)
    {
        doc.Add(new Paragraph("This is a prime number!"));
    }
    foreach (int factor in factors)
    {
        doc.Add(new Paragraph("Factor: " + factor));
    }
}
doc.Close();

通过在为新数字绘制节标题后立即通知事件侦听器,该数字将在打印此节标题的页面的页眉中提及,而实际分解可能在下一页上。

【讨论】:

  • 如果内容很长,如何检测是否添加了新页面?如果自动添加新页面,则不会将其引用添加到字典中
  • 字典仅用于更改正确页面上的header。如果多个页面的header 保持相同,则不需要这些页面的字典条目。
猜你喜欢
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 2021-07-08
  • 2021-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多