danfickle / openhtmltopdf

An HTML to PDF library for the JVM. Based on Flying Saucer and Apache PDF-BOX 2. With SVG image support. Now also with accessible PDF support (WCAG, Section 508, PDF/UA)!

Home Page:https://danfickle.github.io/pdf-templates/index.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

com.openhtmltopdf.render.ContentLimitContainer failing in updateTop method in some cases.

adilxoxo opened this issue · comments

commented

I am not able to get this issue as it is happening in one particular setup. It is working on other setups. Can you please help me to understand this methods purpose. So I can understand where I need to check.

It is failing with no exception message.

#Class Name::com.openhtmltopdf.render.ContentLimitContainer:: Method Name::updateTop:: Line Number::69#

hi @adilxoxo , what do you mean by "it fail" (if there are no exception)?

Do you have an example ?

commented

I can not tell certain example but I would like to know in which cases it might fail. Just give me clear idea or guide me to doc regarding same.

Because this is happening only for some particular reports.

This is log generated my app. I will share stack trace soon.

2020.09.14 14:33:24 diff: 0 Thread: 3b Session: 0 Event: ERROR Source: AbstractPDFReport::printPDFReport[150] >
#Class Name::com.openhtmltopdf.render.ContentLimitContainer:: Method Name::updateTop:: Line Number::69#
2020.09.14 14:33:24 diff: 0 Thread: 3b Session: 0 Event: ERROR Source: AbstractPDFReport::printPDFReport[152] >

commented

Please find stack trace below for same issue.

2020.09.15 15:48:52 diff: 0 Thread: 2f Session: 0 Event: ERROR Source: AbstractPDFReport::printPDFReport[157] > null
java.lang.NullPointerException
at com.openhtmltopdf.render.ContentLimitContainer.updateTop(ContentLimitContainer.java:69)
at com.openhtmltopdf.render.Box.analyzePageBreaks(Box.java:1279)
at com.openhtmltopdf.newtable.TableBox.analyzePageBreaks(TableBox.java:388)
at com.openhtmltopdf.render.Box.analyzePageBreaks(Box.java:1281)
at com.openhtmltopdf.render.Box.analyzePageBreaks(Box.java:1281)
at com.openhtmltopdf.newtable.TableRowBox.analyzePageBreaks(TableRowBox.java:141)
at com.openhtmltopdf.render.Box.analyzePageBreaks(Box.java:1281)
at com.openhtmltopdf.newtable.TableBox.analyzePageBreaks(TableBox.java:388)
at com.openhtmltopdf.newtable.TableBox.analyzePageBreaks(TableBox.java:374)
at com.openhtmltopdf.newtable.TableBox.layoutTable(TableBox.java:287)
at com.openhtmltopdf.newtable.TableBox.layout(TableBox.java:242)
at com.openhtmltopdf.layout.BlockBoxing.layoutBlockChild0(BlockBoxing.java:321)
at com.openhtmltopdf.layout.BlockBoxing.layoutBlockChild(BlockBoxing.java:299)
at com.openhtmltopdf.layout.BlockBoxing.layoutContent(BlockBoxing.java:90)
at com.openhtmltopdf.render.BlockBox.layoutChildren(BlockBox.java:1204)
at com.openhtmltopdf.render.BlockBox.layout(BlockBox.java:1058)
at com.openhtmltopdf.render.BlockBox.layout(BlockBox.java:973)
at com.openhtmltopdf.layout.BlockBoxing.layoutBlockChild0(BlockBoxing.java:321)
at com.openhtmltopdf.layout.BlockBoxing.layoutBlockChild(BlockBoxing.java:299)
at com.openhtmltopdf.layout.BlockBoxing.layoutContent(BlockBoxing.java:90)
at com.openhtmltopdf.render.BlockBox.layoutChildren(BlockBox.java:1204)
at com.openhtmltopdf.render.BlockBox.layout(BlockBox.java:1058)
at com.openhtmltopdf.render.BlockBox.layout(BlockBox.java:973)
at com.openhtmltopdf.pdfboxout.PdfBoxRenderer.layout(PdfBoxRenderer.java:339)
at com.openhtmltopdf.pdfboxout.PdfRendererBuilder.run(PdfRendererBuilder.java:41)
at com.brixip.core.pdf.report.abstracts.AbstractPDFReport.printPDFReport(AbstractPDFReport.java:147)
at com.brixip.core.pdf.report.impl.PDFMapImpl.generate(PDFMapImpl.java:40)
at com.brixip.buss.reports.impl.ReportServiceImpl.merge(ReportServiceImpl.java:2866)
at com.brixip.controller.reportmgmt.ReportsDownloadServlet.getMergedPDF(ReportsDownloadServlet.java:108)
at com.brixip.controller.reportmgmt.ReportsDownloadServlet$1.call(ReportsDownloadServlet.java:71)
at com.brixip.controller.reportmgmt.ReportsDownloadServlet$1.call(ReportsDownloadServlet.java:68)
at com.pvmsys.brix.app.session.provider.SessionProvider.execute(SessionProvider.java:600)
at com.pvmsys.brix.app.session.ods.OdsSession.execute(OdsSession.java:447)
at com.brixip.controller.reportmgmt.ReportsDownloadServlet.doPost(ReportsDownloadServlet.java:68)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.eclipse.equinox.http.servlet.internal.ServletRegistration.service(ServletRegistration.java:61)
at org.eclipse.equinox.http.servlet.internal.ProxyServlet.processAlias(ProxyServlet.java:126)
at org.eclipse.equinox.http.servlet.internal.ProxyServlet.service(ProxyServlet.java:60)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.eclipse.equinox.servletbridge.BridgeServlet.service(BridgeServlet.java:120)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Unknown Source)

thank you, the NullPointerException is the one i expected, as in the code:

getContentLimit(page.getPageNo(), true).updateTop(absY);
I can't really see other possibilities.

So it seems getContentLimit return a null. Looks like there is some kind of corner case.

Could you provide a minimal reproducer? Unfortunately I don't think I'm able to debug without it.

commented

What kind of data do you need ?

We use free marker to generate html string from template then by using jsoup we convert that data into w3c doc.

Data passed to free marker is map and json.

commented

Code snippet :

            PdfRendererBuilder builder = new PdfRendererBuilder();
            builder.useFastMode();
            builder.withW3cDocument(getDocument(input),null);
            builder.toStream(outputStream);
            builder.run();

     public  Document getDocument(String input) throws Exception {
	org.w3c.dom.Document w3cDoc = null;
	org.jsoup.nodes.Document jsoupdoc = Jsoup.parse(input,"UTF-8");
	W3CDom w3cDom = new W3CDom();
	w3cDoc = w3cDom.fromJsoup(jsoupdoc);
	return w3cDoc;
  }

PFA for html template causing issue.

template.zip

I did a try with the version 1.0.4 using the following code:

       try (OutputStream os = new FileOutputStream("test.pdf")) {
            PdfRendererBuilder builder = new PdfRendererBuilder();
            builder.useFastMode();
            builder.withW3cDocument(W3CDom.convert(Jsoup.parse(new File("template.html"), "UTF-8", "")), "");

            builder.toStream(os);
            builder.run();
        }

and it generate the following pdf, without any issues:

test.pdf

commented

Can you please try adding fonts to it.

        File calibri = new File(fontpath+"calibri.ttf");
        File math = new File(fontpath+"maths.ttf");
        File jp = new File(fontpath+"arialuni.ttf");
        builder.useFont(calibri, Font.createFont(Font.TRUETYPE_FONT, calibri).getFamily());
        builder.useFont(math, Font.createFont(Font.TRUETYPE_FONT, math).getFamily());

        builder.useFont(jp, Font.createFont(Font.TRUETYPE_FONT, jp).getFamily());

After looking at your code I tried removing fonts from builder and found that after adding arialuni font to builder is causing issue. I am using version 1.0.3.
PFA for font files.

fonts.zip

Using your template.html with the provided fonts work as expected, with both version 1.0.3 and 1.0.4.

Full code:

package test;

import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import org.jsoup.Jsoup;
import org.jsoup.helper.W3CDom;

import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class App {
    public static void main(String[] args) throws Exception {

        try (OutputStream os = new FileOutputStream("test.pdf")) {
            PdfRendererBuilder builder = new PdfRendererBuilder();
            builder.useFastMode();

            File calibri = new File("calibri.ttf");
            File math = new File("MATHS.ttf");
            File jp = new File("arialuni.ttf");
            builder.useFont(calibri, Font.createFont(Font.TRUETYPE_FONT, calibri).getFamily());
            builder.useFont(math, Font.createFont(Font.TRUETYPE_FONT, math).getFamily());
            builder.useFont(jp, Font.createFont(Font.TRUETYPE_FONT, jp).getFamily());

            builder.withW3cDocument(W3CDom.convert(Jsoup.parse(new File("template.html"), "UTF-8", "")), "");
            builder.toStream(os);
            builder.run();
        }
    }
}

Maybe it's some data that you have removed from the template.html file which cause an issue?

commented

Actually I might be able to fix it as I was ignoring warning for missing ; in style tag.

After adding ; to ** box-sizing: border-box** now its working.

Let me run more scenarios. If issue comes up again will ping you.

Thank you for the help by the way @syjer

commented

Hi,

I am able to reproduce this issue again.

Please try attached template file.

template.zip

This issue occurs when we add empty lines to some data... in my case empty line looks like <p>&nbsp;</p>.

Also I found this issue #399 which seems similar to mine as it is occurring while page break inside table.

commented

I tried debugging code in library and at one point it returns null with input values as below,

pageNo ==== 1
_contentLimits.size() ==== 0
_initialPageNo ==== 2
_contentLimits ==== []
target ==== -1

Also I am able to reslove this issue by replacing border-spacing: 0; -fs-table-paginate: paginate; by -fs-table-paginate: paginate; border-collapse: collapse;

Does order of applying css matters??

also the table border is not proper at page break as shown in below image,

image

Hi @adilxoxo,

In answer to your original question, the method is designed to reserve space as required for paginated table header and footer on each page.

I'll try to have a look over the weekend.

@adilxoxo

Based on your debugging (thanks), I was able to condense the failing test to:

<html>
<body>
    <div style="page-break-before: always;"></div>
    <table style="margin-top: -20px; -fs-table-paginate: paginate;">
      <tr><td>Row 1</td></tr>
    </table>
</body>
</html>

It doesn't like negative margins that push paginated tables back to the previous page. This is the offending CSS in your template:

.topMargin table{
			margin-top:-10px !important;
			margin-bottom:20px !important;
			max-width: 630px;
		}

If you change this margin-top to 0 it will no longer crash.

I'll see if I can fix this bug now by factoring in the margin to the initial page calculation.

commented

@danfickle

Thanks for pointing out the fix. Will do above change to my template.

commented

Hey @danfickle,

Hope you are doing well.

I have another use case in which if <p> , <ol>, <ul> or any other html tag has negative margin and comes between the page break then same issue occurs.

Hey @danfickle,

Hope you are doing well.

I have another use case in which if <p> , <ol>, <ul> or any other html tag has negative margin and comes between the page break then same issue occurs.

Hi @adilxoxo, sorry for missing this, but do you know if this is still a problem or has my fix solved it?