Need urgent help: TGA file read write and then Smoothing
-
@tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:
@tampere2021 While compile the code,I got few errors.
In line 56: void TARGA::write(std::ostream& f)
[Error] qualified-id in declaration before '(' token
In line 74: int main(int argc, char* argv)
{
[Error] a function-definition is not allowed here before '{' tokenOh, I just copied the code, but there is a closing brace missing in the ctor . Just add a
}
in line 46.Please edit your post and use code tags. It's really hard to read your code without them. Just write "```cpp" in the line in before your code
and "```" in the line behind your code.
-
@Schlangenmensch Ok. understood. I have provided a new code here, for your review, Will resend it again with code tags for you to review. Please check and provide your comments for this new code.
"```cpp"
#include <vector>
#include <fstream>//=========================================
// Code for loading a TGA-file
//=========================================
typedef union PixelInfo
{
std::uint32_t Colour;
struct
{
std::uint8_t R, G, B, A;
};
} *PPixelInfo;class Tga
{
private:
std::vectorstd::uint8_t Pixels;
bool ImageCompressed;
std::uint32_t width, height, size, BitsPerPixel;public:
Tga(const char* FilePath);
std::vectorstd::uint8_t GetPixels() { return this->Pixels; }
std::uint32_t GetWidth() const { return this->width; }
std::uint32_t GetHeight() const { return this->height; }
std::uint32_t GetBitsPerPixel() const { return this->BitsPerPixel; }
bool HasAlphaChannel() { return BitsPerPixel == 32; }
};Tga::Tga(const char* FilePath)
{
std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
if (!hFile.is_open()) { throw std::invalid_argument("File Not Found."); }std::uint8_t Header[18] = { 0 };
std::vectorstd::uint8_t ImageData;
static std::uint8_t DeCompressed[12] = { 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
static std::uint8_t IsCompressed[12] = { 0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header));
if (!std::memcmp(DeCompressed, &Header, sizeof(DeCompressed)))
{
BitsPerPixel = Header[16];
width = Header[13] * 256 + Header[12];
height = Header[15] * 256 + Header[14];
size = ((width * BitsPerPixel + 31) / 32) * 4 * height;if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); } ImageData.resize(size); ImageCompressed = false; hFile.read(reinterpret_cast<char*>(ImageData.data()), size);
}
else if (!std::memcmp(IsCompressed, &Header, sizeof(IsCompressed)))
{
BitsPerPixel = Header[16];
width = Header[13] * 256 + Header[12];
height = Header[15] * 256 + Header[14];
size = ((width * BitsPerPixel + 31) / 32) * 4 * height;if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); } PixelInfo Pixel = { 0 }; int CurrentByte = 0; std::size_t CurrentPixel = 0; ImageCompressed = true; std::uint8_t ChunkHeader = { 0 }; int BytesPerPixel = (BitsPerPixel / 8); ImageData.resize(static_cast<size_t>(width) * static_cast<size_t>(height) * sizeof(PixelInfo)); do { hFile.read(reinterpret_cast<char*>(&ChunkHeader), sizeof(ChunkHeader)); if (ChunkHeader < 128) { ++ChunkHeader; for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); ImageData[CurrentByte++] = Pixel.B; ImageData[CurrentByte++] = Pixel.G; ImageData[CurrentByte++] = Pixel.R; if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; } } else { ChunkHeader -= 127; hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { ImageData[CurrentByte++] = Pixel.B; ImageData[CurrentByte++] = Pixel.G; ImageData[CurrentByte++] = Pixel.R; if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; } } } while (CurrentPixel < (static_cast<size_t>(width) * static_cast<size_t>(height)));
}
else
{
hFile.close();
throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File.");
}hFile.close();
this->Pixels = ImageData;
}//=========================================
// code for writing a TGA-file
//=========================================
void writeTGA(const std::string &refFile, Tga &refTGA)
{
unsigned short width = static_cast<unsigned short>(refTGA.GetWidth());
unsigned short height = static_cast<unsigned short>(refTGA.GetWidth());
unsigned char bitsPerPixel = static_cast<unsigned char>(refTGA.GetBitsPerPixel());
unsigned char bitsAlphaChannel = (bitsPerPixel == 32 ? 8 : 0);FILE * fptr = fopen(refFile.c_str(), "wb");
putc(0, fptr);
putc(0, fptr);
putc(2, fptr); /* uncompressed RGB /
putc(0, fptr); putc(0, fptr);
putc(0, fptr); putc(0, fptr);
putc(0, fptr);
putc(0, fptr); putc(0, fptr); / X origin /
putc(0, fptr); putc(0, fptr); / y origin /
putc((width & 0x00FF), fptr);
putc((width & 0xFF00) / 256, fptr);
putc((height & 0x00FF), fptr);
putc((height & 0xFF00) / 256, fptr);
putc(bitsPerPixel, fptr); / 24/32 bit bitmap /
putc(bitsAlphaChannel, fptr); / When 32 bit, write 8, else 0 */auto pixelData = refTGA.GetPixels();
for (size_t i = 0; i < static_cast<size_t>(width) * static_cast<size_t>(height) * (bitsPerPixel/8); i += (bitsPerPixel/8))
{
unsigned char r = pixelData[i];
unsigned char g = pixelData[i + 1];
unsigned char b = pixelData[i + 2];
unsigned char a = (bitsAlphaChannel == 8 ? pixelData[i + 3] : 0);putc(b, fptr); putc(g, fptr); putc(r, fptr); if (bitsAlphaChannel == 8) putc(a, fptr);
}
fclose(fptr);
}//=========================================
// main
//=========================================
int main()
{
Tga oTga("tile.tga");
writeTGA("tile_new.tga", oTga);Tga oTga("tile.tga");
writeTGA("tile_new.tga", oTga);
}
"```"
-
@Schlangenmensch sagte in Need urgent help: TGA file read write and then Smoothing:
"```"
Reposting new code here again.
"```cpp"
#include <vector>
#include <fstream>//=========================================
// Code for loading a TGA-file
//=========================================
typedef union PixelInfo
{
std::uint32_t Colour;
struct
{
std::uint8_t R, G, B, A;
};
} *PPixelInfo;class Tga
{
private:
std::vectorstd::uint8_t Pixels;
bool ImageCompressed;
std::uint32_t width, height, size, BitsPerPixel;public:
Tga(const char* FilePath);
std::vectorstd::uint8_t GetPixels() { return this->Pixels; }
std::uint32_t GetWidth() const { return this->width; }
std::uint32_t GetHeight() const { return this->height; }
std::uint32_t GetBitsPerPixel() const { return this->BitsPerPixel; }
bool HasAlphaChannel() { return BitsPerPixel == 32; }
};Tga::Tga(const char* FilePath)
{
std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
if (!hFile.is_open()) { throw std::invalid_argument("File Not Found."); }std::uint8_t Header[18] = { 0 };
std::vectorstd::uint8_t ImageData;
static std::uint8_t DeCompressed[12] = { 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
static std::uint8_t IsCompressed[12] = { 0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header));
if (!std::memcmp(DeCompressed, &Header, sizeof(DeCompressed)))
{
BitsPerPixel = Header[16];
width = Header[13] * 256 + Header[12];
height = Header[15] * 256 + Header[14];
size = ((width * BitsPerPixel + 31) / 32) * 4 * height;if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); } ImageData.resize(size); ImageCompressed = false; hFile.read(reinterpret_cast<char*>(ImageData.data()), size);
}
else if (!std::memcmp(IsCompressed, &Header, sizeof(IsCompressed)))
{
BitsPerPixel = Header[16];
width = Header[13] * 256 + Header[12];
height = Header[15] * 256 + Header[14];
size = ((width * BitsPerPixel + 31) / 32) * 4 * height;if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); } PixelInfo Pixel = { 0 }; int CurrentByte = 0; std::size_t CurrentPixel = 0; ImageCompressed = true; std::uint8_t ChunkHeader = { 0 }; int BytesPerPixel = (BitsPerPixel / 8); ImageData.resize(static_cast<size_t>(width) * static_cast<size_t>(height) * sizeof(PixelInfo)); do { hFile.read(reinterpret_cast<char*>(&ChunkHeader), sizeof(ChunkHeader)); if (ChunkHeader < 128) { ++ChunkHeader; for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); ImageData[CurrentByte++] = Pixel.B; ImageData[CurrentByte++] = Pixel.G; ImageData[CurrentByte++] = Pixel.R; if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; } } else { ChunkHeader -= 127; hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { ImageData[CurrentByte++] = Pixel.B; ImageData[CurrentByte++] = Pixel.G; ImageData[CurrentByte++] = Pixel.R; if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; } } } while (CurrentPixel < (static_cast<size_t>(width) * static_cast<size_t>(height)));
}
else
{
hFile.close();
throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File.");
}hFile.close();
this->Pixels = ImageData;
}//=========================================
// code for writing a TGA-file
//=========================================
void writeTGA(const std::string &refFile, Tga &refTGA)
{
unsigned short width = static_cast<unsigned short>(refTGA.GetWidth());
unsigned short height = static_cast<unsigned short>(refTGA.GetWidth());
unsigned char bitsPerPixel = static_cast<unsigned char>(refTGA.GetBitsPerPixel());
unsigned char bitsAlphaChannel = (bitsPerPixel == 32 ? 8 : 0);FILE * fptr = fopen(refFile.c_str(), "wb");
putc(0, fptr);
putc(0, fptr);
putc(2, fptr); /* uncompressed RGB /
putc(0, fptr); putc(0, fptr);
putc(0, fptr); putc(0, fptr);
putc(0, fptr);
putc(0, fptr); putc(0, fptr); / X origin /
putc(0, fptr); putc(0, fptr); / y origin /
putc((width & 0x00FF), fptr);
putc((width & 0xFF00) / 256, fptr);
putc((height & 0x00FF), fptr);
putc((height & 0xFF00) / 256, fptr);
putc(bitsPerPixel, fptr); / 24/32 bit bitmap /
putc(bitsAlphaChannel, fptr); / When 32 bit, write 8, else 0 */auto pixelData = refTGA.GetPixels();
for (size_t i = 0; i < static_cast<size_t>(width) * static_cast<size_t>(height) * (bitsPerPixel/8); i += (bitsPerPixel/8))
{
unsigned char r = pixelData[i];
unsigned char g = pixelData[i + 1];
unsigned char b = pixelData[i + 2];
unsigned char a = (bitsAlphaChannel == 8 ? pixelData[i + 3] : 0);putc(b, fptr); putc(g, fptr); putc(r, fptr); if (bitsAlphaChannel == 8) putc(a, fptr);
}
fclose(fptr);
}//=========================================
// main
//=========================================
int main()
{
Tga oTga("tile.tga");
writeTGA("tile_new.tga", oTga);}
"```"
-
not only does this forum feature a very nice preview of what you're about to post, it also offers the ability to edit your previous posts. I know, very advanced things to take into consideration...
Also, markdown really isn't that hard
```cpp
// some code
```
-
@tampere2021 please without the "" around the markdown tag
-
@Schlangenmensch Sorry for the tag, as I am new here. I have corrected it now and also added new code here, Please review it.
I have written a new code to handle both loading TGA file(tile.tga) and writing. But after I execute the code, it creates some weird glitchy patterns on the new TGA file(tilenew.tga). The tilenew.tga file seems broken when written from memory (containing RGBA pixel data loaded from a tga file) to the file back as tga. Below is my code. What am I doing wrong here?#include <vector> #include <fstream> //========================================= // Code for loading a TGA-file //========================================= typedef union PixelInfo { std::uint32_t Colour; struct { std::uint8_t R, G, B, A; }; } *PPixelInfo; class Tga { private: std::vectorstd::uint8_t Pixels; bool ImageCompressed; std::uint32_t width, height, size, BitsPerPixel; public: Tga(const char* FilePath); std::vectorstd::uint8_t GetPixels() { return this->Pixels; } std::uint32_t GetWidth() const { return this->width; } std::uint32_t GetHeight() const { return this->height; } std::uint32_t GetBitsPerPixel() const { return this->BitsPerPixel; } bool HasAlphaChannel() { return BitsPerPixel == 32; } }; Tga::Tga(const char* FilePath) { std::fstream hFile(FilePath, std::ios::in | std::ios::binary); if (!hFile.is_open()) { throw std::invalid_argument("File Not Found."); } std::uint8_t Header[18] = { 0 }; std::vector<std::uint8_t> ImageData; static std::uint8_t DeCompressed[12] = { 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; static std::uint8_t IsCompressed[12] = { 0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header)); if (!std::memcmp(DeCompressed, &Header, sizeof(DeCompressed))) { BitsPerPixel = Header[16]; width = Header[13] * 256 + Header[12]; height = Header[15] * 256 + Header[14]; size = ((width * BitsPerPixel + 31) / 32) * 4 * height; if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); } ImageData.resize(size); ImageCompressed = false; hFile.read(reinterpret_cast<char*>(ImageData.data()), size); } else if (!std::memcmp(IsCompressed, &Header, sizeof(IsCompressed))) { BitsPerPixel = Header[16]; width = Header[13] * 256 + Header[12]; height = Header[15] * 256 + Header[14]; size = ((width * BitsPerPixel + 31) / 32) * 4 * height; if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); } PixelInfo Pixel = { 0 }; int CurrentByte = 0; std::size_t CurrentPixel = 0; ImageCompressed = true; std::uint8_t ChunkHeader = { 0 }; int BytesPerPixel = (BitsPerPixel / 8); ImageData.resize(static_cast<size_t>(width) * static_cast<size_t>(height) * sizeof(PixelInfo)); do { hFile.read(reinterpret_cast<char*>(&ChunkHeader), sizeof(ChunkHeader)); if (ChunkHeader < 128) { ++ChunkHeader; for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); ImageData[CurrentByte++] = Pixel.B; ImageData[CurrentByte++] = Pixel.G; ImageData[CurrentByte++] = Pixel.R; if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; } } else { ChunkHeader -= 127; hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { ImageData[CurrentByte++] = Pixel.B; ImageData[CurrentByte++] = Pixel.G; ImageData[CurrentByte++] = Pixel.R; if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; } } } while (CurrentPixel < (static_cast<size_t>(width) * static_cast<size_t>(height))); } else { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File."); } hFile.close(); this->Pixels = ImageData; } //========================================= // code for writing a TGA-file //========================================= void writeTGA(const std::string &refFile, Tga &refTGA) { unsigned short width = static_cast<unsigned short>(refTGA.GetWidth()); unsigned short height = static_cast<unsigned short>(refTGA.GetWidth()); unsigned char bitsPerPixel = static_cast<unsigned char>(refTGA.GetBitsPerPixel()); unsigned char bitsAlphaChannel = (bitsPerPixel == 32 ? 8 : 0); FILE * fptr = fopen(refFile.c_str(), "wb"); putc(0, fptr); putc(0, fptr); putc(2, fptr); /* uncompressed RGB */ putc(0, fptr); putc(0, fptr); putc(0, fptr); putc(0, fptr); putc(0, fptr); putc(0, fptr); putc(0, fptr); /* X origin */ putc(0, fptr); putc(0, fptr); /* y origin */ putc((width & 0x00FF), fptr); putc((width & 0xFF00) / 256, fptr); putc((height & 0x00FF), fptr); putc((height & 0xFF00) / 256, fptr); putc(bitsPerPixel, fptr); /* 24/32 bit bitmap */ putc(bitsAlphaChannel, fptr); /* When 32 bit, write 8, else 0 */ auto pixelData = refTGA.GetPixels(); for (size_t i = 0; i < static_cast<size_t>(width) * static_cast<size_t>(height) * (bitsPerPixel/8); i += (bitsPerPixel/8)) { unsigned char r = pixelData[i]; unsigned char g = pixelData[i + 1]; unsigned char b = pixelData[i + 2]; unsigned char a = (bitsAlphaChannel == 8 ? pixelData[i + 3] : 0); putc(b, fptr); putc(g, fptr); putc(r, fptr); if (bitsAlphaChannel == 8) putc(a, fptr); } fclose(fptr); } //========================================= // main //========================================= int main() { Tga oTga("tile.tga"); writeTGA("tile_new.tga", oTga); }
-
@tampere2021 Once this code works fine in writing tga , then I need to apply smoothing to the tile_new.tga file.
-
In the wiki article you find some smoothing algorithms: Smoothing
-
@tampere2021
You may also look at documentation of opencv, a library for image processing. There several smoothing methods are documented.
-
I need to apply smoothing for TGA image without using any 3rd party libraries. How can i implement the smooth filter using c++ std library functions? Also my above code posted above has some issues. after I execute the code, it creates some weird glitchy patterns on the new TGA file(tilenew.tga). The tilenew.tga file seems broken when written from memory (containing RGBA pixel data loaded from a tga file) to the file back as tga. Is it because of my asumption with 128x128 pixels? The code has some issue and need help to fix it first, before I smoothing it.
-
First I see a C&P error in line 130: width <-> height
And you should use a Hexview program to compare your two files: Comparison of hex editors
And why are you using the C-based
FILE
functions instead ofofstream
(in comparison to the use of(i)fstream
for reading)?PS: Nearly all 3rd party libraries also only use the C++ std library functions!
-
@tampere2021
Your code has some issues in how it treats 24 vs. 32 bit images. The write function also contains a mistake in how it handles 32 bit alignment (it doesn't).E.g. in the read function (ctor), you always compute the size as
((width * BitsPerPixel + 31) / 32) * 4 * height
, i.e. with 4 bytes per pixel. Then you allocate an array of that size. That's OK if you want to always use 4 bytes per pixel in memory - makes things easier.But then, in the uncompressed case, you read the file data into the buffer without any adjustment. Which won't work for 24 bit images, after all they only have 3 bytes per pixel in the file. The first thing I'd do is to check the return value of the
read
function. It's always a good idea to check return values. And in this case, I think theread
function will return that it has read less data than what you requested it to read. (You request 4 bytes per pixel but the file probably only contains 3 -- unless you really have a TGA with an alpha channel.)To fix this, you first need to decide how you want to hold the data in memory. Either as it is in the file (3 or 4 bytes per pixel, depending on the file). Or always use 4 bytes per pixel in memory.
Holding the data in memory as it is in the file means the read and write code becomes a bit easier, but everything else becomes more complicated.
Holding the data in memory with fixed 4 bytes per pixel makes the read and write code a bit more complicated, but everything else becomes a lot easier, because it can always deal with the same format in memory. Personally I'd prefer this version.
Once you have made a choice, go over your read and write code again, and make sure it does what it's supposed to do. Because as I already wrote, there are some mistakes.
-
@tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:
@wob Hi Wob, I had mentioned here already that this is CPU intensive application and so want to stick onto to using only c++ std libraries and not use any 3rd party tools or libraries.
I don't understand that reasoning. Using third-party libraries will not make things slower, it will probably make things faster. Probably by a lot when we're talking about stuff like blur filters ("smoothing").
Of course you can implement a blur filter with good performance yourself. But it's really hard. A naiive implementation will probably be over an order of magnitude (10x) slower than a good one from a library.
-
@Th69 Hi Th69, can I know what is C&P error in line 130? what changes needed here in my code? please type modified code.
-
@hustbaer Hi hustbaer
I am not sure how to deal with both 32 and 24 bit TGA image files. Please suggest some logic so that it can support for both 32 and 24 bit TGA files.For DeCompressed case here, I modified the code as below. Is it correct?
if (!std::memcmp(UnCompressedTGAcompare, &Header, sizeof(UnCompressedTGAcompare))) { BitsPerPixel = Header[16]; //width = Header[13] * 256 + Header[12]; width = (Header[13] << 8) + Header[12]; //modified code //height = Header[15] * 256 + Header[14]; height = (Header[15] << 8) + Header[14]; //modified code size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
For Compressed case, I have modified the below code as follows . Please feel free to modify my code here.
else if (!std::memcmp(IsCompressedTGAcompare, &Header, sizeof(IsCompressedTGAcompare))) { BitsPerPixel = Header[16]; //width = Header[13] * 256 + Header[12]; width = (Header[13] << 8) + Header[12]; //modified code //height = Header[15] * 256 + Header[14]; height = (Header[15] << 8) + Header[14]; //modified code size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
This code change done with assumption that 0xFF is 255 and not 256.
-
@hustbaer Hi hustbaer
I can use the C/C++ standard libraries, but no external libraries beyond those. So I need to do image parsing and writing needs to be fully implemented within the program itself. Also it must support for both 24 and 32 bit images.
-
@hustbaer Do you suggest to use any specific blur filters? Are there any c++ code references?
-
@tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:
@hustbaer Hi hustbaer
I am not sure how to deal with both 32 and 24 bit TGA image files. Please suggest some logic so that it can support for both 32 and 24 bit TGA files.I already described the logic.
For DeCompressed case here, I modified the code as below. Is it correct?
if (!std::memcmp(UnCompressedTGAcompare, &Header, sizeof(UnCompressedTGAcompare))) { BitsPerPixel = Header[16]; //width = Header[13] * 256 + Header[12]; width = (Header[13] << 8) + Header[12]; //modified code //height = Header[15] * 256 + Header[14]; height = (Header[15] << 8) + Header[14]; //modified code size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
For Compressed case, I have modified the below code as follows . Please feel free to modify my code here.
else if (!std::memcmp(IsCompressedTGAcompare, &Header, sizeof(IsCompressedTGAcompare))) { BitsPerPixel = Header[16]; //width = Header[13] * 256 + Header[12]; width = (Header[13] << 8) + Header[12]; //modified code //height = Header[15] * 256 + Header[14]; height = (Header[15] << 8) + Header[14]; //modified code size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
This code change done with assumption that 0xFF is 255 and not 256.
Those changes don't make a difference, those lines were not the problem.
Also this smells a lot like homework, and I'm not going to do your homework for you.
-
@hustbaer With those code changes, I don't see weird glitchy patterns on the TGA image file anymore, rather I can see overlapping of two images and doesnot retain the actual color of the original image. Somehow the logic seems to be not working for me. Did you mean to modify read function with conditional check?What are other options here? Any way to attach images here?
-
@tampere2021 Below is my updated code for the read function. Please review it.
typedef union PixelInfo { std::uint32_t Colour; struct { std::uint8_t R, G, B, A; }RGBA; } *PPixelInfo; //For DeCompressed case here if (!std::memcmp(DeCompressed, &Header, sizeof(DeCompressed))) { BitsPerPixel = Header[16]; width = Header[13] * 256 + Header[12]; height = Header[15] * 256 + Header[14]; size = ((width * BitsPerPixel + 31) / 32) * 4 * height; //modified code if ((BitsPerPixel != 24) && (BitsPerPixel != 32) && ((width < 1) || (height < 1))) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image.."); } std::vector<unsigned char> ImageData(size); //this is for image data hFile.read(reinterpret_cast<char*>(ImageData.data()), size); unsigned char* BuffP = ImageData.data(); Pixels.resize(width * height); for (int I = 0; I < height; I++) { for (int J = 0; J < width; J++) { Pixels[(height - 1 - I) * width + J].RGBA.B = *(BuffP++); Pixels[(height - 1 - I) * width + J].RGBA.G = *(BuffP++); Pixels[(height - 1 - I) * width + J].RGBA.R = *(BuffP++); Pixels[(height - 1 - I) * width + J].RGBA.A = (BitsPerPixel > 24 ? *(BuffP++) : 0xFF); } if(BitsPerPixel == 24) //Has padding? BuffP += (4 - ((width * 3) % 4)) % 4; } ImageData.resize(size); ImageCompressed = false; hFile.read(reinterpret_cast<char*>(ImageData.data()), size); } //For Compressed case else if (!std::memcmp(IsCompressed, &Header, sizeof(IsCompressed))) { hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header)); BitsPerPixel = Header[16]; width = Header[13] * 256 + Header[12]; height = Header[15] * 256 + Header[14]; size = ((width * BitsPerPixel + 31) / 32) * 4 * height; if ((BitsPerPixel != 24) && (BitsPerPixel != 32) && ((width < 1) || (height < 1))) { hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); } PixelInfo Pixel = { 0 }; char* BuffP = reinterpret_cast<char*>(&Pixel); // added now int CurrentByte = 0; std::size_t CurrentPixel = 0; ImageCompressed = true; std::uint8_t ChunkHeader = { 0 }; int BytesPerPixel = (BitsPerPixel / 8); ImageData.resize(static_cast<size_t>(width) * static_cast<size_t>(height) * sizeof(PixelInfo)); do { ChunkHeader = 0; hFile.read(reinterpret_cast<char*>(&ChunkHeader), sizeof(ChunkHeader)); if (ChunkHeader < 128) { ++ChunkHeader; for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { //hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); hFile.read(BuffP, BytesPerPixel); //added now //ImageData[CurrentByte++] = Pixel.B; //ImageData[CurrentByte++] = Pixel.G; //ImageData[CurrentByte++] = Pixel.R; //if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; //added now Pixels[CurrentByte].RGBA.B = Pixel.RGBA.B; Pixels[CurrentByte].RGBA.G = Pixel.RGBA.G; Pixels[CurrentByte].RGBA.R = Pixel.RGBA.R; Pixels[CurrentByte].RGBA.A = (BitsPerPixel > 24) ? Pixel.RGBA.A : 0xFF; CurrentByte += BytesPerPixel; ++CurrentPixel; } } else { ChunkHeader -= 127; //hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); //added now hFile.read(BuffP, BytesPerPixel); for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { //ImageData[CurrentByte++] = Pixel.B; //ImageData[CurrentByte++] = Pixel.G; //ImageData[CurrentByte++] = Pixel.R; //if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; //added now Pixels[CurrentByte].RGBA.B = Pixel.RGBA.B; Pixels[CurrentByte].RGBA.G = Pixel.RGBA.G; Pixels[CurrentByte].RGBA.R = Pixel.RGBA.R; Pixels[CurrentByte].RGBA.A = (BitsPerPixel > 24) ? Pixel.RGBA.A : 0xFF; CurrentByte += BytesPerPixel; ++CurrentPixel; } } } while (CurrentPixel < (static_cast<size_t>(width) * static_cast<size_t>(height))); } else hFile.close(); throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File."); } hFile.close(); this->Pixels = ImageData; }
Also in lines 38,39,40,41 and 95,96,97,98 and 116,117,118,119. I got the below errors. Any idea what could be wrong here?
[Error] request for member 'RGBA' in '((Tga*)this)->Tga::Pixels.std::vector<_Tp, _Alloc>::operator[]<unsigned char, std::allocator<unsigned char> >(((std::vector<unsigned char>::size_type)((((((Tga*)this)->Tga::height - ((uint32_t)I)) + 4294967295u) * ((Tga*)this)->Tga::width) + ((uint32_t)J))))', which is of non-class type '__gnu_cxx::__alloc_traits<std::allocator<unsigned char> >::value_type {aka unsigned char}'