I'm writing a simple scanning application using jfreesane and Apache PDFBox.
Here is the scanning code:
InetAddress address = InetAddress.getByName("192.168.0.17");
SaneSession session = SaneSession.withRemoteSane(address);
List<SaneDevice> devices = session.listDevices();
SaneDevice device = devices.get(0);
device.open();
device.getOption("resolution").setIntegerValue(300);
BufferedImage bimg = device.acquireImage();
File file = new File("test_scan.png");
ImageIO.write(bimg, "png", file);
device.close();
And making PDF:
PDDocument document = new PDDocument();
float width = bimg.getWidth();
float height = bimg.getHeight();
PDPage page = new PDPage(new PDRectangle(width, height));
document.addPage(page);
PDImageXObject pdimg = LosslessFactory.createFromImage(document, bimg);
PDPageContentStream stream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true);
stream.drawImage(pdimg, 0, 0);
stream.close();
document.save(filename);
document.close();
And here is the result:
As you can see the PDF image is more "pale" (saturation? - sorry, I'm not good at color theory and don't know how to name it correctly).
What I have found out:
Printing BufferedImage to JLabel using JLabel(new ImageIcon(bimg))
constructor produces the same result as with PDF ("pale" colors)
so I guess PDFBox is not the reason.
Changing scanning resolution -
no effect.
bimg.getTransparency() returns 1 (OPAQUE)
bimg.getType() returns 0 (TYPE_CUSTOM)
PNG file:
http://s000.tinyupload.com/index.php?file_id=95648202713651192395
PDF file
http://s000.tinyupload.com/index.php?file_id=90369236997064329368
There was an issue in JFreeSane with colorspaces, it was fixed in version 0.97:
https://github.com/sjamesr/jfreesane/releases/tag/jfreesane-0.97
Related
I am trying to create pdf in java using pdfbox 1.8, but problem is I am not able to show CMYK image on pdf so I try to solution on same like below code:
File filePath = new File("C:/Users/msuryawanshi/Documents/10734730431625_C1LA.jpg");
JPEGImageDecoder jpegDecoder = JPEGCodec.createJPEGDecoder(new FileInputStream(filePath));
BufferedImage image = jpegDecoder.decodeAsBufferedImage();
imageUrl = "http://extranet.handgards.com/gs1/10734730431625_C1LA.jpg";
File f = new File("C:/Users/msuryawanshi/Documents/10734730431625_C1LA.jpg");
String url = "http://extranet.handgards.com/gs1/10734730431625_C1LA.jpg";
Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
ImageReader reader = null;
while (readers.hasNext()) {
reader = (ImageReader) readers.next();
if (reader.canReadRaster()) {
break;
}
}
//Stream the image file (the original CMYK image)
ImageInputStream input = ImageIO.createImageInputStream(f);
reader.setInput(input);
//Read the image raster
Raster raster = reader.readRaster(0, null);
//Create a new RGB image
BufferedImage bi = new BufferedImage(raster.getWidth(), raster.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
//Fill the new image with the old raster
bi.getRaster().setRect(raster);
PDXObjectImage ximage = new PDPixelMap(document, bi);
contentStream.drawXObject(ximage, margin + 5, texty, 170, 100);
but image is not meaningful, I have attached output pdf and original image which i want display on my pdf. please help for the same.
PDFBox doesn't support embedding CMYK images at all because java itself can't read such images. You might be able to embed it as an RGB image by using the twelvemonkeys library instead of Java ImageIO to read the JPEG into a BufferedImage. From there, just use PDPixelMap (in 1.8) or LosslessFactory (in 2.0).
I did split PDF to JPEG images using PDFBox version 2.0.2. At first, I did just coding as sample like thatÖ
BufferedImage image = pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.RGB);
And now, I want to convert this image to PDF, but the image DPI is so large.
I really want to reduce dpi. So I tried this, but it also didn't work:
PDImageXObject pdImageXObject = JPEGFactory.createFromImage(doc, bimg, 0.5f, 100);
How can I reduce DPI?
This is my source code:
InputStream in = new FileInputStream(imagePath);
BufferedImage bimg = ImageIO.read(in);
float width = bimg.getWidth() ;
float height = bimg.getHeight();
PDPage page = new PDPage(new PDRectangle(width, height));
doc.addPage(page);
//PDStream stream = new PDStream(doc, in);
PDImageXObject pdImageXObject = JPEGFactory.createFromImage(doc, bimg, 0.5f, 10);
PDPageContentStream contentStream = new PDPageContentStream(doc, page);
contentStream.drawImage(pdImageXObject, 0, 0);
contentStream.close();
}
} finally {
System.out.println("ddd");
doc.save(pdfPath);
doc.close();
}
}
There are 2 problems:
1) page size. It is not done in pixels but in page units. 1 unit = 1/72 inch. So your rectangle would be calculated like this:
PDPage page = new PDPage(new PDRectangle(width / 300 * 72, height / 300 * 72));
2) scale image. At 300dpi it must be scaled by 72/300 because the 1:1 is 72 dpi.
float scale = 72 / 300;
contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth()*scale, pdImage.getHeight()*scale);
Btw using JPEGFactory is not a good idea, because some quality will be lost. Use LosslessFactory instead.
About your use of the dpi parameter of JPEGFactory - that is just metadata. It doesn't scale anything.
If you really want to "reduce dpi", then render the PDF at 72 dpi instead of 300, then you don't need the scaling when creating the new PDF.
I had a similar problem and I solved it using the following:
PDPage page = new PDPage(PDRectangle.A4);
PDImageXObject pdImage = PDImageXObject.createFromFile(imgFile, doc);
PDPageContentStream contents = new PDPageContentStream(doc, page, false, false);
contents.drawImage(pdImage, 0, 0, PDRectangle.A4.getWidth(), PDRectangle.A4.getHeight());
Im trying to add a TIFF image (CCIT Group 3) to a PDF using Java and PDFBox 1.8.10. There is an image shown on the output file, but its displayed wrong. Its only some black and white pixels.
String outputPath = "/tmp/PDFImage.pdf";
String imagePath = "/tmp/header.tif";
PDDocument doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
PDPageContentStream content = new PDPageContentStream(doc, page);
PDXObjectImage ximage = new PDCcitt(doc, new RandomAccessFile(new File(imagePath), "r"));
content.drawImage(ximage, 0, 500);
content.close();
doc.save(outputPath);
doc.close();
The PDFBox dependencies says : To write TIFF images a JAI ImageIO Core library will be needed.
I imported the library and and scanned for plugins, but dont found an example how to use is exactly. Someone can help ?
I'm using pdxbox on google app engine, I use modifed version to be compatible with app engine (https://stackoverflow.com/a/12342272/2459131).
But I'm not able to add image in pdf. Because : javax.imageio.ImageIO is a restricted class
I need to make this work :
BufferedImage awtImage = ImageIO.read(new File(image));
I found two link that can help but I don't know how to use it :
https://github.com/pascalleclercq/appengine-awt/releases/tag/appengine-awt-1.0.0
http://mvnrepository.com/artifact/fr.opensagres.xdocreport.appengine-awt/appengine-awt/1.0.0
--> import in my project but com.google.code.appengine.awt.image.BufferedImage cannot be use in pdfbox's method
Edit :
PDDocument document = new PDDocument();
PDPage tmp = (PDPage) PDDocument.load("WEB-INF/pdfs/TemplateFactureEmpty3.pdf").getDocumentCatalog().getAllPages().get(0);
document.addPage(tmp);
PDPageContentStream content = new PDPageContentStream(document, tmp, true, true);
// choice 1 , pb : call ImageIO restricted
InputStream in = new FileInputStream(new File("WEB-INF/CokeLogo1.png"));
PDJpeg ximage = new PDJpeg(document, in);
// choise 2 , pb : BufferedImage and ImageIO restricted
BufferedImage awtImage = ImageIO.read(new File("WEB-INF/CokeLogo1.png") );
PDXObjectImage ximage = new PDPixelMap(document, awtImage);
float scale = 1f; // alter this value to set the image size
content.drawXObject(ximage, 56, 800, ximage.getWidth() * scale,ximage.getHeight() * scale);
Thanks,
Francois
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.
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!
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()?
This code worked for me.
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);
}
Reference/Courtesy: http://www.paulzepernick.com/java/java-apache-pdfbox-convert-multipage-tiff-to-pdf/
Maven dependency:
<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>