Java merging multiple JPEG files into single multi-page TIFF file [duplicate] - java

I am using JAI to load in multipage TIFF images
File file = workArea[0];
SeekableStream s = new FileSeekableStream(file);
TIFFDecodeParam param = null;
ImageDecoder dec = ImageCodec.createImageDecoder("tiff", s, param);
//first page
RenderedImage op1 =
new NullOpImage(dec.decodeAsRenderedImage(0),
null,
OpImage.OP_IO_BOUND,
null);
BufferedImage pg1 = new BufferedImage(op1.getWidth(), op1.getHeight(),
BufferedImage.TYPE_INT_RGB);
pg1.getGraphics().drawImage((Image) op1, 0, 0, null);
However, in the last line I get a runtime error of:
Exception in thread "main" java.lang.ClassCastException:
javax.media.jai.MullOpImage cannot be cast to java.awt.Image
I clear the RenderedImage after attempting to set the BufferedImage so I don't exactly "need" the RenderedImage if there is another method of doing this.
I attempted:
pg1.setData(op1.getData());
and that gives an ArrayIndexOutOfBoundsException. I'm not sure why exactly as pg1's width and height are set by op1's, but there is probably a very valid reason.

I found a solution at http://www.jguru.com/faq/view.jsp?EID=114602
The first one didn't work, however, the convertRenderedImage function did work.
public BufferedImage convertRenderedImage(RenderedImage img) {
if (img instanceof BufferedImage) {
return (BufferedImage)img;
}
ColorModel cm = img.getColorModel();
int width = img.getWidth();
int height = img.getHeight();
WritableRaster raster = cm.createCompatibleWritableRaster(width, height);
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
Hashtable properties = new Hashtable();
String[] keys = img.getPropertyNames();
if (keys!=null) {
for (int i = 0; i < keys.length; i++) {
properties.put(keys[i], img.getProperty(keys[i]));
}
}
BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties);
img.copyData(raster);
return result;
}

Use op1.getAsBufferedImage() to create pg1.

If you are stuck with a RenderedImage, you can use
PlanarImage.wrapRenderedImage(renderedImage).getAsBufferedImage()
see here for documentation

JAI apparently has a "converter" class in there:
ImageDecoder dec = ImageCodec.createImageDecoder("PNM", new File(input), null);
return new RenderedImageAdapter(dec.decodeAsRenderedImage()).getAsBufferedImage()
ref: http://www.programcreek.com/java-api-examples/index.php?api=com.sun.media.jai.codec.ImageDecoder

Try this :
RenderedImage im = dec.decodeAsRenderedImage();
BufferedImage bi = PlanarImage.wrapRenderedImage(im).getAsBufferedImage();

The easiest way to load TIFF is using Twelve Monkey with provide plugin to support TIFF format into Standard Java ImageIO.
Just add below Maven dependency,
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
<version>3.5</version>
</dependency>
Now, you will be able to load TIFF file directly Using ImageIO.
ImageReader imageReader1 = SPI.createReaderInstance();
ImageInputStream iis1 = ImageIO.createImageInputStream(new File("1.tif"));
imageReader1.setInput(iis1);
BufferedImage = imageReader1.read(0);
It is very easy and reliable because it uses standard Java ImageIO API for all processing.
Only the Plugin from Twelve Monkey provide the SPI plugin to provide support of TIFF.
Adding here one example program which is running is Java 8 and it reads TIFF files and create a single multi-page TIFF file:
BufferedImage b1 = null;
BufferedImage b2 = null;
TIFFImageReaderSpi SPI = new TIFFImageReaderSpi();
ImageReader imageReader1 = SPI.createReaderInstance();
ImageInputStream iis1 = ImageIO.createImageInputStream(new File("1.tif"));
imageReader1.setInput(iis1);
b1 = imageReader1.read(0);
ImageReader imageReader2 = SPI.createReaderInstance();
ImageInputStream iis2 = ImageIO.createImageInputStream(new File("2.tif"));
imageReader2.setInput(iis2);
b2 = imageReader2.read(0);
ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();
writer.setOutput(ImageIO.createImageOutputStream(new File("3.tif")));
ImageWriteParam writeParam = writer.getDefaultWriteParam();
//writeParam.setTilingMode(ImageWriteParam.MODE_EXPLICIT);
//writeParam.setCompressionType("Deflate");
writer.prepareWriteSequence(null);
IIOImage i1 = new IIOImage(b1, null, null);
IIOImage i2 = new IIOImage(b2, null, null);
writer.writeToSequence(i1, writeParam);
writer.writeToSequence(i2, writeParam);
writer.endWriteSequence();
writer.dispose();
It is working with Java 8, if someone wants to add compression just comment the line and add appropriate compression name.

Related

JAI Tiff to JPEG convertion issue

I have an issue converting Tiff-Files to JPEGs with JAI. This is my Code:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
TIFFDecodeParam param = null;
ImageDecoder dec = ImageCodec.createImageDecoder("tiff", new FileSeekableStream(inPath), param);
RenderedImage op = dec.decodeAsRenderedImage(0);
JPEGEncodeParam jpgparam = new JPEGEncodeParam();
jpgparam.setQuality(67);
ImageEncoder en = ImageCodec.createImageEncoder("jpeg", baos, jpgparam);
en.encode(op);
Mostly this code works fine, but with some Images, I got the following error:
java.lang.RuntimeException: Only 1, or 3-band byte data may be written.
at com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:142)
I cant find any related Problems over here and i have no idea how to fix it. The Images who throw this error have a high Resolution (9000 x 7000 or more) and are mostly scans of old pictures.
Image with this ColorModel works:
ColorModel:
#pixelBits = 24
numComponents = 3
color space = java.awt.color.ICC_ColorSpace#21981a50
transparency = 1 has alpha = false
isAlphaPre = false
This not:
ColorModel:
#pixelBits = 16
numComponents = 1
color space = java.awt.color.ICC_ColorSpace#88a30ad
transparency = 1 has alpha = false
isAlphaPre = false
I tried reading the JPEG standard, and it is not readily clear whether this is a limitation of the JPEG format or just the Encoder.
The encoder provide with java only encodes 1 or 3 byte bands, so in your case there are 16bit gray scale images. One way to solve this, as it appears you have done, is to save the image using a PNG encoder. It would not support the compression quality parameter.
The other way to handle this would be to save your image as an 8bit gray scale image.
I made a simple example to test this w/out JAI.
public static void main(String[] args) throws Exception{
BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_USHORT_GRAY);
Iterator<ImageWriter> writers = ImageIO.getImageWritersBySuffix("jpg");
while( writers.hasNext() ){
ImageWriter writer = writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream( new File("junk.jpg") );
writer.setOutput(ios);
writer.write(img);
}
}
The simplest way I can see to convert it is to create a new image and draw to it with a graphics.
BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = img2.getGraphics();
g.drawImage(img, 0, 0);
g.dispose();
Then img2 can be saved as JPG.

Exporting 8 bit-dpeth JPEG with ImageIO

Using Java ImageIO, is it possible to export a jpeg image that has a bit-depth of 8? How would I do this? Even when exporting a BufferedImage of TYPE_BYTE_BINARY, which is a grayscale image, the result is a JPEG with bit-depth of 24.
This is what I have so far.
public void testJpegBitDepth() throws Exception{
Path pIn = Paths.get("testing/jpg/box1.jpg"), pOut;
BufferedImage bi;
//*******************************************
//Write 8 bit jpg
//Init ImageWriter
Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = null;
while(it.hasNext()) {
try {
writer = it.next();
//Read input
bi = ImageIO.read(pIn.toFile());
if(bi == null)
throw new Exception("Failed to read input file: " + pIn);
//Convert to gray
bi = AWTImaging.convertToGray(bi);
log.debug("Num bands from the image raster: " + bi.getRaster().getNumBands());
pOut = test.outputDir.resolve("jpegBitDepth-8-"
+ pIn.getFileName().toString() + ".jpg");
//Init ImageTypeSpecifier
ImageTypeSpecifier imageType = ImageTypeSpecifier.createGrayscale(
8, //8 bits per pixel
DataBuffer.TYPE_BYTE, //stored in a byte
false); //unsigned
//Init WriteParam
ImageWriteParam param = writer.getDefaultWriteParam();
param.setDestinationType(imageType);
//Not sure if this is required or not, but the same Exception occurs either way
//param.setSourceBands(new int[] {0});
//Init meta
IIOMetadata meta = writer.getDefaultImageMetadata(imageType, param);
String metadataFormat = "javax_imageio_jpeg_image_1.0";
IIOMetadataNode root = new IIOMetadataNode(metadataFormat);
IIOMetadataNode jpegVariety = new IIOMetadataNode("JPEGvariety");
IIOMetadataNode markerSequence = new IIOMetadataNode("markerSequence");
//I think we want app0JFIF metadata here, as it can specify a grayscale image https://docs.oracle.com/javase/10/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
IIOMetadataNode app0JFIF = new IIOMetadataNode("app0JFIF");
root.appendChild(jpegVariety);
root.appendChild(markerSequence);
jpegVariety.appendChild(app0JFIF);
meta.mergeTree(metadataFormat, root);
//Export jpg
Files.deleteIfExists(pOut);
ImageOutputStream ios = ImageIO.createImageOutputStream(pOut.toFile());
writer.setOutput(ios);
writer.write(meta, new IIOImage(bi, null, meta), param);
log.debug("Succeded writing jpeg with writer: " + writer.getClass().toString());
break;
}catch(Exception e) {
log.error("Failed writing jpeg with writer: " + (writer != null ? writer.getClass().toString():"null"));
log.error("Ex: " + e);
}
}
}
I'm getting an Exception thrown from JpegImageWriter, here is the relevant stack trace:
Ex: javax.imageio.IIOException: Metadata components != number of destination bands
File=null,Class=com.sun.imageio.plugins.jpeg.JPEGImageWriter,Method=checkSOFBands,Line=-1
File=null,Class=com.sun.imageio.plugins.jpeg.JPEGImageWriter,Method=writeOnThread,Line=-1
File=null,Class=com.sun.imageio.plugins.jpeg.JPEGImageWriter,Method=write,Line=-1
Also I know that the Buffered Image is a TYPE_BYTE_BINARY, and the raster has 1 band (I printed this in a debug message above). So the Exception message would make me think that I need to define in the app0JFIF metadata that we are exporting 1 band. I don't know how to define this though, does anyone have any experience with this? This metadata is difficult to work with, or is it just me?
Thanks in advance.
You are correct about needing one band. Here’s how I did it:
if (bi.getSampleModel().getNumBands() != 1) {
ColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false,
Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
BufferedImage oneBandedImage = new BufferedImage(colorModel,
colorModel.createCompatibleWritableRaster(
bi.getWidth(), bi.getHeight()),
false, new Properties());
Graphics g = oneBandedImage.createGraphics();
g.drawImage(bi, 0, 0, null);
g.dispose();
bi = oneBandedImage;
}
After doing that, I didn’t need to directly obtain an ImageWriter and I didn’t need to set any metadata; ImageIO.write(bi, "JPEG", file) was sufficient.
I ran /usr/bin/file on the result, and got this:
JPEG image data, JFIF standard 1.02, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 315x180, components 1
I assume the components 1 part means that it has only one channel.

Tesseract : Index out of bounds exceptions for OCR method

I am working on a Spring-MVC application in which I am using Tesseract for OCR. I am getting an Index out of bounds exception for the file I am passing. Any ideas?
Error log :
et.sourceforge.tess4j.TesseractException: java.lang.IndexOutOfBoundsException
at net.sourceforge.tess4j.Tesseract.doOCR(Tesseract.java:215)
at net.sourceforge.tess4j.Tesseract.doOCR(Tesseract.java:196)
at com.tooltank.spring.service.GroupAttachmentsServiceImpl.testOcr(GroupAttachmentsServiceImpl.java:839)
at com.tooltank.spring.service.GroupAttachmentsServiceImpl.lambda$addAttachment$0(GroupAttachmentsServiceImpl.java:447)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IndexOutOfBoundsException
at javax.imageio.stream.FileCacheImageOutputStream.seek(FileCacheImageOutputStream.java:170)
at net.sourceforge.tess4j.util.ImageIOHelper.getImageByteBuffer(ImageIOHelper.java:297)
at net.sourceforge.tess4j.Tesseract.setImage(Tesseract.java:397)
at net.sourceforge.tess4j.Tesseract.doOCR(Tesseract.java:290)
at net.sourceforge.tess4j.Tesseract.doOCR(Tesseract.java:212)
... 4 more
Code :
private String testOcr(String fileLocation, int attachId) {
try {
File imageFile = new File(fileLocation);
BufferedImage img = ImageIO.read(imageFile);
BufferedImage blackNWhite = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics2D graphics = blackNWhite.createGraphics();
graphics.drawImage(img, 0, 0, null);
String identifier = String.valueOf(new BigInteger(130, random).toString(32));
String blackAndWhiteImage = previewPath + identifier + ".png";
File outputfile = new File(blackAndWhiteImage);
ImageIO.write(blackNWhite, "png", outputfile);
ITesseract instance = new Tesseract();
// Point to one folder above tessdata directory, must contain training data
instance.setDatapath("/usr/share/tesseract-ocr/");
// ISO 693-3 standard
instance.setLanguage("deu");
String result = instance.doOCR(outputfile);
result = result.replaceAll("[^a-zA-Z0-9öÖäÄüÜß#\\s]", "");
Files.delete(new File(blackAndWhiteImage).toPath());
GroupAttachments groupAttachments = this.groupAttachmentsDAO.getAttachmenById(attachId);
System.out.println("OCR Result is "+result);
if (groupAttachments != null) {
saveIndexes(result, groupAttachments.getFileName(), null, groupAttachments.getGroupId(), false, attachId);
}
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Thank you.
Due to a bug in Java Image IO (which was fixed with Java 9), the current version of Java Tesseract Wrapper (3.4.0 as this answer was written) does not work with < Java 9. To work with lower Java versions, you can try the following fix to Tesseract ImageIOHelper class. Simply make a copy of the class in your project and apply the necessary changes and it will work with both files and BufferedImages smoothly.
Note: This version does not use the Tiff optimization used in the original class, you can add it if it is necessary for your project.
public static ByteBuffer getImageByteBuffer(RenderedImage image) throws IOException {
//Set up the writeParam
if (image instanceof BufferedImage) {
return convertImageData((BufferedImage) image);
}
ColorModel cm = image.getColorModel();
int width = image.getWidth();
int height = image.getHeight();
WritableRaster raster = cm
.createCompatibleWritableRaster(width, height);
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
Hashtable properties = new Hashtable();
String[] keys = image.getPropertyNames();
if (keys != null) {
for (int i = 0; i < keys.length; i++) {
properties.put(keys[i], image.getProperty(keys[i]));
}
}
BufferedImage result = new BufferedImage(cm, raster,
isAlphaPremultiplied, properties);
image.copyData(raster);
return convertImageData(result);
}
Try upgrading to tess4j version 3.4.1.
That solved the issue for me.

CMYK Image display on pdf using pdfbox

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

antialiasing in java image scaling library

I am currently using http://code.google.com/p/java-image-scaling/ this library to generate scaled images for my web app.But when I scale down the image to about 100x100 size there are some leftover artifacts visible in some images. Is this an issue with antialiasing? And how do I use antialiasing with this library.The api documentation doesn't say any thing about it.
Here is the code
File f = new File("C:\\Users\\ad min\\Pictures\\30-whisky-3d-wallpaper-1152x864.jpg");
BufferedImage src = ImageIO.read(f);
//ResampleOp resampleOp = new ResampleOp(76, 76);
ResampleOp resampleOp = new ResampleOp(200,200);
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.VerySharp);
BufferedImage rescaled = resampleOp.filter(src, null);
ImageIO.write(rescaled, "JPG", new File(
"C:\\Users\\ad min\\Pictures\\scaleddown.jpg"));
what am I doing wrong?
I finally didn't need antialiasing I simply used this code given in the foloowing link and it worked :) whewww
http://www.universalwebservices.net/web-programming-resources/java/adjust-jpeg-image-
compression-quality-when-saving-images-in-java
Iterator<ImageWriter> iter = ImageIO
.getImageWritersByFormatName("jpeg");
ImageWriter writer = (ImageWriter) iter.next();
// instantiate an ImageWriteParam object with default compression
// options
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(1); // an integer between 0 and 1
// 1 specifies minimum compression and maximum quality
File file = new File("C:\\Users\\ad min\\Pictures\\scaleddown.jpg");
FileImageOutputStream output = new FileImageOutputStream(file);
writer.setOutput(output);
IIOImage image = new IIOImage(rescaled, null, null);
writer.write(null, image, iwp);
writer.dispose();

Categories