我正在使用 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;
}
根据此链接:
它指出错误是因为PDJepg对象应该在创建contentStream之前创建,但这就是我在代码中所做的。
我不确定我的代码结构是否有问题,或者我正在处理从Web服务调用中获取的图像字节的方式可能存在错误。
有没有人知道可能出现什么问题?
更新
我做了什么Zelter Ady,实际上我从Web服务获得的图像是有效的,因为我能用它生成一个物理文件,所以问题应该是在图像的操作周围,事情我不知道我错过了什么。
答案 0 :(得分:3)
我遇到了同样的问题。对于某些图像,Acrobat无法显示包含此消息的页面:
图像数据不足
我的问题来自某些jpeg图片中的colorModel。
要跟踪哪些图像不正常,请按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
显然,失败的图像是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
)。
答案 1 :(得分:2)
这可能是Adobe查看者方面的问题,而不是创建时的问题。最新的Acrobat版本存在一个已知问题:更新到10.1.4或9.5.2后出现“图像数据不足”错误:
答案 2 :(得分:1)
在构建pdf之前,尝试将图像保存在文件中,只是为了查看图像已完成并可以保存。
您可以使用类似的方法测试收到的图像:
System.IO.File.WriteAllBytes("c:\\tmp.png", (byte[]) singleImageMap.get(Constants.FRONT));
然后在imageviewer中打开图像。如果图像无法打开,那么你在这里有错误。如果图像没问题......至少你知道这部分还可以!
答案 3 :(得分:1)
经过大量调试后,我发现问题出在这里:
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()?
答案 4 :(得分:0)
此代码对我有用。
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>