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.
This commit is contained in:
AnyOldName3
2020-04-13 20:42:57 +01:00
parent 864b087b1f
commit 597441ca33

View File

@@ -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;
}