question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TGA 4BYTE_BGRX image fails to transform. Possible cause in custom bandoffsets for 32-bit depth of image

See original GitHub issue

Describe 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

  1. The version of the TwelveMonkeys ImageIO library in use. 3.7.0, the TGA plugin.

  2. The exact output of java --version (or java -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)
  1. 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:

  1. Compile the below sample code
  2. Use the provided sample image
  3. Run the code with the sample file
  4. 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:closed
  • Created 2 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
KoenDGcommented, Sep 7, 2021

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.

0reactions
haraldkcommented, Sep 7, 2021

@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

Read more comments on GitHub >

github_iconTop Results From Across the Web

Bit depth and preferences - Adobe Support
Bit depth specifies how much color information is available for each pixel in an image. More bits of information per pixel result in...
Read more >
32bit TGA files are read as 8bit images [solved, user error]
It seems that 32bit TGA files are upon opening imported as 8bit images. which means, there is a lot of detail loss.
Read more >
jpeg 32 bit depth not showing on latex - TeX
When I upload my images of 300 dpi some are uploaded but some are creating problems (when they upload, immediately their dpi converts...
Read more >
Bit Depth & How Compression Affects Normal Maps - CG Cookie
Image bit depth and compression play a huge role in how your normal maps look in any game or render engine. In this...
Read more >
LG G watch not displaying 32-bit Images or Gradients with full ...
According to this site, the LG G Watch has a color-depth or 24-bit, which should be ... Normal images on the device appear...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found