【问题标题】:Insufficient Data For An Image (PDF File Generation)图像数据不足(PDF 文件生成)
【发布时间】:2012-03-18 11:41:45
【问题描述】:

我正在使用 PDFBox 生成 PDF 文件,但是当我尝试绘制从字节数组接收到的图像时,出现以下错误:

图片数据不足

这是我的代码的基本结构:

    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;
    }

由于我从 Web 服务收到 PNG 文件,因此我使用以下方法转换为 JPG:

    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;
}

根据这个链接:

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

指出错误是因为应该在创建 contentStream 之前创建 PDJepg 对象,但这就是我在代码中所做的。

我不确定我的代码结构是否存在问题,或者我处理从 Web 服务调用获得的图像字节的方式是否存在错误。

有人知道可能是什么问题吗?

更新

我做了 Zelter Ady 所做的事情,实际上我从 Web 服务获取的图像是有效的,因为我能够用它生成一个物理文件,所以问题应该是围绕图像的操作,事情我不知道我错过了什么。

【问题讨论】:

    标签: java pdf-generation pdfbox


    【解决方案1】:

    我也遇到了同样的问题。对于某些图像,Acrobat 无法显示带有以下消息的页面:

    图片数据不足

    我的问题来自一些 jpeg 图像中的 colorModel。 为了跟踪哪些图像不正确,我通过log.warn(img.getColorModel()); 记录了 BufferedImage colorModel

    [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
    

    显然,失败的图像是 8 位编码的。

    为了解决这个问题,我做了以下操作:

    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);
    ...
    

    重点是重新创建一个 24 位的 BufferedImage。 (BufferedImage.TYPE_3BYTE_BGR)。

    【讨论】:

      【解决方案2】:

      这可能是 Adob​​e 查看器方面的问题,而不是创建时的问题。最新 Acrobat 版本存在一个已知问题:更新到 10.1.4 或 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/

      【讨论】:

        【解决方案3】:

        在构建pdf之前尝试将图像保存在文件中,以查看图像是否完整并且可以保存。

        你可以使用这样的东西来测试接收到的图像:

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

        然后在图像查看器中打开图像。如果图像无法打开,那么你在这里有一个错误。如果图片没问题....至少你知道这部分没问题!

        【讨论】:

        • 好的。我这样做了,并且验证了我得到了一个有效的字节数组,因为我能够在物理文件夹中创建图像。所以现在我确定问题不是来自 Web 服务调用响应,我不确定问题出在哪里,我不知道 PDFBox 是否无法处理文件。
        【解决方案4】:

        好吧,经过大量调试后,我发现问题出在这里:

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

        PDJpeg 类有两个构造函数:

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

        我传递了一个 BufferedImage 并且在某些时候我仍然无法弄清楚,我假设所有字节都没有被完全发送,因此我收到了消息“图像数据不足” .

        解决方案:我传递的是 InputStream 而不是 BufferedImage。

        我仍然不知道为什么我在使用 BufferedImage 时会出现该错误,也许我需要执行某种 .push() 操作?

        【讨论】:

          【解决方案5】:

          这段代码对我有用。

          import java.awt.Dimension;
          import java.awt.image.BufferedImage;
          import org.apache.commons.imaging.Imaging;
          
          import org.apache.pdfbox.pdmodel.PDDocument;
          import org.apache.pdfbox.pdmodel.PDPage;
          import org.apache.pdfbox.pdmodel.PDPageContentStream;
          import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
          import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
          
          public void generatePdfFromTifPbox(File sourceFile, String destinationPath) throws Exception {
              //sourceFile is tiff file, destinationPath is pdf destination path with pdf file name
              PDDocument doc = new PDDocument();
              List<BufferedImage> bimages = Imaging.getAllBufferedImages(sourceFile);
              for (BufferedImage bi : bimages) {
              PDPage page = new PDPage();
              doc.addPage(page);
              PDPageContentStream contentStream = new PDPageContentStream(doc, page);
              try {
              // the .08F can be tweaked. Go up for better quality,
              // but the size of the PDF will increase
              PDImageXObject image = JPEGFactory.createFromImage(doc, bi, 0.08f);
              Dimension scaledDim = getScaledDimension(new Dimension(image.getWidth(), image.getHeight()),
              new Dimension((int) page.getMediaBox().getWidth(), (int) page.getMediaBox().getHeight()));
              contentStream.drawImage(image, 1, 1, scaledDim.width, scaledDim.height);
              } finally {
              contentStream.close();
              }
              }
              doc.save(destinationPath);
              }
          
          
          private Dimension getScaledDimension(Dimension imgSize, Dimension boundary) {
              int original_width = imgSize.width;
              int original_height = imgSize.height;
              int bound_width = boundary.width;
              int bound_height = boundary.height;
              int new_width = original_width;
              int new_height = original_height;
          
              // first check if we need to scale width
              if (original_width > bound_width) {
              // scale width to fit
              new_width = bound_width;
              // scale height to maintain aspect ratio
              new_height = (new_width * original_height) / original_width;
              }
          
              // then check if we need to scale even with the new height
              if (new_height > bound_height) {
              // scale height to fit instead
              new_height = bound_height;
              // scale width to maintain aspect ratio
              new_width = (new_height * original_width) / original_height;
              }
          
              return new Dimension(new_width, new_height);
              }
          

          参考/礼貌: http://www.paulzepernick.com/java/java-apache-pdfbox-convert-multipage-tiff-to-pdf/

          Maven 依赖:

          <dependency>
             <groupId>org.apache.pdfbox</groupId>
             <artifactId>pdfbox</artifactId>
             <version>2.0.3</version> 
          </dependency> 
              
              
          <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-imaging</artifactId>
             <version>1.0-alpha1</version>
          </dependency>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2023-03-09
            • 2011-04-20
            • 1970-01-01
            • 2012-12-01
            • 2014-09-17
            • 1970-01-01
            • 2012-07-18
            相关资源
            最近更新 更多