加载24位TGA

扫码查看
本文介绍了加载24位TGA的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个TGA加载器来加载TGA文件。



示例TGA 24位文件从Photoshop中加载并保存32位TGA文件只是很好,但当它涉及到加载和保存24位,它搞砸了。 :



>



我的输出:





任何想法是什么问题吗?我做的填充与我的位图加载器相同的方式,它的工作原理,但TGA不.. ..下面的代码可以编译和加载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>像素;
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 {
++ ChunkHeader;
for(int I = 0; I {
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 {
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或32 Bit TGA File。);
}

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

//翻转像素并将它们存储在我的向量中

for(std :: size_t I = 0; I {
for(std :: size_t J = 0; 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 ++);
像素[(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(无法打开文件进行写操作);}

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


//将其回滚到我们加载它时的状态..
for(std :: size_t I = 0; I {
for(std :: size_t J = 0; J {//翻转ScanLines / Rows回到正常。
*(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(((& 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(((& 0xFF)/ 0xFF));
hFile.put(BitsPerPixel);
hFile.put(0x0);
}
hFile.close();
}



int main()
{
}


解决方案

我认为你的问题是你假设一个TGA文件是填充的,而不是。 p>

因此,您的缓冲区大小错误,并且您错误地对其进行索引。你对输入和输出对称地这样做意味着它几乎可以工作,但是填充字节在图像中结束,(由于每行一个字节出来)导致图像上的斜条纹,交替通过颜色通道



您读取的字节数将少于预期,但您不检查。



尽管对于您处理2字节字段不正确是完全正确的,但是此特定图片的宽度/高度小于255像素,所以不受苦)。


I wrote a TGA loader to load TGA files. It loads and saves 32-bit TGA files just fine but when it comes to loading and saving 24-bit, it messed up.

Example TGA 24-bit file from Photoshop:

My output:

Any idea what is wrong with it? I did the padding the same way as my bitmap loader and it works but the TGA doesn't.. :S The code below can compile and load TGA's just in case anyone is wanting to test it.

#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()
{
}
解决方案

I think the problem you have is that you're assuming a TGA file is padded, and it isn't.

So your buffers are the wrong size, and you index them wrongly. That you do so symmetrically for input and output means that it almost works, but the padding byte ends up in the image, which (as it's out by one byte per line) results in a diagonal stripe up the image, alternating through the colour channels.

You reads will be returning less bytes than you expected, but you're not checking.

(Though 6502 is completely correct about you handling 2-byte fields incorrectly - however this particular image is less than 255 pixels wide/high, so doesn't suffer).

这篇关于加载24位TGA的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 03:30
查看更多