Cleanup TGA header interpretation

* Read the colour map `First Entry Index` field. If non-zero, error out as the format specification is vague as to what it does and different readers interpret it differently.
* Rename the variable that holds the colour map entry size as the existing name could be misinterpreted as the size of the pointer, not the thing pointed to.
* Handle images reporting themselves as 15 bits per pixel in the same way as Truevision's example code.
This commit is contained in:
AnyOldName3 2019-05-04 01:19:31 +01:00
parent f97ea3577d
commit 47ec2c7951

View File

@ -273,8 +273,9 @@ int *numComponents_ret)
int flags; int flags;
int format; int format;
unsigned char *colormap; unsigned char *colormap;
int colormapFirst = 0;
int colormapLen = 0; int colormapLen = 0;
int indexsize = 0; int colormapDepth = 0;
int rleIsCompressed; int rleIsCompressed;
int rleRemaining; int rleRemaining;
int rleEntrySize; int rleEntrySize;
@ -283,6 +284,7 @@ int *numComponents_ret)
unsigned char *dest; unsigned char *dest;
int bpr; int bpr;
unsigned char *linebuf; unsigned char *linebuf;
int alphaBPP;
tgaerror = ERR_NO_ERROR; /* clear error */ tgaerror = ERR_NO_ERROR; /* clear error */
@ -296,8 +298,10 @@ int *numComponents_ret)
type = header[2]; type = header[2];
width = getInt16(&header[12]); width = getInt16(&header[12]);
height = getInt16(&header[14]); height = getInt16(&header[14]);
depth = header[16] >> 3; // Add 7 as R5G5B5 images with no alpha data take up two bytes per pixel, but only 15 bits
depth = (header[16] + 7) >> 3;
flags = header[17]; flags = header[17];
alphaBPP = flags & 0x0F;
/* check for reasonable values in case this is not a tga file */ /* check for reasonable values in case this is not a tga file */
if ((type != 1 && type != 2 && type != 10) || if ((type != 1 && type != 2 && type != 10) ||
@ -315,18 +319,25 @@ int *numComponents_ret)
colormap = NULL; colormap = NULL;
if (header[1] == 1) /* there is a colormap */ if (header[1] == 1) /* there is a colormap */
{ {
colormapLen = getInt16(&header[5]); colormapFirst = getInt16(&header[3]);
indexsize = header[7]>>3; if (colormapFirst != 0)
colormap = new unsigned char [colormapLen*indexsize];
fin.read((char*)colormap,colormapLen*indexsize);
if (indexsize == 2) /* 16 bits */
{ {
if (flags & 1) format = 4; // Error on non-zero colormapFirst as it's unclear from the specification what it actually does
tgaerror = ERR_UNSUPPORTED;
return NULL;
}
colormapLen = getInt16(&header[5]);
colormapDepth = (header[7] + 7) >> 3;
colormap = new unsigned char[colormapLen*colormapDepth];
fin.read((char*)colormap, colormapLen*colormapDepth);
if (colormapDepth == 2) /* 16 bits */
{
if (alphaBPP == 1) format = 4;
else format = 3; else format = 3;
} }
else else
format = indexsize; format = colormapDepth;
} }
else else
{ {
@ -360,7 +371,7 @@ int *numComponents_ret)
{ {
case 1: /* colormap, uncompressed */ case 1: /* colormap, uncompressed */
{ {
if (colormapLen == 0 || indexsize == 0) if (colormapLen == 0 || colormapDepth == 0)
{ {
tgaerror = ERR_UNSUPPORTED; /* colormap missing or empty */ tgaerror = ERR_UNSUPPORTED; /* colormap missing or empty */
@ -373,7 +384,7 @@ int *numComponents_ret)
unsigned char * formattedMap = new unsigned char[colormapLen * format]; unsigned char * formattedMap = new unsigned char[colormapLen * format];
for (int i = 0; i < colormapLen; i++) for (int i = 0; i < colormapLen; i++)
{ {
convert_data(colormap, formattedMap, i, indexsize, format); convert_data(colormap, formattedMap, i, colormapDepth, format);
} }
int x, y; int x, y;