From 47ec2c79513e452161766084c828f8c67be4a72c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 4 May 2019 01:19:31 +0100 Subject: [PATCH 1/7] 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. --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 35 +++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index 53da479ac..dc9825c9a 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -273,8 +273,9 @@ int *numComponents_ret) int flags; int format; unsigned char *colormap; + int colormapFirst = 0; int colormapLen = 0; - int indexsize = 0; + int colormapDepth = 0; int rleIsCompressed; int rleRemaining; int rleEntrySize; @@ -283,6 +284,7 @@ int *numComponents_ret) unsigned char *dest; int bpr; unsigned char *linebuf; + int alphaBPP; tgaerror = ERR_NO_ERROR; /* clear error */ @@ -296,8 +298,10 @@ int *numComponents_ret) type = header[2]; width = getInt16(&header[12]); 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]; + alphaBPP = flags & 0x0F; /* check for reasonable values in case this is not a tga file */ if ((type != 1 && type != 2 && type != 10) || @@ -315,18 +319,25 @@ int *numComponents_ret) colormap = NULL; if (header[1] == 1) /* there is a colormap */ { - colormapLen = getInt16(&header[5]); - indexsize = header[7]>>3; - colormap = new unsigned char [colormapLen*indexsize]; - fin.read((char*)colormap,colormapLen*indexsize); - - if (indexsize == 2) /* 16 bits */ + colormapFirst = getInt16(&header[3]); + if (colormapFirst != 0) { - 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 = indexsize; + format = colormapDepth; } else { @@ -360,7 +371,7 @@ int *numComponents_ret) { case 1: /* colormap, uncompressed */ { - if (colormapLen == 0 || indexsize == 0) + if (colormapLen == 0 || colormapDepth == 0) { tgaerror = ERR_UNSUPPORTED; /* colormap missing or empty */ @@ -373,7 +384,7 @@ int *numComponents_ret) unsigned char * formattedMap = new unsigned char[colormapLen * format]; for (int i = 0; i < colormapLen; i++) { - convert_data(colormap, formattedMap, i, indexsize, format); + convert_data(colormap, formattedMap, i, colormapDepth, format); } int x, y; From 348fbfe41049cd642e1e0b6a7f79b454bca1aa08 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 May 2019 00:56:42 +0100 Subject: [PATCH 2/7] Switch to using safe buffers (fixing a memory leak) --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 76 +++++++++++++++----------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index dc9825c9a..79e70da55 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -258,6 +258,36 @@ const int rleEntrySize) } } +template +struct SafeArray +{ + SafeArray() { impl = NULL; } + SafeArray(size_t size) { impl = new T[size]; } + ~SafeArray() { delete[] impl; } + + T* release() + { + T* temp = impl; + impl = NULL; + return temp; + } + + void reinitialise(size_t size) + { + delete[] impl; + + impl = new T[size]; + } + + operator T*() { return impl; } + + template + explicit operator U() { return (U)impl; } + +private: + T* impl; +}; + unsigned char * simage_tga_load(std::istream& fin, @@ -272,7 +302,7 @@ int *numComponents_ret) int depth; int flags; int format; - unsigned char *colormap; + SafeArray colormap; int colormapFirst = 0; int colormapLen = 0; int colormapDepth = 0; @@ -280,10 +310,8 @@ int *numComponents_ret) int rleRemaining; int rleEntrySize; unsigned char rleCurrent[4]; - unsigned char *buffer; unsigned char *dest; int bpr; - unsigned char *linebuf; int alphaBPP; tgaerror = ERR_NO_ERROR; /* clear error */ @@ -316,7 +344,6 @@ int *numComponents_ret) if (header[0]) /* skip identification field */ fin.seekg(header[0],std::ios::cur); - colormap = NULL; if (header[1] == 1) /* there is a colormap */ { colormapFirst = getInt16(&header[3]); @@ -328,7 +355,7 @@ int *numComponents_ret) } colormapLen = getInt16(&header[5]); colormapDepth = (header[7] + 7) >> 3; - colormap = new unsigned char[colormapLen*colormapDepth]; + colormap.reinitialise(colormapLen*colormapDepth); fin.read((char*)colormap, colormapLen*colormapDepth); if (colormapDepth == 2) /* 16 bits */ @@ -355,10 +382,10 @@ int *numComponents_ret) rleIsCompressed = 0; rleRemaining = 0; rleEntrySize = depth; - buffer = new unsigned char [width*height*format]; + SafeArray buffer(width*height*format); dest = buffer; bpr = format * width; - linebuf = new unsigned char [width*depth]; + SafeArray linebuf(width * depth); //check the intended image orientation bool bLeftToRight = (flags&0x10)==0; @@ -374,14 +401,9 @@ int *numComponents_ret) if (colormapLen == 0 || colormapDepth == 0) { tgaerror = ERR_UNSUPPORTED; /* colormap missing or empty */ - - if (colormap) delete [] colormap; - delete [] buffer; - delete [] linebuf; - return NULL; } - unsigned char * formattedMap = new unsigned char[colormapLen * format]; + SafeArray formattedMap(colormapLen * format); for (int i = 0; i < colormapLen; i++) { convert_data(colormap, formattedMap, i, colormapDepth, format); @@ -394,7 +416,7 @@ int *numComponents_ret) if (fin.gcount() != (std::streamsize) (width*depth)) { tgaerror = ERR_READ; - break; + return NULL; } for (x = 0; x < width; x++) @@ -416,7 +438,6 @@ int *numComponents_ret) break; default: tgaerror = ERR_UNSUPPORTED; - delete [] formattedMap; return NULL; /* unreachable code - (depth < 1 || depth > 4) rejected by "check for reasonable values in case this is not a tga file" near the start of this function*/ } @@ -426,8 +447,6 @@ int *numComponents_ret) } dest += lineoffset; } - - delete [] formattedMap; } break; case 2: /* RGB, uncompressed */ @@ -439,7 +458,7 @@ int *numComponents_ret) if (fin.gcount() != (std::streamsize) (width*depth)) { tgaerror = ERR_READ; - break; + return NULL; } for (x = 0; x < width; x++) { @@ -455,13 +474,14 @@ int *numComponents_ret) int pos = fin.tellg(); fin.seekg(0,std::ios::end); + // This is the size of the rest of the TGA file, not just the image section size = (int)fin.tellg() - pos; fin.seekg(pos,std::ios::beg); - unsigned char* buf = new unsigned char [size]; + SafeArray buf(size); if (buf == NULL) { tgaerror = ERR_MEM; - break; + return NULL; } unsigned char* src = buf; @@ -483,27 +503,21 @@ int *numComponents_ret) else { tgaerror = ERR_READ; + return NULL; } - if (buf) delete [] buf; } break; default: + { tgaerror = ERR_UNSUPPORTED; - } - - if (linebuf) delete [] linebuf; - if (colormap) delete [] colormap; - - if (tgaerror) - { - if (buffer) delete [] buffer; - return NULL; + return NULL; + } } *width_ret = width; *height_ret = height; *numComponents_ret = format; - return buffer; + return buffer.release(); } From c9fc6e0f791c29721d51893d086aaaccc38f0e87 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 May 2019 00:59:40 +0100 Subject: [PATCH 3/7] Consistently check for failed memory allocation --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index 79e70da55..5499412bc 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -356,6 +356,11 @@ int *numComponents_ret) colormapLen = getInt16(&header[5]); colormapDepth = (header[7] + 7) >> 3; colormap.reinitialise(colormapLen*colormapDepth); + if (colormap == NULL) + { + tgaerror = ERR_MEM; + return NULL; + } fin.read((char*)colormap, colormapLen*colormapDepth); if (colormapDepth == 2) /* 16 bits */ @@ -387,6 +392,12 @@ int *numComponents_ret) bpr = format * width; SafeArray linebuf(width * depth); + if (buffer == NULL || linebuf == NULL) + { + tgaerror = ERR_MEM; + return NULL; + } + //check the intended image orientation bool bLeftToRight = (flags&0x10)==0; bool bTopToBottom = (flags&0x20)!=0; @@ -404,6 +415,11 @@ int *numComponents_ret) return NULL; } SafeArray formattedMap(colormapLen * format); + if (formattedMap == NULL) + { + tgaerror = ERR_MEM; + return NULL; + } for (int i = 0; i < colormapLen; i++) { convert_data(colormap, formattedMap, i, colormapDepth, format); From 33bf30cd8c78282287a0d679dcdda1c673ee3211 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 10 May 2019 00:04:08 +0100 Subject: [PATCH 4/7] Check TGA footer if present to see if attribute channel contains alpha data --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 98 +++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index 5499412bc..cdb9071d2 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -76,6 +76,15 @@ simage_tga_error(char * buffer, int buflen) return tgaerror; } +enum AttributeType +{ + NO_ALPHA = 0, + ALPHA_UNDEFINED_IGNORE = 1, + ALPHA_UNDEFINED_KEEP = 2, + ALPHA_PRESENT = 3, + ALPHA_PREMULTIPLIED = 4, + ATTRIBUTE_TYPE_UNSET = 256 // Out of range of values possible in file +}; /* TODO: */ /* - bottom-up images */ @@ -133,6 +142,16 @@ convert_32_to_32(const unsigned char * const src, unsigned char * const dest) dest[3] = src[3]; } +static void +convert_32_to_24(const unsigned char * const src, unsigned char * const dest) +{ + /* opengl image format is RGB */ + /* TGA image format is BGRA (with A as attribute, not alpha) for 32 bit */ + dest[0] = src[2]; + dest[1] = src[1]; + dest[2] = src[0]; +} + static void convert_data(const unsigned char * const src, unsigned char * const dest, @@ -159,9 +178,16 @@ const int destformat) } else { - assert(srcformat == 4 && destformat == 4); - convert_32_to_32(src+x*srcformat, - dest+x*destformat); + assert(srcformat == 4); + if (destformat == 3) + convert_32_to_24(src + x * srcformat, + dest + x * destformat); + else + { + assert(destformat == 4); + convert_32_to_32(src + x * srcformat, + dest + x * destformat); + } } } @@ -296,6 +322,7 @@ int *height_ret, int *numComponents_ret) { unsigned char header[18]; + unsigned char footer[26]; int type; int width; int height; @@ -313,6 +340,7 @@ int *numComponents_ret) unsigned char *dest; int bpr; int alphaBPP; + AttributeType attributeType = ATTRIBUTE_TYPE_UNSET; tgaerror = ERR_NO_ERROR; /* clear error */ @@ -331,6 +359,37 @@ int *numComponents_ret) flags = header[17]; alphaBPP = flags & 0x0F; + fin.seekg(-26, std::ios::end); + fin.read((char*)footer, 26); + if (fin.gcount() != 26) + { + tgaerror = ERR_READ; + return NULL; + } + + // TGA footer signature is null-terminated, so works like a C string + if (strcmp((char*)&footer[8], "TRUEVISION-XFILE.") == 0) + { + unsigned int extensionAreaOffset = getInt32(&footer[0]); + unsigned int developerAreaOffset = getInt32(&footer[4]); + + if (extensionAreaOffset != 0) + { + fin.seekg(extensionAreaOffset + 494); + char attrType; + fin.read(&attrType, 1); + if (fin.gcount() != 1) + { + tgaerror = ERR_READ; + return NULL; + } + + attributeType = (AttributeType) attrType; + } + } + + fin.seekg(18); + /* check for reasonable values in case this is not a tga file */ if ((type != 1 && type != 2 && type != 10) || (width < 0 || width > 4096) || @@ -365,20 +424,41 @@ int *numComponents_ret) if (colormapDepth == 2) /* 16 bits */ { - if (alphaBPP == 1) format = 4; - else format = 3; + if (alphaBPP == 1 && (attributeType == ALPHA_PRESENT || attributeType == ALPHA_PREMULTIPLIED || attributeType == ATTRIBUTE_TYPE_UNSET)) + format = 4; + else + format = 3; } + else if (colormapDepth == 3) + format = 3; else - format = colormapDepth; + { + assert(colormapDepth == 4); + if (attributeType == ALPHA_PRESENT || attributeType == ALPHA_PREMULTIPLIED || attributeType == ATTRIBUTE_TYPE_UNSET) + format = 4; + else + format = 3; + } } else { if (depth == 2) /* 16 bits */ { - if (flags & 1) format = 4; - else format = 3; + if (alphaBPP == 1 && (attributeType == ALPHA_PRESENT || attributeType == ALPHA_PREMULTIPLIED || attributeType == ATTRIBUTE_TYPE_UNSET)) + format = 4; + else + format = 3; + } + else if (depth == 3) + format = 3; + else + { + assert(depth == 4); + if (attributeType == ALPHA_PRESENT || attributeType == ALPHA_PREMULTIPLIED || attributeType == ATTRIBUTE_TYPE_UNSET) + format = 4; + else + format = 3; } - else format = depth; } /* SoDebugError::postInfo("simage_tga_load", "TARGA file: %d %d %d %d %d\n", */ From 05e896af7eaeda2ce134d335ed82d15e2f4b4930 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 10 May 2019 00:04:49 +0100 Subject: [PATCH 5/7] Add support for type 9 (colour mapped, compressed) TGA images. --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 86 +++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index cdb9071d2..f1e9944e7 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -391,7 +391,7 @@ int *numComponents_ret) fin.seekg(18); /* 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 != 9 && type != 10) || (width < 0 || width > 4096) || (height < 0 || height > 4096) || (depth < 1 || depth > 4)) @@ -564,6 +564,90 @@ int *numComponents_ret) } } break; + case 9: /* colormap, compressed */ + { + if (colormapLen == 0 || colormapDepth == 0) + { + tgaerror = ERR_UNSUPPORTED; /* colormap missing or empty */ + return NULL; + } + SafeArray formattedMap(colormapLen * format); + if (formattedMap == NULL) + { + tgaerror = ERR_MEM; + return NULL; + } + for (int i = 0; i < colormapLen; i++) + { + convert_data(colormap, formattedMap, i, colormapDepth, format); + } + + int size, x, y; + int pos = fin.tellg(); + + fin.seekg(0, std::ios::end); + // This is the size of the rest of the TGA file, not just the image section + size = (int)fin.tellg() - pos; + fin.seekg(pos, std::ios::beg); + SafeArray buf(size); + if (buf == NULL) + { + tgaerror = ERR_MEM; + return NULL; + } + unsigned char* src = buf; + + fin.read((char*)buf, size); + if (fin.gcount() == (std::streamsize)size) + { + for (y = 0; y < height; y++) + { + rle_decode(&src, linebuf, width*depth, &rleRemaining, + &rleIsCompressed, rleCurrent, rleEntrySize); + assert(src <= buf + size); + + for (x = 0; x < width; x++) + { + int index; + switch (depth) + { + case 1: + index = linebuf[x]; + break; + case 2: + index = getInt16(linebuf + x * 2); + break; + case 3: + index = getInt24(linebuf + x * 3); + break; + case 4: + index = getInt32(linebuf + x * 4); + break; + default: + tgaerror = ERR_UNSUPPORTED; + return NULL; /* unreachable code - (depth < 1 || depth > 4) rejected by "check for reasonable values in case this is not a tga file" near the start of this function*/ + } + + if (index >= colormapLen) + { + tgaerror = ERR_UNSUPPORTED; + return NULL; + } + + int adjustedX = bLeftToRight ? x : (width - 1) - x; + for (int i = 0; i < format; i++) + (dest + adjustedX * format)[i] = (formattedMap + index * format)[i]; + } + dest += lineoffset; + } + } + else + { + tgaerror = ERR_READ; + return NULL; + } + } + break; case 10: /* RGB, compressed */ { int size, x, y; From 7b6135f0f730a7802ae36cd1f3043b0a858dfa3b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 11 May 2019 00:00:41 +0100 Subject: [PATCH 6/7] Avoid wasting memory loading optional TGA fields as RLE image data --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 45 +++++++++++++++++--------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index f1e9944e7..4f0d5e11e 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -341,6 +341,7 @@ int *numComponents_ret) int bpr; int alphaBPP; AttributeType attributeType = ATTRIBUTE_TYPE_UNSET; + std::streampos endOfImage; tgaerror = ERR_NO_ERROR; /* clear error */ @@ -360,6 +361,7 @@ int *numComponents_ret) alphaBPP = flags & 0x0F; fin.seekg(-26, std::ios::end); + endOfImage = fin.tellg() + (std::streamoff)26; fin.read((char*)footer, 26); if (fin.gcount() != 26) { @@ -370,22 +372,40 @@ int *numComponents_ret) // TGA footer signature is null-terminated, so works like a C string if (strcmp((char*)&footer[8], "TRUEVISION-XFILE.") == 0) { + endOfImage -= 26; unsigned int extensionAreaOffset = getInt32(&footer[0]); unsigned int developerAreaOffset = getInt32(&footer[4]); if (extensionAreaOffset != 0) { - fin.seekg(extensionAreaOffset + 494); - char attrType; - fin.read(&attrType, 1); - if (fin.gcount() != 1) + endOfImage = std::min(endOfImage, (std::streampos)extensionAreaOffset); + + // We only need the last few fields of the extension area + fin.seekg(extensionAreaOffset + 482); + unsigned char extensionAreaBuffer[13]; + fin.read((char*)extensionAreaBuffer, 13); + if (fin.gcount() != 13) { tgaerror = ERR_READ; return NULL; } - attributeType = (AttributeType) attrType; + unsigned int colorCorrectionOffset = getInt32(&extensionAreaBuffer[0]); + unsigned int postageStampOffset = getInt32(&extensionAreaBuffer[4]); + unsigned int scanLineOffset = getInt32(&extensionAreaBuffer[8]); + + if (colorCorrectionOffset != 0) + endOfImage = std::min(endOfImage, (std::streampos)colorCorrectionOffset); + if (postageStampOffset != 0) + endOfImage = std::min(endOfImage, (std::streampos)postageStampOffset); + if (scanLineOffset != 0) + endOfImage = std::min(endOfImage, (std::streampos)scanLineOffset); + + attributeType = (AttributeType) extensionAreaBuffer[12]; } + + if (developerAreaOffset != 0) + endOfImage = std::min(endOfImage, (std::streampos)developerAreaOffset); } fin.seekg(18); @@ -583,12 +603,10 @@ int *numComponents_ret) } int size, x, y; - int pos = fin.tellg(); + std::streampos pos = fin.tellg(); + + size = (int)(endOfImage - pos); - fin.seekg(0, std::ios::end); - // This is the size of the rest of the TGA file, not just the image section - size = (int)fin.tellg() - pos; - fin.seekg(pos, std::ios::beg); SafeArray buf(size); if (buf == NULL) { @@ -651,12 +669,9 @@ int *numComponents_ret) case 10: /* RGB, compressed */ { int size, x, y; - int pos = fin.tellg(); + std::streampos pos = fin.tellg(); - fin.seekg(0,std::ios::end); - // This is the size of the rest of the TGA file, not just the image section - size = (int)fin.tellg() - pos; - fin.seekg(pos,std::ios::beg); + size = (int)(endOfImage - pos); SafeArray buf(size); if (buf == NULL) { From 8491fd780d1bf17599f0dfc265df157a031c961f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 13 May 2019 21:56:07 +0100 Subject: [PATCH 7/7] Add support for Targa type 3 and 11 images (greyscale) --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 76 ++++++++++++++++++-------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index 4f0d5e11e..f78aad3a3 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -158,35 +158,52 @@ convert_data(const unsigned char * const src, unsigned char * const dest, const int x, const int srcformat, const int destformat) { - if (srcformat == 2) + if (destformat > 2) /* color */ { - if (destformat == 3) - convert_16_to_24(src+x*srcformat, - dest+x*destformat); + if (srcformat == 2) + { + if (destformat == 3) + convert_16_to_24(src + x * srcformat, + dest + x * destformat); + else + { + assert(destformat == 4); + convert_16_to_32(src + x * srcformat, + dest + x * destformat); + } + } + else if (srcformat == 3) + { + assert(destformat == 3); + convert_24_to_24(src + x * srcformat, + dest + x * destformat); + } else { - assert(destformat == 4); - convert_16_to_32(src+x*srcformat, - dest+x*destformat); + assert(srcformat == 4); + if (destformat == 3) + convert_32_to_24(src + x * srcformat, + dest + x * destformat); + else + { + assert(destformat == 4); + convert_32_to_32(src + x * srcformat, + dest + x * destformat); + } } } - else if (srcformat == 3) - { - assert(destformat == 3); - convert_24_to_24(src+x*srcformat, - dest+x*destformat); - } else { - assert(srcformat == 4); - if (destformat == 3) - convert_32_to_24(src + x * srcformat, - dest + x * destformat); + if (destformat == 1) + { + assert(srcformat == 1 || srcformat == 2); + (dest + x * destformat)[0] = (src + x * srcformat)[0]; + } else { - assert(destformat == 4); - convert_32_to_32(src + x * srcformat, - dest + x * destformat); + assert(srcformat == 2 && destformat == 2); + (dest + x * destformat)[0] = (src + x * srcformat)[0]; + (dest + x * destformat)[1] = (src + x * srcformat)[1]; } } } @@ -411,7 +428,7 @@ int *numComponents_ret) fin.seekg(18); /* check for reasonable values in case this is not a tga file */ - if ((type != 1 && type != 2 && type != 9 && type != 10) || + if ((type != 1 && type != 2 && type != 3 && type != 9 && type != 10 && type != 11) || (width < 0 || width > 4096) || (height < 0 || height > 4096) || (depth < 1 || depth > 4)) @@ -460,7 +477,7 @@ int *numComponents_ret) format = 3; } } - else + else if ((type & ~8) != 3) /* color image */ { if (depth == 2) /* 16 bits */ { @@ -480,6 +497,19 @@ int *numComponents_ret) format = 3; } } + else /* greyscale image */ + { + if (depth == 1) + format = 1; + else + { + assert(depth == 2); + if (attributeType == ALPHA_PRESENT || attributeType == ALPHA_PREMULTIPLIED || attributeType == ATTRIBUTE_TYPE_UNSET) + format = 2; + else + format = 1; + } + } /* SoDebugError::postInfo("simage_tga_load", "TARGA file: %d %d %d %d %d\n", */ /* type, width, height, depth, format); */ @@ -566,6 +596,7 @@ int *numComponents_ret) } break; case 2: /* RGB, uncompressed */ + case 3: /* greyscale, uncompressed */ { int x, y; for (y = 0; y < height; y++) @@ -667,6 +698,7 @@ int *numComponents_ret) } break; case 10: /* RGB, compressed */ + case 11: /* greyscale, compressed */ { int size, x, y; std::streampos pos = fin.tellg();