From b7d865f2cfb648d6acf9cd93d27bfe2c1d069933 Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Wed, 18 May 2022 22:18:20 +0200 Subject: [PATCH] #680 TGAImageReader now reads attribute bits with no extension area as alpha --- .../imageio/plugins/tga/TGAImageReader.java | 2 +- .../plugins/tga/TGAImageReaderTest.java | 51 +++++++++++++++--- .../test/resources/tga/alpha-no-extension.tga | Bin 0 -> 42796 bytes 3 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 imageio/imageio-tga/src/test/resources/tga/alpha-no-extension.tga diff --git a/imageio/imageio-tga/src/main/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReader.java b/imageio/imageio-tga/src/main/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReader.java index edb92dca..e819ece7 100755 --- a/imageio/imageio-tga/src/main/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReader.java +++ b/imageio/imageio-tga/src/main/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReader.java @@ -136,7 +136,7 @@ final class TGAImageReader extends ImageReaderBase { case TGA.IMAGETYPE_TRUECOLOR_RLE: ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); - boolean hasAlpha = header.getAttributeBits() > 0 && extensions != null && extensions.hasAlpha(); + boolean hasAlpha = header.getAttributeBits() > 0 && (extensions == null || extensions.hasAlpha()); boolean isAlphaPremultiplied = extensions != null && extensions.isAlphaPremultiplied(); switch (header.getPixelDepth()) { diff --git a/imageio/imageio-tga/src/test/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReaderTest.java b/imageio/imageio-tga/src/test/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReaderTest.java index 7b23c2f3..5bff09bc 100755 --- a/imageio/imageio-tga/src/test/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReaderTest.java +++ b/imageio/imageio-tga/src/test/java/com/twelvemonkeys/imageio/plugins/tga/TGAImageReaderTest.java @@ -44,6 +44,7 @@ import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.spi.ImageReaderSpi; import javax.imageio.stream.ImageInputStream; import java.awt.*; +import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -81,20 +82,20 @@ public class TGAImageReaderTest extends ImageReaderAbstractTest new TestData(getClassLoaderResource("/tga/CTC24.TGA"), new Dimension(128, 128)), // RLE compressed 24 bit BGR new TestData(getClassLoaderResource("/tga/CTC32.TGA"), new Dimension(128, 128)), // RLE compressed 32 bit BGRA - // Further samples from http://www.fileformat.info/format/tga/sample/index.htm + // More samples from http://www.fileformat.info/format/tga/sample/index.htm new TestData(getClassLoaderResource("/tga/FLAG_B16.TGA"), new Dimension(124, 124)), // Uncompressed 16 bit BGR bottom/up new TestData(getClassLoaderResource("/tga/FLAG_B24.TGA"), new Dimension(124, 124)), // Uncompressed 24 bit BGR bottom/up - new TestData(getClassLoaderResource("/tga/FLAG_B32.TGA"), new Dimension(124, 124)), // Uncompressed 32 bit BGRA bottom/up + new TestData(getClassLoaderResource("/tga/FLAG_B32.TGA"), new Dimension(124, 124)), // Uncompressed 32 bit BGRX bottom/up new TestData(getClassLoaderResource("/tga/FLAG_T16.TGA"), new Dimension(124, 124)), // Uncompressed 16 bit BGR top/down // new TestData(getClassLoaderResource("/tga/FLAG_T24.TGA"), new Dimension(124, 124)), // Uncompressed 24 bit BGR top/down (missing from file set) - new TestData(getClassLoaderResource("/tga/FLAG_T32.TGA"), new Dimension(124, 124)), // Uncompressed 32 bit BGRA top/down + new TestData(getClassLoaderResource("/tga/FLAG_T32.TGA"), new Dimension(124, 124)), // Uncompressed 32 bit BGRX top/down new TestData(getClassLoaderResource("/tga/XING_B16.TGA"), new Dimension(240, 164)), // Uncompressed 16 bit BGR bottom/up new TestData(getClassLoaderResource("/tga/XING_B24.TGA"), new Dimension(240, 164)), // Uncompressed 24 bit BGR bottom/up - new TestData(getClassLoaderResource("/tga/XING_B32.TGA"), new Dimension(240, 164)), // Uncompressed 32 bit BGRA bottom/up + new TestData(getClassLoaderResource("/tga/XING_B32.TGA"), new Dimension(240, 164)), // Uncompressed 32 bit BGRX bottom/up new TestData(getClassLoaderResource("/tga/XING_T16.TGA"), new Dimension(240, 164)), // Uncompressed 16 bit BGR top/down new TestData(getClassLoaderResource("/tga/XING_T24.TGA"), new Dimension(240, 164)), // Uncompressed 24 bit BGR top/down - new TestData(getClassLoaderResource("/tga/XING_T32.TGA"), new Dimension(240, 164)), // Uncompressed 32 bit BGRA top/down + new TestData(getClassLoaderResource("/tga/XING_T32.TGA"), new Dimension(240, 164)), // Uncompressed 32 bit BGRX top/down new TestData(getClassLoaderResource("/tga/autodesk-3dsmax-extsize494.tga"), new Dimension(440, 200)), // RLE compressed 32 bit BGRA bottom/up, with extension area size 494 @@ -102,7 +103,8 @@ public class TGAImageReaderTest extends ImageReaderAbstractTest new TestData(getClassLoaderResource("/tga/monochrome16_top_left_rle.tga"), new Dimension(64, 64)), // RLE compressed 16 bit monochrome new TestData(getClassLoaderResource("/tga/692c33d1-d0c3-4fe2-a059-f199d063bc7a.tga"), new Dimension(256, 256)), // Uncompressed BGR, with colorMapDepth set to 24 - new TestData(getClassLoaderResource("/tga/0112eccd-2c29-4368-bcef-59c823b6e5d1.tga"), new Dimension(256, 256)) // RLE compressed BGR, with extension area size 0 + new TestData(getClassLoaderResource("/tga/0112eccd-2c29-4368-bcef-59c823b6e5d1.tga"), new Dimension(256, 256)), // RLE compressed BGR, with extension area size 0 + new TestData(getClassLoaderResource("/tga/alpha-no-extension.tga"), new Dimension(167, 64)) // Uncompressed BGRA, without extension area ); } @@ -143,6 +145,43 @@ public class TGAImageReaderTest extends ImageReaderAbstractTest reader.dispose(); } + @Test + public void testAlpha() throws IOException { + ImageReader reader = createReader(); + + // These samples have "attribute bits" that are *NOT* alpha, according to the extension area + for (String sample : Arrays.asList("/tga/UTC16.TGA", "/tga/UTC32.TGA", "/tga/CTC16.TGA", "/tga/CTC32.TGA")) { + try (ImageInputStream input = ImageIO.createImageInputStream(getClassLoaderResource(sample))) { + reader.setInput(input); + + BufferedImage image = reader.read(0); + + String message = String.format("RGB value differs for sample '%s'", sample); + assertRGBEquals(message, 0xffff0000, image.getRGB(0, 0), 0); + assertRGBEquals(message, 0xff00ff00, image.getRGB(8, 0), 0); + assertRGBEquals(message, 0xff0000ff, image.getRGB(16, 0), 0); + assertRGBEquals(message, 0xff000000, image.getRGB(24, 0), 0); + assertRGBEquals(message, 0xffff0000, image.getRGB(32, 0), 0); + assertRGBEquals(message, 0xff00ff00, image.getRGB(40, 0), 0); + assertRGBEquals(message, 0xff0000ff, image.getRGB(48, 0), 0); + assertRGBEquals(message, 0xffffffff, image.getRGB(56, 0), 0); + } + } + + // This sample has "attribute bits" that *ARE* alpha, and there is no extension area + try (ImageInputStream input = ImageIO.createImageInputStream(getClassLoaderResource("/tga/alpha-no-extension.tga"))) { + reader.setInput(input); + + BufferedImage image = reader.read(0); + + String message = "RGB value differs for sample '/tga/alpha-no-extension.tga'"; + assertRGBEquals(message, 0x00ffffff, image.getRGB(0, 0), 0); + assertRGBEquals(message, 0xffffffff, image.getRGB(48, 14), 0); + } + + reader.dispose(); + } + @Test public void testMetadataTextEntries() throws IOException { ImageReader reader = createReader(); diff --git a/imageio/imageio-tga/src/test/resources/tga/alpha-no-extension.tga b/imageio/imageio-tga/src/test/resources/tga/alpha-no-extension.tga new file mode 100644 index 0000000000000000000000000000000000000000..a9a5a250ca87d23ece99057ffa411c390cfccdba GIT binary patch literal 42796 zcmeI4&5hkQ6ontW$~GMY*~gnSkVR}@fWQXq*l-1IAuXf@R}dgAq=mGQ7Sh64A8aOP zE=Y-zC`x)d1PDfXj@G~om;p0j2F!pNFau`5 z4445kUVaoeACOOICe3f)%YN4IET&HCJfRpF@|0`)bzPWo~Y|s{~1TP zpXTAD;hZC7se`eQd6P6Yq&bx9T+{I9aI%LM*nlllZAT5~ut|T(pPL)FrlH1`DO=BU zKk8cQKU~(1bE;=4OVNc^ zYPK{z_THs+_GA-3GOuc2tRM4l)X;2>>oumO-ix}{vdQ};W#`1mcd0Gx)6kpEs0p@k zO?A_B%s-Y_%hjY+hcUfs>N;DVsB5YJk*lTstkqic^=6a4F;;3Avmt7zhcUgh%)O+e zuBHA*HdV8w>7%}-m_ZK_Z9n$wd_e3#OIX6YWssG;UeYY`*(b<^uF5NI(>CEdwshe<2?HM2sSZiU{}uWXfF(LtwkKF`7d0J zP2M|?9**vl$R_7GhL>DZ-yB_sCH)Cql$-RSJRcrVA>6(#wJNHdUbz<&; z(bjVaBIUDx8 z#`pjDJsnQ>w8?FM(LefS3nsPBmU}O2e8^atdoIxfUa6b$bMJ73ecv@YuPLkAqXX=; zjM2YGU=#M@-#(%P%N{cx>XuB zwEeTBd+ujk`Ta+EfEC`)w+_4mpLslp|7&4Oy^gpKtjsvQ&-lvo!<;vyM&H{59+MBjnlZJqe9+>l$Sf+iD|PYT&%KY|5wK0M7ipkJ+C4 zE~mO3Ej`wkE$+cU+)F?c#?aJW?ml_84)`wFaF53`vDy3mG>&hHHLfcQ>3Z+uy?;w* zzDn~%i(~Xpi#k&sz4n)ACpQ-IY+#FWNqWxSCS1pLE9YFF8?P|0N3GYK4-!8KYwFso zER4j!K5wgM1HLunc;Bn<_uQ^(PWp^}g~7C!&Jk8y_QPzp)w9+&x_)i#(^?x^+s~Io@X21-X0W)9*%zzm%17^Ssm;p0j2F!pNFau`5 f46I_{_BH(a=G}|;4{sk{zxv_B%ZFcHJimPgFr!q! literal 0 HcmV?d00001