我的 Targa Reader 出现了非常轻微的问题。1 个像素关闭,2 个额外像素为黑色:S
我正在加载的 24 位 targa 文件如下所示:
注意左上角的白色像素。左上角的第一个像素是白色的。
但是当我将文件像素保存为 24 位位图时,它看起来像:
请注意,白色像素不知何故位于右上角以及其上方的 2 个黑色像素。
我一生都无法弄清楚为什么除此之外其他一切都是正确的。这让我很困扰,因为我非常接近能够加载 TGA。
知道我下面的代码有什么问题吗?我正在为使用 Photoshop 创建的 16、24 和 32 位 TGA 文件编写 TGA 阅读器。
typedef union RGB //Struct which will hold all pixels.
{
uint32_t Color;
struct
{
unsigned char B, G, R, A;
} RGBA;
} *PRGB;
class Tga //My Targa class that will load the TGA file.
{
private:
std::vector<RGB> Pixels;
uint32_t width, height, size, BitsPerPixel;
public:
Tga(const char* FilePath);
};
Tga::Tga(const char* FilePath)
{
//Open the file for reading..
std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
if (!hFile.is_open()){throw std::invalid_argument("File Not Found.");}
//The header is 12 bytes. By reading it, I can tell if the TGA is compressed or not.
byte Header[12] = {0};
byte DeCompressed[12] = {0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
byte IsCompressed[12] = {0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header)); //Read the header.
if (memcmp(DeCompressed, &Header, sizeof(Header)) == 0) //If it is not compressed.
{
hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header));
BitsPerPixel = Header[4]; //Displays correctly.
width = Header[1] * 256 + Header[0]; //Displays correctly.
height = Header[3] * 256 + Header[2]; //Displays correctly.
size = ((width * BitsPerPixel + 31) / 32) * 4 * height; //Same algorithm for bitmaps. width * height * 3 OR width * height * 4. Taken from MSDN.
if ((BitsPerPixel != 24) && (BitsPerPixel != 32) && ((width < 1) || (height < 1)))
{
hFile.close();
throw std::logic_error("Error: Invalid TGA File. Width And Height cannot be less than 0. BitsPerPixel must be 24 or 32 bits.");
}
std::vector<unsigned char> ImageData(size); //An array for holding the image data.
hFile.read(reinterpret_cast<char*>(ImageData.data()), size);
unsigned char* BuffPos = ImageData.data();
Pixels.resize(width * height); //A vector holding my structs that will hold the pxiels.
//The following is supposed to flip the Image and copy it into my struct vector.
for (int I = 0; I < height; I++)
{
for (int J = 0; J < width; J++)
{
Pixels[(height - 1 - I) * width + J].RGBA.B = *(BuffPos++);
Pixels[(height - 1 - I) * width + J].RGBA.G = *(BuffPos++);
Pixels[(height - 1 - I) * width + J].RGBA.R = *(BuffPos++);
Pixels[(height - 1 - I) * width + J].RGBA.A = (BitsPerPixel > 24 ? *(BuffPos++) : 0xFF);
}
if(BitsPerPixel == 24) //Has padding?
BuffPos += (4 - ((width * 3) % 4)) % 4;
}
}
else if (memcmp(IsCompressed, &Header, sizeof(Header)) == 0) //The TGA is compressed..
{
hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header));
BitsPerPixel = Header[4];
height = Header[1] * 256 + Header[0];
width = Header[3] * 256 + Header[2];
size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
if ((BitsPerPixel != 24) && (BitsPerPixel != 32) && ((width < 1) || (height < 1)))
{
hFile.close();
throw std::logic_error("Error: Invalid TGA File. Width And Height cannot be less than 0. BitsPerPixel must be 24 or 32 bits.");
}
RGB Pixel = {0};
char* BuffPos = reinterpret_cast<char*>(&Pixel);
int CurrentByte = 0, CurrentPixel = 0;
int BytesPerPixel = (BitsPerPixel / 8);
Pixels.resize(width * height * sizeof(RGB));
do
{
byte ChunkHeader = 0;
hFile.read(reinterpret_cast<char*>(&ChunkHeader), sizeof(byte));
if (ChunkHeader < 128)
{
++ChunkHeader;
for (int I = 0; I < ChunkHeader; ++I)
{
hFile.read(BuffPos, BytesPerPixel);
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(BuffPos, BytesPerPixel);
for (int I = 0; I < ChunkHeader; ++I)
{
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 < (width * height));
}
hFile.close();
//I can guarantee nothing is wrong with the bitmap creator.
Bitmap BMP(width, height, 24); //Take the pixels structure and create a 24 bit bitmap. This works 100% of the time for PNG and Bitmap using the same structure.
BMP.Set(Pixels);
BMP.Save("C:/Foo.bmp");
}
int main()
{
Tga F("C:/Foo.tga");
}