2

TGAファイルをロードするTGAローダーを作成しました。32ビットのTGAファイルを問題なくロードおよび保存しますが、24ビットのロードおよび保存に関しては混乱します。

PhotoshopのTGA24ビットファイルの例:

ここに画像の説明を入力してください

私の出力:

ここに画像の説明を入力してください

何が悪いのか分かりますか?ビットマップローダーと同じ方法でパディングを実行しましたが、TGAは機能しません。:S以下のコードは、誰かがテストしたい場合に備えて、TGAをコンパイルおよびロードできます。

#include <iostream>
#include <vector>
#include <stdexcept>
#include <fstream>
#include <cstring>

typedef union RGB
{
    std::uint32_t Color;
    struct
    {
        std::uint8_t B, G, R, A;
    } RGBA;
} *PRGB;

class Tga
{
    private:
        std::vector<RGB> Pixels;
        bool ImageCompressed;
        std::uint32_t width, height, size, BitsPerPixel;

    public:
        Tga(const char* FilePath);
        void Save(const char* FilePath);
};

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] * 0xFF + Header[12];
        height = Header[15] * 0xFF + 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] * 0xFF + Header[12];
        height = Header[15] * 0xFF + 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.");
        }

        RGB Pixel = {0};
        int CurrentByte = 0;
        std::size_t CurrentPixel = 0;
        ImageCompressed = true;
        std::uint8_t ChunkHeader = {0};
        int BytesPerPixel = (BitsPerPixel / 8);
        ImageData.resize(width * height * sizeof(RGB));

        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.RGBA.B;
                    ImageData[CurrentByte++] = Pixel.RGBA.G;
                    ImageData[CurrentByte++] = Pixel.RGBA.R;
                    if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.RGBA.A;
                }
            }
            else
            {
                ChunkHeader -= 127;
                hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel);

                for(int I = 0; I < ChunkHeader; ++I, ++CurrentPixel)
                {
                    ImageData[CurrentByte++] = Pixel.RGBA.B;
                    ImageData[CurrentByte++] = Pixel.RGBA.G;
                    ImageData[CurrentByte++] = Pixel.RGBA.R;
                    if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.RGBA.A;
                }
            }
        } while(CurrentPixel < (width * height));
    }
    else
    {
        hFile.close();
        throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File.");
    }

    hFile.close();
    std::uint8_t* BuffPos = ImageData.data();
    Pixels.resize(width * height);

    //Flip the pixels and store them in my vector..

    for (std::size_t I = 0; I < height; ++I)
    {
        for (std::size_t 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)
            BuffPos += (-width * 3) & 3;
    }
}

void Tga::Save(const char* FilePath)
{
    std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
    if (!hFile.is_open()) {throw std::invalid_argument("Cannot open file for writing.");}

    std::vector<std::uint8_t> ImageData(size);
    std::uint8_t* BuffPos = ImageData.data();


    //Flip it back to how it was when we loaded it.. 
    for (std::size_t I = 0; I < height; ++I)
    {
        for (std::size_t J = 0; J < width; ++J)
        {                                                                   //Flip The ScanLines/Rows back to normal.
            *(BuffPos++) = 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;

            if (BitsPerPixel > 24)
                *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.A;
        }
        if(BitsPerPixel == 24)
            BuffPos += (-width * 3) & 3;
    }

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

    if (!ImageCompressed)
    {
        hFile.write(reinterpret_cast<char*>(&DeCompressed), sizeof(DeCompressed));
        hFile.put((width & 0xFF));
        hFile.put((width & 0xFF) / 0xFF);
        hFile.put((height & 0xFF));
        hFile.put(((height & 0xFF) / 0xFF));
        hFile.put(BitsPerPixel);
        hFile.put(0x0);
        hFile.write(reinterpret_cast<char*>(ImageData.data()), ImageData.size());
        hFile.close();
    }
    else
    {
        hFile.write(reinterpret_cast<char*>(&IsCompressed), sizeof(IsCompressed));
        hFile.put((width & 0xFF));
        hFile.put((width & 0xFF) / 0xFF);
        hFile.put((height & 0xFF));
        hFile.put(((height & 0xFF) / 0xFF));
        hFile.put(BitsPerPixel);
        hFile.put(0x0);
    }
    hFile.close();
}



int main()
{
}
4

2 に答える 2

5

あなたのコードには確かに少なくともいくつかの問題があります:

width  = Header[13] * 0xFF + Header[12];

これは2バイトの値を読み取る正しい方法ではありません...0xFFは255であり、256ではありません。正しい方法は

width  = (Header[13] << 8) + Header[12];

あなたのコードはまた、書くときに同じ領域で異なる問題を抱えています:

hFile.put((width & 0xFF));
hFile.put((width & 0xFF) / 0xFF);

コードが間違っています(たとえば、の下位8ビットのみを考慮することに注意してくださいwidth)。代わりに正しいバージョンになります

hFile.put(width & 0xFF);
hFile.put((width >> 8) & 0xFF);
于 2012-12-30T23:14:25.590 に答える
2

あなたが抱えている問題は、TGAファイルがパディングされていると想定していることだと思いますが、そうではありません。

したがって、バッファのサイズが間違っており、インデックスが間違っています。入力と出力で対称的に行うということは、ほぼ機能することを意味しますが、パディングバイトは画像内で終了します。これにより、画像上に斜めのストライプが作成され、カラーチャネルが交互に表示されます。 。

読み取りは予想よりも少ないバイトを返しますが、チェックしていません。

6502は、2バイトのフィールドを誤って処理することについては完全に正しいですが、この特定の画像は幅/高さが255ピクセル未満であるため、問題はありません)。

于 2012-12-31T00:08:24.240 に答える