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)!
https://danfickle.github.io/pdf-templates/index.html
Other
1.92k stars 357 forks source link

PDF creation from html string fails unless testMode(true) #107

Open dtrucken opened 7 years ago

dtrucken commented 7 years ago

My code:

   private String test = "<html><body><p>Hello world!</p></body></html>";

   PdfRendererBuilder builder = new PdfRendererBuilder();
   builder.withW3cDocument(DOMBuilder.jsoup2DOM(Jsoup.parse(test)), "http://localhost:8888/");
   builder.toStream(outputStream);
   builder.testMode(true);
   builder.run();

The above renders nicely -- thanks!! myfilename (16).pdf

However, if testMode isn't set to true, the PDF created renders what looks like an empty page. There is a /Filter /FlateDecode section in the actual file created, but, apparently the contents of the stream are not valid myfilename (15).pdf

danfickle commented 7 years ago

Hi @dtrucken I couldn't replicate this. My setup:

    private void render() throws Exception {
        String test = "<html><body><p>Hello world!</p></body></html>";

        PdfRendererBuilder builder = new PdfRendererBuilder();
        builder.withW3cDocument(DOMBuilder.jsoup2DOM(Jsoup.parse(test)),
                "http://localhost:8888/");
        try (OutputStream outputStream = new FileOutputStream(
                "/Users/you/Documents/pdftests/test-107.pdf")) {
            builder.toStream(outputStream);
            builder.testMode(false);
            builder.run();
        }
    }

The only thing I can think of is to check that the output stream is being closed. Other than that, if you are still having this issue, could you let us know what version you are using and also what Java version you are running on?

dtrucken commented 7 years ago

I'll try to experiment more this week. I'm using spring boot and Oracle java 8, build132, or something like that... I'm hooking up directly to the output stream given to me by spring's REST ioc. I don't save the PDF output to a file at all.

Dave

On Jul 24, 2017 12:35 AM, "danfickle" notifications@github.com wrote:

Hi @dtrucken https://github.com/dtrucken I couldn't replicate this. My setup:

private void render() throws Exception { String test = "

Hello world!

";

  PdfRendererBuilder builder = new PdfRendererBuilder();
  builder.withW3cDocument(DOMBuilder.jsoup2DOM(Jsoup.parse(test)),
          "http://localhost:8888/");
  try (OutputStream outputStream = new FileOutputStream(
          "/Users/you/Documents/pdftests/test-107.pdf")) {
      builder.toStream(outputStream);
      builder.testMode(false);
      builder.run();
  }

}

The only thing I can think of is to check that the output stream is being closed. Other than that, if you are still having this issue, could you let us know what version you are using and also what Java version you are running on?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/danfickle/openhtmltopdf/issues/107#issuecomment-317323744, or mute the thread https://github.com/notifications/unsubscribe-auth/AEtGjgLjiAitGz0ZCgXSittcaSao6pYdks5sRC0DgaJpZM4OdeXd .

chubbard commented 6 years ago

I'm having the exact same problem. If I follow the simple example in the docs then I end up with a blank pdf document. If I just add testMode(true) then it renders as expected. I'm using Java 1.8 build 144 on Windows 10. This is a basic hello world html file. I am saving it to a file, and I flush stream. I'm using the try-catch-resource syntax so it should close the stream.

grizio commented 5 years ago

Is there any news on this ticket?

I also had the exact same behavior. However, I used a ByteArrayOutputStream instead of a file but the result is the same.

danfickle commented 4 years ago

Hi @grizio,

I think the original problem was that pdfbox seems to require a seekable stream to save the PDF. However, if you are using a ByteArrayOutputStream that should not be an issue. Can you provide a minimal sample that demonstrates, including what you are doing with the byte array?

grizio commented 4 years ago

Hello @danfickle,

I am not on the project anymore and cannot access the code. However, the issue was the exact same code than above except for the outputStream being a ByteArrayOutputStream instead of a FileOutputStream.

Setting testMode(true) worked and we continued with this setting.

charbonnier666 commented 4 years ago

same problem here... it works only in testMode(true)

danfickle commented 3 years ago

This sounds like a serious problem, if anyone has a replicable sample that would be great!

snakemastr commented 3 years ago

Hi @danfickle

I just came across this issue and can provide a stripped example (due to copyright reasons).

I am not a Java developer but Frontend Javascript developer and was given the task to create a pdf in a VueJS environment. I'm not sure ByteArrayOutputStream is what I need perse but the result is the same. testMode(false) or omitted gives a blank page and testMode(true) gives "Test" in h1 format.

FileOutputStream does work with testMode(false) but I don't want to write a file, only send the bytes directly.

I also tried an example where an AbstractResourceStreamWriter is created and passed through ResourceStreamRequestHandler using a WebPage, and I am pretty sure that also worked correctly, but I need the webservice endpoint for security reasons and therefore cannot rely on RequestCycle. (I don't know why or if this is relevant information, no Java developr ;-) )

PdfService.java

public class PdfService {

    public void printUrlToPdf(String html, OutputStream output) throws IOException {
        String xhtml = convertHtmlToXHTML(html);
        PdfRendererBuilder builder = new PdfRendererBuilder();
        builder.useFastMode();
        //System.out.println(xhtml);
        builder.withHtmlContent(xhtml, "test.html");
        builder.testMode(false);
        builder.toStream(output);
        builder.run();
    }

    private String convertHtmlToXHTML(String input) {
        org.jsoup.nodes.Document d = Jsoup.parse(input, "US-ASCII");
        d.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
        return d.html();
    }
}

JAX-RS endpoint

 @POST
    @Produces("application/pdf")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response toPDF(@Nonnull @RequestBody Request request) {
        /* stripped out parsing code but simple String has same result */
        String html = "<h1>Test</h1>";
        try {
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                PdfService service = new PdfService();
                service.printUrlToPdf(html, byteArrayOutputStream);
                return Response.ok(byteArrayOutputStream.toByteArray())
                        .header("content-disposition", "attachment; filename = mockFile.pdf")
                        .build();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

If you need more information, please let me know. I have trashed the AbstractResourceStreamWriter example but can always try to replicate it..

Are there any downsides to using the testMode(true) setting?

danfickle commented 3 years ago

Test mode just tells PDF-BOX not to compress streams. Therefore, setting it to false should be OK although it will produce a larger PDF.

Could you upload the failed PDF document so I can try to compare to one I've produced? I assume it is not zero size.

mathimus commented 3 years ago

Dear Dan,

I'm glad to have found this thread, because I bumped into the same problem while trying to get openhtmltopdf working. Btw, thank you for developing the tool in the first place! I hope the example code I can give counts as minimal. The context is that of a Spring Controller. In the code below, enabling test mode makes all the difference.

    @RequestMapping(value="/my_kingdom_for_a_pdf_file", method = { RequestMethod.GET }, produces = "application/pdf; charset=UTF-8")
    @ResponseBody
    public void giveMeSomePdfPlease(final HttpServletResponse response) throws IOException {
        String html = "<!DOCTYPE html>" +
                "<html>" +
                "<head><style>body {font-family: 'handwriting', 'deja-sans', sans-serif, serif;} </style></head>" +
                "<body dir=\"auto\" style=\"background-color:blue;\">" +
                "<div style=\"text-align:center;font-size: 90px;color:orange;\">" +
                "Hello World!" +
                "</div>" +
                "</body>" +
                "</html>";
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        PdfRendererBuilder builder = new PdfRendererBuilder();
        builder.withHtmlContent(html, null);
        builder.toStream(outputStream);
        builder.testMode(true); // The test cases differ only in the presence of this line
        builder.run();
        response.setContentType("application/pdf");
        response.setContentLength(outputStream.size());
        response.getOutputStream().write(outputStream.toByteArray());
        response.getOutputStream().flush();
        outputStream.close();
    }

Attached are the two resulting pdf's. I could of course continue producing pdf's with uncompressed content for now. But any tips or improvements on that front are of course much appreciated. pdf_testmode_false.pdf pdf_testmode_true.pdf

grizio commented 3 years ago

I tested again the sample codes. I have no issue on Manjaro. However, my issues were when I used macOS. I do not have it anymore so I cannot check if it is the cause of defect.