Downloaded PDF looks empty although it contains some data

Thanks to this. It really works.

BTW, here's how I do it using spring controller and ajax with pdf generated by jasper

The Controller:

public ResponseEntity<?> printPreview(@ModelAttribute("claim") Claim claim)
{
    try
    {
        //Code to get the byte[] from jasper report.
        ReportSource source = new ReportSource(claim);
        byte[] report = reportingService.exportToByteArrayOutputStream(source);

        //Conversion of bytes to Base64
        byte[] encodedBytes = java.util.Base64.getEncoder().encode(report);

        //Setting Headers
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/pdf"));
        headers.setContentDispositionFormData("pdfFileName.pdf", "pdfFileName.pdf");
        headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        headers.setContentLength(encodedBytes.length);

        return new ResponseEntity<>(encodedBytes, headers, HttpStatus.OK);
    }
    catch (Exception e)
    {
        LOG.error("Error on generating report", e);
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
 }

The ajax:

    $.ajax({
       type: "POST",
       url: "",
       data: form.serialize(), //Data from my form
       success: function(response)
       {
                let binaryString = window.atob(response);
                let binaryLen = binaryString.length;
                let bytes = new Uint8Array(binaryLen);

                for (let i = 0; i < binaryLen; i++) {
                    let ascii = binaryString.charCodeAt(i);
                    bytes[i] = ascii;
                }

                let blob = new Blob([bytes], {type: "application/pdf"});
                let link = URL.createObjectURL(blob);
                window.open(link, '_blank');
       },
       error: function()
       {

       }
     });

This will load the pdf in new window.

References: Return generated pdf using spring MVC


I solved the issue. The problem was in a way the data is delivered from the server to the client. It is critical to assure that the server sends the data in Base64 encoding, otherwise the client side can't deserialize the PDF string back to the binary format. Below, you can find the full solution.

Server-side:

OutputStream pdfStream = PDFGenerator.pdfGenerate(data);

String pdfFileName = "test_pdf";

// represent PDF as byteArray for further serialization
byte[] byteArray = ((java.io.ByteArrayOutputStream) pdfStream).toByteArray();

// serialize PDF to Base64
byte[] encodedBytes = java.util.Base64.getEncoder().encode(byteArray);

response.reset();
response.addHeader("Pragma", "public");
response.addHeader("Cache-Control", "max-age=0");
response.setHeader("Content-disposition", "attachment;filename=" + pdfFileName);
response.setContentType("application/pdf");

// avoid "byte shaving" by specifying precise length of transferred data
response.setContentLength(encodedBytes.length);

// send to output stream
ServletOutputStream servletOutputStream = response.getOutputStream();

servletOutputStream.write(encodedBytes);
servletOutputStream.flush();
servletOutputStream.close();

Client side:

let binaryString = window.atob(data);

let binaryLen = binaryString.length;

let bytes = new Uint8Array(binaryLen);

for (let i = 0; i < binaryLen; i++) {
    let ascii = binaryString.charCodeAt(i);
    bytes[i] = ascii;
}

let blob = new Blob([bytes], {type: "application/pdf"});

let link = document.createElement('a');

link.href = window.URL.createObjectURL(blob);
link.download = pdfFileName;

link.click();

Reference topics:

  • How to convert a PDF generating in response.outputStream to a Base64 encoding

  • Download File from Bytes in JavaScript