TGA 4BYTE_BGRX image fails to transform. Possible cause in custom bandoffsets for 32-bit depth of image
See original GitHub issueDescribe the bug Filtering certain TGA images results in an exception:
java.awt.image.ImagingOpException: Unable to transform src image
Explanation below with code example.
Version information
-
The version of the TwelveMonkeys ImageIO library in use.
3.7.0
, the TGA plugin. -
The exact output of
java --version
(orjava -version
for older Java releases).
$ java -version
openjdk version "1.8.0_275"
OpenJDK Runtime Environment Corretto-8.275.01.1 (build 1.8.0_275-b01)
OpenJDK 64-Bit Server VM Corretto-8.275.01.1 (build 25.275-b01, mixed mode)
- Extra information about OS version, server version, standalone program or web application packaging, executable wrapper, etc. Please state exact version numbers where applicable.
A jar with some GC flags, cannot share full details.
To Reproduce Steps to reproduce the behavior:
- Compile the below sample code
- Use the provided sample image
- Run the code with the sample file
- See error
I don’t know for sure why this happens, though I suspect it has to do with this: https://github.com/haraldk/TwelveMonkeys/blob/master/imageio/imageio-tga/src/main/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReader.java#L141
If the bitdepth is 32, a TGAImageReader will return an ImageTypeSpecifier
with bandOffsets: new int[] {2, 1, 0, 3}
This, combined with how BufferedImage behaves, I suspect is the root cause of the issue. But I can’t be sure.
Expected behavior The file gets filtered without error
Example code
File orig = new File(...); // Absolute path to file
ImageInputStream input = ImageIO.createImageInputStream(orig); // javax.imageio.ImageIO
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
ImageReader reader = readers.next();
reader.setInput(input);
ImageReadParam param = reader.getDefaultReadParam();
// This is where the bandOffset gets set to what it is.
BufferedImage originalImage = reader.getImageTypes(0).next().createBufferedImage(reader.getWidth(0), reader.getHeight(0));
param.setDestination(originalImage);
try {
originalImage = reader.read(0, param); // Don't really need the return value here, as it will always be same value as "image"
} catch (javax.imageio.IIOException e) {
// See: https://github.com/haraldk/TwelveMonkeys/issues/197
// Ignore this exception or display a warning or similar, for exceptions happening during decoding
logger.warn(e.getMessage(), e);
}
int width = 240; // Known for this image
int height = 164; // Known for this image
AffineTransform transform = new AffineTransform();
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
BufferedImage resultImage = op.createCompatibleDestImage(originalImage, (originalImage.getType() == BufferedImage.TYPE_BYTE_GRAY) ? originalImage.getColorModel() : null);
Graphics2D g = resultImage.createGraphics();
g.setBackground(Color.WHITE);
g.clearRect(0, 0, resultImage.getWidth(), resultImage.getHeight());
resultImage = op.filter(originalImage, resultImage); // The exception happens here
When creating the bufferedimage, it will pass here: https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/master/jdk/src/share/classes/java/awt/image/BufferedImage.java#L785-L801
The condition:
offs[0] == numBands-1 &&
offs[1] == numBands-2 &&
offs[2] == numBands-3
Will fail, as there are 4 bands. 4 minus 1 is 3, but the first item of 2,1,0,3
isn’t 3
. At this point the code has no alternative and the BufferedImage ends up with imageType
TYPE_CUSTOM
.
The code ends up here: https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/master/jdk/src/share/classes/java/awt/image/AffineTransformOp.java#L284
And inside that method goes here: https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/master/jdk/src/share/classes/sun/awt/image/ImagingLib.java#L254
transformBI
is a native method, I can’t find details on how it works.
The condition fails and retBI
never gets assigned. It is returned as null
. Which causes the exception.
Sample file(s) This file from this repo can cause it: https://github.com/haraldk/TwelveMonkeys/blob/master/imageio/imageio-tga/src/test/resources/tga/XING_T32.TGA
Stack trace
java.awt.image.ImagingOpException: Unable to transform src image
at java.awt.image.AffineTransformOp.filter(AffineTransformOp.java:285)
// Own code
Sorry if this is a lot. I spent quite some time debugging it and am not even sure of what I saw anymore.
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (7 by maintainers)
Top GitHub Comments
Fix confirmed. I added a quick unit test using the code I put up there, and ran it once on master, once on an older git commit. Most recent code runs fine, older code gives the expected error.
@KoenDG
I submitted a fix for this issue (and same issue in SGI and PCX/DCX formats), along with some other minor improvements. I believe that will fix this issue for you, but please test and report back if it doesn’t. 😀
Thanks a log for your report, excellent PR and feedback!
Best regards,
– Harald K