From 597441ca33d97d5ed75f570d3211fe56f5c14076 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 13 Apr 2020 20:42:57 +0100 Subject: [PATCH 1/2] Add option to treat all TGA files as TGA 1.0 Some files which are malformed TGA 2.0 files are technically valid TGA 1.0 files. For example, an image that just happened to have pixel data matching the TGA 2.0 footer or files created by buggy TGA 2.0 writers and were only ever fed to TGA 1.0 readers. --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 95 ++++++++++++++------------ 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index 7249bfe29..4819de94a 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -339,7 +339,8 @@ unsigned char * simage_tga_load(std::istream& fin, int *width_ret, int *height_ret, -int *numComponents_ret) +int *numComponents_ret, +bool ignoreTGA2Fields) { unsigned char header[18]; unsigned char footer[26]; @@ -382,50 +383,54 @@ int *numComponents_ret) fin.seekg(-26, std::ios::end); endOfImage = fin.tellg() + (std::streamoff)26; - 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) + if (!ignoreTGA2Fields) { - endOfImage -= 26; - unsigned int extensionAreaOffset = getInt32(&footer[0]); - unsigned int developerAreaOffset = getInt32(&footer[4]); - - if (extensionAreaOffset != 0) + fin.read((char*)footer, 26); + if (fin.gcount() != 26) { - 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; - } - - 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]; + tgaerror = ERR_READ; + return NULL; } - if (developerAreaOffset != 0) - endOfImage = std::min(endOfImage, (std::streampos)developerAreaOffset); + // 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) + { + 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; + } + + 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); @@ -804,14 +809,14 @@ class ReaderWriterTGA : public osgDB::ReaderWriter virtual const char* className() const { return "TGA Image Reader"; } - ReadResult readTGAStream(std::istream& fin) const + ReadResult readTGAStream(std::istream& fin, bool ignoreTGA2Fields) const { unsigned char *imageData = NULL; int width_ret; int height_ret; int numComponents_ret; - imageData = simage_tga_load(fin,&width_ret,&height_ret,&numComponents_ret); + imageData = simage_tga_load(fin, &width_ret, &height_ret, &numComponents_ret, ignoreTGA2Fields); if (imageData==NULL) return ReadResult::FILE_NOT_HANDLED; @@ -852,9 +857,9 @@ class ReaderWriterTGA : public osgDB::ReaderWriter return readImage(file, options); } - virtual ReadResult readImage(std::istream& fin,const Options* =NULL) const + virtual ReadResult readImage(std::istream& fin, const Options* options = NULL) const { - return readTGAStream(fin); + return readTGAStream(fin, options && options->getOptionString().find("IGNORE_TGA_2_FIELDS") != std::string::npos); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const @@ -867,7 +872,7 @@ class ReaderWriterTGA : public osgDB::ReaderWriter osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); if(!istream) return ReadResult::FILE_NOT_HANDLED; - ReadResult rr = readTGAStream(istream); + ReadResult rr = readTGAStream(istream, options && options->getOptionString().find("IGNORE_TGA_2_FIELDS") != std::string::npos); if(rr.validImage()) rr.getImage()->setFileName(file); return rr; } From 16a5e019c5e8c2d899a32736af4cd2226840a04a Mon Sep 17 00:00:00 2001 From: Chris Djali Date: Sat, 25 Apr 2020 20:07:03 +0100 Subject: [PATCH 2/2] Register option Also make the capitalisation consistent with more plugins --- src/osgPlugins/tga/ReaderWriterTGA.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/osgPlugins/tga/ReaderWriterTGA.cpp b/src/osgPlugins/tga/ReaderWriterTGA.cpp index 4819de94a..30f9fb446 100644 --- a/src/osgPlugins/tga/ReaderWriterTGA.cpp +++ b/src/osgPlugins/tga/ReaderWriterTGA.cpp @@ -805,6 +805,7 @@ class ReaderWriterTGA : public osgDB::ReaderWriter ReaderWriterTGA() { supportsExtension("tga","Tga Image format"); + supportsOption("ignoreTga2Fields", "(Read option) Ignore TGA 2.0 fields, even if present. Makes it possible to read files as a TGA 1.0 reader would, helpful when dealing with malformed TGA 2.0 files which are still valid TGA 1.0 files, such as when an image ends with data resembling a TGA 2.0 footer by coincidence."); } virtual const char* className() const { return "TGA Image Reader"; } @@ -859,7 +860,7 @@ class ReaderWriterTGA : public osgDB::ReaderWriter virtual ReadResult readImage(std::istream& fin, const Options* options = NULL) const { - return readTGAStream(fin, options && options->getOptionString().find("IGNORE_TGA_2_FIELDS") != std::string::npos); + return readTGAStream(fin, options && options->getOptionString().find("ignoreTga2Fields") != std::string::npos); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const @@ -872,7 +873,7 @@ class ReaderWriterTGA : public osgDB::ReaderWriter osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); if(!istream) return ReadResult::FILE_NOT_HANDLED; - ReadResult rr = readTGAStream(istream, options && options->getOptionString().find("IGNORE_TGA_2_FIELDS") != std::string::npos); + ReadResult rr = readTGAStream(istream, options && options->getOptionString().find("ignoreTga2Fields") != std::string::npos); if(rr.validImage()) rr.getImage()->setFileName(file); return rr; }