I'm using PDFBox to generate PDF files, however when I try to draw an image which I receive from an array of bytes I get the following error:

Insufficient data for an image

This is the basic structure of my code:

    public ByteArrayOutputStream generatePDF() {                

        .. Variable Declaration

        // Creating Document
        document = new PDDocument();

        // Creating Pages       
        for(int i = 0; i < arrayVar.length; i++) {

            // Adding page to document
            page = new PDPage();

            // Creating FONT Attributes
            fontNormal = PDType1Font.HELVETICA;
            fontBold = PDType1Font.HELVETICA_BOLD;

            // Building Front & Back Invoice Images         
            singleImageMap = // Getting Map With Array Of Bytes from Web Service Call;

            if(singleImageMap != null && !singleImageMap.isEmpty()) {

                            arrayFront = Utils.readImage((byte[]) singleImageMap.get(Constants.WS_IMAGE_FRONT));
            arrayBack = Utils.readImage((byte[]) singleImageMap.get(Constants.WS_IMAGE_BACK));

            fileFront = new ByteArrayInputStream(arrayFront);
            fileBack = new ByteArrayInputStream(arrayBack);                 
                bufferedImageFront = ImageIO.read(fileFront);
                bufferedImageBack = ImageIO.read(fileBack);                 

                rescaledFrontImg = Scalr.resize(bufferedImageFront, 500);
                rescaledBackImg = Scalr.resize(bufferedImageBack, 500);

                front = new PDJpeg(document, rescaledFrontImg);
                back = new PDJpeg(document, rescaledBackImg);

            }

            // Next we start a new content stream which will "hold" the to be created content.
            contentStream = new PDPageContentStream(document, page);                

            // Let's define the content stream
            contentStream.beginText();
            contentStream.setFont(fontNormal, 8);
            contentStream.moveTextPositionByAmount(200, 740);
            contentStream.drawString("NAME: " + arrayVar[i].getParameter(Constants.NAME));
            contentStream.endText();

            if(front != null && back != null) {
                contentStream.drawImage(front, 55, 500);
                contentStream.drawImage(back, 55, 260); 
            }           

            // Add Page
            document.addPage(page);

            // Let's close the content stream       
            contentStream.close();

        }

        // Let's create OutputStream object
        output = new ByteArrayOutputStream(); 

        // Finally Let's save the PDF
        document.save(output);
        document.close();

        return output;
    }

Since I receive a PNG file from the Web Service I do the conversion to JPG with the following method:

    public static byte[] readImage(byte[] file) throws Exception {

    ImageInputStream is = ImageIO.createImageInputStream(new ByteArrayInputStream(file));

    BufferedImage originalImage = ImageIO.read(is);         
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ImageIO.write(originalImage, "jpg", baos ); 

    byte[] imageInByte = baos.toByteArray();

    return imageInByte;
}

As per this link:

https://issues.apache.org/jira/browse/PDFBOX-849

It points out that the error is because the PDJepg object should be created before the creation of the contentStream, but that's what I do in my code.

I'm not sure if there is a problem with the structure of my code, or that maybe there is an error in the way I'm handling the image bytes I'm getting from the Web Service call.

Does anyone has an idea of what could be the problem?

UPDATE

I did what Zelter Ady and indeed the image that I'm getting from the Web Service is valid since I was able to generate a physical file with it, so the problem should be somewhere around the manipulation of the image, the thing is I don't know what I'm missing.

有帮助吗?

解决方案 4

Well after a lot of debugging I found that the problem was here:

front = new PDJpeg(document, rescaledFrontImg);
back = new PDJpeg(document, rescaledBackImg);

The PDJpeg class has two constructors:

PDJpeg(PDDocument doc, BufferedImage bi)
PDJpeg(PDDocument doc, InputStream is)

I was passing a BufferedImage and at some point that I still can't figure out, I assume all the bytes were not being completely sent thus I got the message "Insufficient Data For An Image".

Solution: I passed an InputStream instead of a BufferedImage.

I still don't know why I got that error using a BufferedImage maybe I needed to do some sort of .push()?

其他提示

I've got the same problem. With some images, Acrobat failed to display pages with this message:

Insufficient data for an image

My problem came from the colorModel in some jpeg images. To track which images weren't ok, i log the BufferedImage colorModel by log.warn(img.getColorModel());

[VisualLocatorServlet.doGet:142] ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@4b7fce transparency = 1 has alpha = false isAlphaPre = false
[VisualLocatorServlet.doGet:142] ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@4b7fce transparency = 1 has alpha = false isAlphaPre = false
[VisualLocatorServlet.doGet:142] ColorModel: #pixelBits = 8 numComponents = 1 color space = java.awt.color.ICC_ColorSpace@19ef899 transparency = 1 has alpha = false isAlphaPre = false

Obviously, failing images are 8-bits encoded.

To fix that, i did the following:

byte[] buffer = null;
ByteArrayOutputStream out = new ByteArrayOutputStream();
BufferedImage img = ImageIO.read(new URL(visual));
/* resample 8-bits to 24-bits if necessary to fix pdf corruption */             
if(img.getColorModel().getNumColorComponents()==1){
  log.warn("components #1"+img.getColorModel());
  BufferedImage out = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
  Graphics2D g2 = out.createGraphics();
  g2.setBackground(Color.WHITE);
  g2.drawImage(i, 0, 0, null);
  g2.dispose();
  log.warn("redrawn image "+img.getColorModel());
}
ImageIO.write(img, "jpeg", out);
...

The main point is to recreate a BufferedImage in 24bits. (BufferedImage.TYPE_3BYTE_BGR).

This may be an issue on the Adobe viewer side rather than at creation time. There's a known issue with the latest Acrobat versions: “Insufficient data for an image” error after updating to 10.1.4 or 9.5.2:

http://blogs.adobe.com/dmcmahon/2012/08/21/acrobat-insufficient-data-for-an-image-error-after-updating-to-10-1-4-or-9-5-2/

Before the build of the pdf try to save the image in a file, just to see the image is complete and can be saved.

You may use something like this to test the received image:

System.IO.File.WriteAllBytes("c:\\tmp.png", (byte[]) singleImageMap.get(Constants.FRONT));

and then open the image in a imageviewer. If the image cannot be open, then u have an error here. If the image is ok.... at least you know that this part is ok!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top