1

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

1 回答 1

2

我认为您的标题大小错误。各种位定义如下;断言只是为了确保编译器正确打包结构。

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;
}
于 2012-12-24T23:07:48.213 回答