ImageIO.read illegal argument exception - raster bands/colour space components? - java

Apologies for the somewhat vague title, I can't work out what the keywords are here. The setup's quite simple, I'm opening an image with
ImageIO.read(new File(filename));
This works for most files, however for one I get an IllegalArgumentException with the detail: "numbers of source Raster bands and source color space components do not match". This image was obtained via wget on a valid Flickr URL, and I've used other images obtained this way, so the method for obtaining images seems sound in principle. I'm not sure what's causing the exception.
A workaround would be more than acceptable - I'm not fussed with using ImageIO in particular, and the image looks fine visually. I just need to get it being read without Java freaking out!
Here's the image in question, in case it's of any use:

So I was having this same issue and found that the image was gray-scale and that the default ImageIO.read implementation was not figuring that out because the image metadata wasn't quite as expected. I wrote a work around that retries the load as 'BufferedImage.TYPE_BYTE_GRAY' if it fails the main load.
Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
Exception lastException = null;
while (iter.hasNext()) {
ImageReader reader = null;
try {
reader = (ImageReader)iter.next();
ImageReadParam param = reader.getDefaultReadParam();
reader.setInput(stream, true, true);
Iterator<ImageTypeSpecifier> imageTypes = reader.getImageTypes(0);
while (imageTypes.hasNext()) {
ImageTypeSpecifier imageTypeSpecifier = imageTypes.next();
int bufferedImageType = imageTypeSpecifier.getBufferedImageType();
if (bufferedImageType == BufferedImage.TYPE_BYTE_GRAY) {
param.setDestinationType(imageTypeSpecifier);
break;
}
}
bufferedImage = reader.read(0, param);
if (null != bufferedImage) break;
} catch (Exception e) {
lastException = e;
} finally {
if (null != reader) reader.dispose();
}
}
// If you don't have an image at the end of all readers
if (null == bufferedImage) {
if (null != lastException) {
throw lastException;
}
}

The error message is informative and indicates that the number of raster bands, as mentioned in the ICC color profile, seems to be incorrect. I used ImageMagick to strip the ICC profile from the image. ImageIO subsequently has no problems reading the images (~1k bad images). Hope that helps.

It is possible to read this image using twelvemonkeys ImageIO, which is a more robust and forgiving replacement for the original ImageIO provided by the JRE.
See https://github.com/haraldk/TwelveMonkeys/
I found this solution in the PDF Box Jira https://issues.apache.org/jira/browse/PDFBOX-3637
In order to use twelvemonkeys, it is sufficient to add it as a maven dependency. It then registers itself before the default image processor.
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.3.2</version> <!-- Alternatively, build your own version -->
</dependency>

Related

Writing a BMP with transparency using ImageIO

Does anyone have a way of storing a BufferedImage with transparency as BMP in Java? Preferably using the ImageIO API.
For some reason I can't write a BMP in ARGB (BGRA) format, even though the BMP has supported alpha channel since, at least, Win95. I can, however, easily write the same image as a PNG. It also works fine storing an image without alpha, like TYPE_INT_RGB or TYPE_3BYTE_BGR.
Consider the following code snippet:
public static void main(String[] args) throws IOException {
if (!ImageIO.write(new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB), "BMP", new File("foo.bmp"))) {
System.err.println("Couldn't write BMP!");
}
if (!ImageIO.write(new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB), "PNG", new File("foo.png"))) {
System.err.println("Couldn't write PNG!");
}
}
Output:
Couldn't write BMP!
In BMPImageWriterSpi:
public boolean canEncodeImage(ImageTypeSpecifier type) {
...
if (!(numBands == 1 || numBands == 3))
return false;
I'm afraid Java doesn't support 32 bit BMPs. You'd have to write your own or find an existing library (ImageJ comes to mind although I don't know if it supports BMP). Wikipedia is very elaborate on the file format and it looks quite easy, even giving a complete field-by-field example of a 32-bit BMP.

Java ImageIO.read(URL) returning null when it shouldn't

Okay so I have spent about 15 hours trying to figure this out. I am working on this program that gets exported to a non-runnable jar file. The issue is I am trying to load an image in the jar and set it to a variable.
I HAVE looked at other posts and I think I have tried everything I could find but nothing seems to work.
I am not asking how to FIND the image as I can get the URL of the image, but then ImageIO.read(URL) is not throwing any exception, but returning null. The image is a .png which I have heard is compatible with ImageIO.read(). I am using an API so that is what the log() lines are.
Any help is appreciated. Thank you!
My Project:
Project
->src
-->package
--->Main.java
--->paint.png
My Code:
In my main method:
(mainPaint is a private Image)
mainPaint = getImage("paint.png");
The method:
private Image getImage(String fileName) {
URL url = getClass().getResource(fileName);
BufferedImage image = null;
log(url.toString()); // To make sure I have the correct file
// returning jar:file:/C:/Users/Me/MyJar.jar!/package/paint.png
try {
image = ImageIO.read(url);
} catch (IOException e1) {
log("Error converting url to image.");
// This is not happening
}
if (image == null) {
log("Image is null.");
// This is happening
}
return image;
}
Is the URL invalid? Am I just missing something? I'm just trying to save the local image in the jar as an Image object, I feel like this is way too difficult for what I am trying to do.
EDIT:
I also just tried making mainPaint a BufferedImage and using:
Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource(fileName));
if(image == null) {
log("Image is null");
}
log("Height: " + image.getHeight(null));
log("Width: " + image.getWidth(null));
BufferedImage bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(image, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
The height and width of the image are returning -1?
ImageIO.read() will not load SVG files, so if your images are in SVG formate you will need to add plugins to it to support SVG
Here is another SO post that explain where you can do that.
ImageIO.read() will load only GIF, PNG, JPEG, BMP, and WBMP image types.
Any other image type will return null without error.
It could answer to your question .

Zxing Format Exception in Scanning PDF and converting to Buffered Image to Decode QR

I'm having problem with getting continuous successful QR decoding after PDF conversion. I keep getting,
"Exception in thread "main" com.google.zxing.FormatException."
My conversion attempts were done in:
PDFBox
public static BufferedImage convertPDFtoBufferedImageType2(String PDFPath) throws IOException{
PDDocument document = null;
try {
document = PDDocument.load(PDFPath);
PDPage firstPage = (PDPage) document.getDocumentCatalog().getAllPages().get(0);
return firstPage.convertToImage();
} catch (IOException ex) {
Logger.getLogger(PDF_Utility.class.getName()).log(Level.SEVERE, null, ex);
return null;
} finally {
if(document != null)
document.close();
}
}
Second Attempt with ghost4j
public static BufferedImage convertPDFtoBufferedImage(String PDFPath) throws IOException, RendererException, DocumentException{
System.setProperty("jna.library.path", "C:\\Program Files\\gs\\gs9.16\\bin\\");
PDFDocument document = new PDFDocument();
document.load(new File(PDFPath));
SimpleRenderer renderer = new SimpleRenderer();
renderer.setResolution(300);
List<Image> imgs = renderer.render(document);
Image im = imgs.get(0);
BufferedImage bi = new BufferedImage
(im.getWidth(null),im.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics bg = bi.getGraphics();
bg.drawImage(im, 0, 0, null);
bg.dispose();
return bi;
}
My QR Decoder is:
public static String readQRCode(BufferedImage image, String charset, Map hintMap)
throws FileNotFoundException, IOException, NotFoundException, ChecksumException, FormatException {
Result qrCodeResult = null;
BinaryBitmap binaryBitmap = new BinaryBitmap(
new HybridBinarizer(new BufferedImageLuminanceSource(image)));
try{
qrCodeResult = new com.google.zxing.qrcode.QRCodeReader().decode(binaryBitmap,hintMap);
}catch(NotFoundException | FormatException e){ //attempt without hints
qrCodeResult = new com.google.zxing.qrcode.QRCodeReader().decode(binaryBitmap);
}
return qrCodeResult.getText();
}
And the reason why I called decode twice was because sometimes the "try harder"
hintMap.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
actually didn't catch the QR code, but the default did.
Anyways, these code snippets do catch most of my QR scans from a pile of documents, but there are times where it does not catch it at all. I even attempted to write it out as an image and then re-read it in:
ImageIO.write((RenderedImage) im, "png", new File("/path/to/my/img.png"));
Interestingly, http://zxing.org/w/decode.jspx does decode that output image, but my code couldn't.
I also tried different charset:
CHAR_SET = "UTF-8"; and CHAR_SET = "ISO-8859-1";
By getting Format Exceptions, the code was found, but "did not conform to the barcode's format rules. This could have been due to a mis-detection."
Apology for the messy code, but those attempts have gained majority of successful scans. 9/10 rate? Interestingly, sometimes another scanned copy of the same doc worked. Any help/advice/crazy voodoo combination is appreciated! Thanks!
EDIT: I got a sample (after whiting out the contents around. The real image has contents! Zxing website was able to catch this QR code too (with and without contents! (My program already ignored the other 1Ds at this same format and those with contents).
#Tilman Hausherr pointed out for the PDFBox default rendering size as low so I changed the default to 300dpi as he suggested. Overall, it worked for my case but definitely slowed down the speed. Will need to tweak my algorithm to run both a fast and this slower one as a backup.
return firstPage.convertToImage(BufferedImage.TYPE_4BYTE_ABGR, 300);
EDIT: Increased the success rate of catching barcodes, but did not successfully catch all. Increasing the dpi does not help.

BufferedImage get resized with different colors

I am resizing many jpeg images using Apache Sanselan which also deals with CMYK colors.
I have a problem when trying to convert jpeg images that has an alpha channel... when doing it the result is an image with different colors, and i guess that java somehow handles these type of images as a different color format.
As i said, the RGB resizing works fine as well as CMYK. ARGB images turn out with different colors.
An example:
Any suggestions? Can i force somehow ignore the alpha channel and handle the image as an RGB image? or convert it to be an RGB image without losing the real colors?
The code that handles this image is:
ImageInputStream stream = ImageIO.createImageInputStream(file);
Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
while (iter.hasNext()) {
ImageReader reader = iter.next();
reader.setInput(stream);
BufferedImage image = null;
ICC_Profile profile = null;
try {
image = reader.read(0);
} catch (IIOException e) {
... (CMYK conversion if needed)
}
return image;
}
return null;
Thanks in advance
I found a good solution here (first solution worked great):
problem using ImageIO.write jpg file
Edit:
There is a new open source library which supports CMYK processing.
All you need to do is to add the dependency to your project and a new reader will be added to the list of readers (while the known JPEGImageReader can't deal with CMYK).
You will probably want to iterate over these readers and read the image using the first reader which doesn't throw exception.
This package is a release candidate, but i am using it and it solved a huge problem that we had hard time dealing with.
http://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-jpeg/3.0-rc5
You can do the iteration this way to get the BufferedImage, and after you got that, the rest is easy (you can use any existing image converting package to save it as another format):
try (ImageInputStream input = ImageIO.createImageInputStream(source)) {
// Find potential readers
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
// For each reader: try to read
while (readers != null && readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(input);
BufferedImage image = reader.read(0);
return image;
} catch (IIOException e) {
// Try next reader, ignore.
} catch (Exception e) {
// Unexpected exception. do not continue
throw e;
} finally {
// Close reader resources
reader.dispose();
}
}
// Couldn't resize with any of the readers
throw new IIOException("Unable to resize image");
}

Saving colorspace in jpeg

I have a servlet to convert and cache smaller versions of photographs. It is implemented using java.awt.image + javax.imageio and a third party resample filter. The originals are all uploaded with an sRGB color profile. When I resample them and save them again they still are in sRGB however this is not recorded in the saved file.
How can I make sure this information is saved in the file?
In case you wondered it makes a difference, images without a profile are much more saturated on my screen (Safari + OSX + Calibrated screen) then when they have the correct sRGB profile. Also I'm sure it's the missing profile information and not the resampling algorithm.
Turns out it is enough to include an EXIF tag ColorSpace=1 that tells it should be processed as sRGB. Succeeded into doing this using Apache Commons Sanselan. This library is unfortunatly not complete so it can only be used to modify the EXIF after the file has been created.
Relevant code, based on Sanselan example:
public void addExifMetadata(File jpegImageFile, File dst)
throws IOException, ImageReadException, ImageWriteException {
OutputStream os = null;
try {
TiffOutputSet outputSet = new TiffOutputSet();
TiffOutputField colorspace = TiffOutputField.create(
TiffConstants.EXIF_TAG_COLOR_SPACE, outputSet.byteOrder, new Integer(1));
TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory();
exifDirectory.add(colorspace);
os = new FileOutputStream(dst);
os = new BufferedOutputStream(os);
new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
os.close();
os = null;
} finally {
if (os != null)
try {
os.close();
} catch (IOException e) {
}
}
}

Categories