Проблемы с отображением Targa / TGA

Очень небольшая проблема с моим Targa Reader. Один пиксель отключен, а 2 дополнительных пикселя черные: S

24-битный файл targa, который я загружаю, выглядит следующим образом:
введите описание изображения здесь

Обратите внимание на белый пиксель в самом верхнем левом углу. Самый первый пиксель вверху слева — белый.

Но когда я сохраняю пиксели файла обратно как 24-битное растровое изображение, это выглядит так:
введите описание изображения здесь

Обратите внимание, что белый пиксель находится сверху справа, а также 2 черных пикселя над ним.

Я не могу понять, почему все остальное правильно, за исключением этого … Это беспокоит меня, потому что я так близок к возможности загружать TGA.

Любая идея, что не так с моим кодом ниже? Я пишу TGA Reader для 16, 24 и 32-битных файлов TGA, созданных с помощью Photoshop.

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");
}

1

Решение

Я думаю, что у вас неправильный размер заголовка. Различные биты определены как ниже; утверждения существуют только для того, чтобы убедиться, что компилятор правильно упаковывает структуры.

typedef uint8_t byte;

enum class color_map_type : byte {
absent  = 0,
present = 1,
};

enum class image_type : byte {
none             = 0,
color_mapped     = 1,
true_color       = 2,
black_white      = 3,
rle_color_mapped = 9,
rle_true_color   = 10,
rle_black_white  = 11,
};

struct color_map_spec {
uint16_t first_entry_index;
uint16_t length;
byte     entry_size;
};
static_assert(sizeof(color_map_spec) == 5, "bad size");

struct image_descriptor {
byte alpha    : 4;
byte right    : 1;
byte top      : 1;
byte reserved : 2;
};
static_assert(sizeof(image_descriptor) == 1, "bad size");

struct image_spec {
uint16_t         x_origin;
uint16_t         y_origin;
uint16_t         width;
uint16_t         height;
byte             depth;
image_descriptor descriptor;
};
static_assert(sizeof(image_spec) == 10, "bad size");

struct header {
byte           id_length;
color_map_type color_map_type;
image_type     image_type;
color_map_spec color_map_spec;
image_spec     image_spec;
};
static_assert(sizeof(header) == 18, "bad size");

struct footer {
uint32_t ext_area_offset;
uint32_t dev_dir_offset;
char     signature[16];
char     dot_terminator;
char     null_terminator;
}
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]