Problems writing TIFF files with ImageIO - java

I'm using Java 11, attempting to write compressed TIFF images with ImageIO. Most images write correctly, but some images throw an IIOException from within the javax.imageio code. My application is using Graphics 2D to resize images, then writing them to file. The Exception is:
javax.imageio.IIOException: I/O error writing TIFF file!
Here is the code snippet where I create the ImageWriter and write the image. The Exception is thrown from the last line in this snippet, tiffWriter.write().
//Create the TiffWriter, tell it where to write
ImageWriter tiffWriter = ImageIO.getImageWritersByFormatName("tiff").next();
tiffWriter.setOutput(imageOut);
//Wrap up the BufferedImage and Metadata in the IIOImage
IIOImage iioImg = new IIOImage(bi, null, meta);
//Set some writing parameters, so we get the G4 compression
ImageWriteParam writeParam = tiffWriter.getDefaultWriteParam();
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType(COMPRESSION_TYPE_GROUP4FAX);
//Write the image
tiffWriter.write(null, iioImg, writeParam);
The relevant stack trace entries are:
File=TIFFImageWriter.java,Class=com.sun.imageio.plugins.tiff.TIFFImageWriter,Method=write,Line=2612
File=TIFFImageWriter.java,Class=com.sun.imageio.plugins.tiff.TIFFImageWriter,Method=write,Line=2315
There is no further information given. So I'm not really sure what steps to take next. I know that I have write permission in the destination location. I can't seem to find any pattern with the images that fail the write operation. It seems like a roughly 20% failure rate in my sample.
Has anyone else experienced this error when writing TIFF files?
EDIT:
Just to clarify, I am setting the compression type to "CCITT T.6". The compression definitely has something to do with this error. If I omit the lines:
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType(COMPRESSION_TYPE_GROUP4FAX);
Then the IIOException is not thrown!
In my batch of test images, the same images fail no matter what the compression type is. But if there is no compression, all images are written successfully.
So I guess the question is, why does writing a compressed image fail here?

Related

It is possible to use the TessAPI1.TessPDFRendererCreate API of tess4J without needing to create physical files?

I am using the Tesseract Java API (tess4J) to convert Tiff images to PDFs.
This works nicely, but I am forced to write both the source Tiff image and the output PDF to local filestore as actual physical files in order to use the TessAPI1.TessPDFRendererCreate API.
Please note the following in the code snippet below: -
The input Tiff is originally a java.awt.image.BufferedImage, but I have to write it to a physical file (sourceTiffFile is a File object).
I must specify a file path for the output (pdfFullFilepath is a String representing an absolute path for the new PDF file).
try {
ImageIO.write(bufferedImage, "tiff", sourceTiffFile);
} catch (Exception ioe) {
//handling code...
}
TessResultRenderer renderer = TessAPI1.TessPDFRendererCreate(pdfFullFilepath, dataPath, 0);
TessAPI1.TessResultRendererInsert(renderer, TessAPI1.TessPDFRendererCreate(pdfFullFilepath, dataPath, 0));
int result = TessAPI1.TessBaseAPIProcessPages(handle, sourceTiffFile.getAbsolutePath(), null, 0, renderer);
I would really like to avoid creating physical files, but am not sure if it is possible with this API. Ideally, I would like to pass the Tiff as a java.awt.image.BufferedImage or a byte array and receive the output PDF as a byte array.
Any suggestions would be most welcome as always. Thank you :)
You can pass in ProcessPage API method a Pix, which can be converted from a BufferedImage, but the output will still be a physical file. Tesseract API dictates that.
https://tesseract-ocr.github.io/tessapi/4.0.0/a01625.html
http://tess4j.sourceforge.net/docs/docs-4.4/net/sourceforge/tess4j/TessAPI1.html
For ex:
int result = TessAPI1.TessBaseAPIProcessPage(handle, LeptUtils.convertImageToPix(bufferedImage), page_index, "input file name", null, 0, renderer);

Does ImageIO.read() take EXIF orientation metadata into account?

In JPEG images, EXIF metadata is sometimes included and tells in what orientation the image should be shown.
The question is, whether Java's ImageIO.read() takes EXIF into account while reading a JPEG image, and automatically applies the transformation.
More concretely, if I use Java's ImageIO for converting a JPEG image with EXIF into a PNG image, is the orientation of the PNG image going to be correct? Or is the below code going to produce a PNG image without taking EXIF orientation instructions into account?
private byte[] convertToPng(byte[] imageFileAsByteArray) {
ByteArrayInputStream bis = new ByteArrayInputStream(imageFileAsByteArray);
BufferedImage bi = ImageIO.read(bis);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(bi, "png", bos);
return bos.toByteArray();
}
The short answer is, unfortunately, no; ImageIO.read(..) (by default) does not take the Exif Orientation tag into account. Your PNG will be not be rotated accordingly.
However, all ImageIO.read(..) does internally, is to look up an appropriate ImageReader plug-in for the input, and delegate reading to it. And while the JRE-bundled plug-in does not take Exif into account, it is possible to add support for it, in a third-party ImageReader. Unfortunately, I don't know of any that do, but I am considering adding Exif orientation support to the TwelveMonkeys ImageIO JPEGImageReader in the future.
In the mean time, you have to apply the rotation yourself, by reading the metadata and rotating. The value of the orientation tag can be acquired either using the ImageIO JPEG metadata or some third-party library. I think both the mentioned metadata-extractor or TwelveMonkeys ImageIO can be used for this purpose. JAI ImageIO (using the TIFF metadata) can probably also do this.
If using the ImageIO JPEG metadata, be aware:
Note that an application wishing to interpret Exif metadata given a metadata tree structure in the javax_imageio_jpeg_image_1.0 format must check for an unknown marker segment with a tag indicating an APP1 marker and containing data identifying it as an Exif marker segment.
I have struggled with jpeg exif orientation for awhile, and now that I set out to fix my problems, I find that they are gone. To make sure for myself, I simplified OP.s example so as to read
public static void main (String [] args) throws Exception {
java.io.File in = new java.io.File ("in.jpg");
java.io.File out = new java.io.File ("out.png");
BufferedImage image = ImageIO.read (new FileInputStream(in));
ImageIO.write (image, "png", out);
}
in.jpg is a picture with exif orientation tag 8, tilted to the left. When I run the example, out.png is created as a properly oriented png picture. So it seems that ImageIo has learned something recently.

Decoding of old style JPEG-in-TIFF data is not supported

I need to display the 3rd page of scanned tiff files. i used the code
TIFFReader reader = new TIFFReader(new File(pathOfFile));
RenderedImage image = reader.getPage(2);
its sometimes work. and show error : Decoding of old style JPEG-in-TIFF data is not supported.
I used aspriseTIFF.jar
then how i solve this problem.
please reply.
thanks in advance
The problem you have run into is that "old style" JPEG compression in the TIFF format (compression == 6), is not supported in the library you use.
This is quite common I guess, as "old-style" JPEG compression is deprecated in TIFF, because it was never fully specified. And because of this under-specification, various vendors implemented it in different, incompatible ways. Support was dropped in favor for TIFF compression 7, JPEG.
Unfortunately, old TIFF files using this compression still exists, so you need to find another library. The good news is that you can use ImageIO and a proper plug-in.
Using a TIFF ImageReader plug-in, like the one from my TwelveMonkeys ImageIO open source project, you should be able to do this:
// Create input stream
try (ImageInputStream input = ImageIO.createImageInputStream(file)) {
// Get the reader
ImageReader reader = ImageIO.getImageReaders(input).next();
try {
reader.setInput(input);
// Read page 2 of the TIFF file
BufferedImage image = reader.read(2, null);
}
finally {
reader.dispose();
}
}
(sorry about the try/finally boiler-plate, but it is important to avoid resource/memory leaks).

DICOM JPEG compression not yet supported in Android

DicomDroid.jar used to open a .dcm formated image in my Android application. I got the follwing exception when try to open it.
java.io.IOException: DICOM JPEG compression not yet supported
Adding my code below
try {
// Read the imagefile into a byte array (data[])
File imagefile = new File(path);
byte[] data = new byte[(int) imagefile.length()];
FileInputStream fis = new FileInputStream(imagefile);
fis.read(data);
fis.close();
// Create a DicomReader with the given data array (data[])
DicomReader DR = new DicomReader(data);
} catch (Exception ex) {
Log.e("ERROR", ex.toString());
}
What can be done to avoid this error?
Thanks in advance.
The cause is pretty obvious. That DICOM library doesn't support that particular kind of DICOM file.
There's not much you can do about it ... unless you are prepared to enhance the library yourself.
But I think you have probably made a mistake in setting up your instrument to generate DICOM files with JPEG compression. JPEG is lossy, and best practice is to capture and store images with the best resolution feasible. If you need to downgrade resolution to reduce bandwidth, it would be better to
save a high resolution DICOM,
convert the DICOM to a low resolution JPG, and
send the JPEG.
Another option is to get the Dicom file in an uncompressed format (ej: Explicit VR Little Endian). This is the simplest dicom file format and every dicom library has support for such format.
So, when you get your Dicom file from your PACS, force this transfer syntax. This way, your dicom library will be able to deal with the image file.

error in sending image from android to java app serially -javax.imageio.IIOException: Bogus Huffman table definition

I need to send image from android app to java app. Basically, I need a byte array from the image to send to rf module which transmits.Another rf module receives and sends the byte array to java app which must make the image .
Android code:
FileInputStream fis = new FileInputStream(myFile);
byte[] b=new byte[(int)myFile.length()];
fis.read(b);server.send(b);
Java code:
FileOutputStream fwrite = new FileOutputStream(new File("my_xml"),true);
fwrite.write(bb);//bb is a byte from rf using input stream as soon as a byte comes it is read to file. This is necessary for some other reasons
fwrite.flush();
fwrite.close();
After getting full file:
FileInputStream fir=new FileInputStream("my_xml");
final BufferedImage bufferedImage = ImageIO.read(fir);
ImageIO.write(bufferedImage, "bmp", new File("image.bmp"));
fir.close();
I am getting error javax.imageio.IIOException: Bogus Huffman table definition
The rf is working fine because text file is being sent perfectly.Please help.Even without ImageIo code is not giving image even after changing extension to jpeg
The error means that the image file cant be read because the format is wrong.That is some bytes are missing or wrong or out of proper position and therefore file cant be decoded. My rf transfer does not have protocols like tcp/ip therefore some bytes are lost due to error in communication channel and hence the error.
You don't need to use ImageIO just to copy a file. Just read and write the bytes.
Your code has other problems:
You are assuming that read(byte[]) fills the buffer. It doesn't. Check the Javadoc.
You are also assuming that the file length fits into an int. If it does, fine. If it doesn't, you are hosed.
You appear to be opening and closing the FileOutputStream on every byte received. This could not be more inefficient. Open it once, write everything, close it.
flush() before close() is redundant.
You are storing the image in a file called 'my_xml'. This is only going to cause confusion, if it hasn't already.
You don't even need the file. Just load the image directly from the input stream.

Categories