Skip to content

Commit 8313811

Browse files
committed
Fixed issue loading palettized (indexed colour) png files that have transparency. Specifically pass the SPNG_DECODE_TRNS flag to the decode so it properly reads the tRNS chunk. Also fixed the src pixel format so it is correctly set for palettized pngs.
1 parent 3694dff commit 8313811

File tree

3 files changed

+41
-16
lines changed

3 files changed

+41
-16
lines changed

Modules/Image/Src/tImagePNG.cpp

+33-14
Original file line numberDiff line numberDiff line change
@@ -262,19 +262,39 @@ bool tImagePNG::Load(const uint8* pngFileInMemory, int numBytes, const LoadParam
262262
return false;
263263
}
264264

265-
int bitDepth = ihdr.bit_depth;
266-
bool hasAlpha = (ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA) || (ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA);
267265
Width = ihdr.width;
268266
Height = ihdr.height;
269267
int numPixels = Width * Height;
268+
int bitDepth = ihdr.bit_depth;
270269

271-
// If the src bit depth is 16, RGBA are all linear. Otherwise RGB are sRGB and A is linear.
272-
if (bitDepth == 16)
273-
PixelFormatSrc = hasAlpha ? tPixelFormat::R16G16B16A16 : tPixelFormat::R16G16B16;
270+
if (ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
271+
{
272+
switch (bitDepth)
273+
{
274+
case 1: PixelFormatSrc = tPixelFormat::PAL1BIT; break;
275+
case 2: PixelFormatSrc = tPixelFormat::PAL2BIT; break;
276+
case 3: PixelFormatSrc = tPixelFormat::PAL3BIT; break;
277+
case 4: PixelFormatSrc = tPixelFormat::PAL4BIT; break;
278+
case 5: PixelFormatSrc = tPixelFormat::PAL5BIT; break;
279+
case 6: PixelFormatSrc = tPixelFormat::PAL6BIT; break;
280+
case 7: PixelFormatSrc = tPixelFormat::PAL7BIT; break;
281+
default:
282+
case 8: PixelFormatSrc = tPixelFormat::PAL8BIT; break;
283+
}
284+
}
274285
else
275-
PixelFormatSrc = hasAlpha ? tPixelFormat::R8G8B8A8 : tPixelFormat::R8G8B8;
286+
{
287+
bool hasAlpha = (ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA) || (ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA);
288+
289+
// If the src bit depth is 16, RGBA are all linear. Otherwise RGB are sRGB and A is linear.
290+
if (bitDepth == 16)
291+
PixelFormatSrc = hasAlpha ? tPixelFormat::R16G16B16A16 : tPixelFormat::R16G16B16;
292+
else
293+
PixelFormatSrc = hasAlpha ? tPixelFormat::R8G8B8A8 : tPixelFormat::R8G8B8;
294+
ColourProfileSrc = (bitDepth == 16) ? tColourProfile::lRGB : tColourProfile::sRGB;
295+
}
296+
276297
PixelFormat = PixelFormatSrc;
277-
ColourProfileSrc = (bitDepth == 16) ? tColourProfile::lRGB : tColourProfile::sRGB;
278298
ColourProfile = ColourProfileSrc;
279299

280300
// Are we being asked to do auto-gamma-compression?
@@ -296,13 +316,11 @@ bool tImagePNG::Load(const uint8* pngFileInMemory, int numBytes, const LoadParam
296316
}
297317

298318
// Output format, does not depend on source PNG format except for SPNG_FMT_PNG, which is the PNGs format in
299-
// host-endian (or big-endian for SPNG_FMT_RAW). Note that for these two formats <8-bit images are left byte-packed.
300-
// Here we decode to a 16 bit buffer if the src is 16 bit to keep full precision.
319+
// host-endian (or big-endian for SPNG_FMT_RAW). Note that for these two formats < 8-bit images are left byte-packed.
320+
// Here we decode to a 16 bit buffer if the src is 16 bit to keep full precision. For non-16-bit per component
321+
// buffers, including palettized, we decode to RGBA8.
301322
int fmt = (bitDepth == 16) ? SPNG_FMT_RGBA16 : SPNG_FMT_RGBA8;
302323

303-
// With SPNG_FMT_PNG indexed color images are output as palette indices, pick another format to expand them.
304-
// if (ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
305-
// fmt = SPNG_FMT_RGBA8;
306324
size_t rawPixelsSize = 0;
307325
errCode = spng_decoded_image_size(ctx, fmt, &rawPixelsSize);
308326
if (errCode)
@@ -314,8 +332,9 @@ bool tImagePNG::Load(const uint8* pngFileInMemory, int numBytes, const LoadParam
314332

315333
uint8* rawPixels = new uint8[rawPixelsSize];
316334

317-
// Decode the image in one go.
318-
errCode = spng_decode_image(ctx, rawPixels, rawPixelsSize, fmt, 0);
335+
// Decode the image in one go. I'm pretty sure we always want to decode transparency.
336+
// Certainly for palettized images it is required.
337+
errCode = spng_decode_image(ctx, rawPixels, rawPixelsSize, fmt, SPNG_DECODE_TRNS);
319338
if (errCode)
320339
{
321340
delete[] rawPixels;

UnitTests/Src/TestImage.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,12 @@ tTestUnit(ImagePicture)
400400
tga.Save("WrittenXeyes.tga");
401401
tRequire( tSystem::tFileExists("WrittenXeyes.png"));
402402

403+
png.Load("PNG/Mouse.png");
404+
png.Save("WrittenMouse.png");
405+
pic.Set(png); tga.Set(pic);
406+
tga.Save("WrittenMouse.tga");
407+
tRequire( tSystem::tFileExists("WrittenMouse.png"));
408+
403409
tImageQOI qoi;
404410
qoi.Load("TacentTestPattern32.qoi");
405411
qoi.Save("WrittenTacentTestPattern32.qoi");

UnitTests/Src/UnitTests.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ int main(int argc, char** argv)
197197
// tTest(Interval);
198198
// tTest(FileTypes);
199199
// tTest(Directories);
200-
tTest(File);
200+
// tTest(File);
201201
// tTest(FindRec);
202202
// tTest(Network);
203203
// tTest(Time);
@@ -218,7 +218,7 @@ int main(int argc, char** argv)
218218
// tTest(ImageSave);
219219
// tTest(ImageTexture);
220220
// tTest(ImageMultiFrame);
221-
// tTest(ImagePicture);
221+
tTest(ImagePicture);
222222
// tTest(ImageQuantize);
223223
// tTest(ImagePalette);
224224
// tTest(ImageFilter);

0 commit comments

Comments
 (0)