Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从内存写入时,有时会损坏TGA文件_C++_File Writing_Tga - Fatal编程技术网

C++ 从内存写入时,有时会损坏TGA文件

C++ 从内存写入时,有时会损坏TGA文件,c++,file-writing,tga,C++,File Writing,Tga,当我从内存中写入包含从tga文件加载到tga文件的RGBA像素数据的图像缓冲区时,有时会观察到一种奇怪的行为 图像缓冲区从TGA文件加载,算法从该线程窃取和改编: 我从这个地址窃取并改编的写作方法: 下面是一个最小的可编译示例,其中tileA.tga被正确地保存回光盘作为tileA_new.tga,但是TileB_new.tga被破坏了图形看起来很奇怪,带有假像素!为什么TileB_new.tga坏了 这两个源tga文件是不同的,但它们可以在gimp和irfanview中正确查看,我仔细检查了加

当我从内存中写入包含从tga文件加载到tga文件的RGBA像素数据的图像缓冲区时,有时会观察到一种奇怪的行为

图像缓冲区从TGA文件加载,算法从该线程窃取和改编:

我从这个地址窃取并改编的写作方法:

下面是一个最小的可编译示例,其中tileA.tga被正确地保存回光盘作为tileA_new.tga,但是TileB_new.tga被破坏了图形看起来很奇怪,带有假像素!为什么TileB_new.tga坏了

这两个源tga文件是不同的,但它们可以在gimp和irfanview中正确查看,我仔细检查了加载算法。这是可行的,因为当我用OpenGL将两个加载的瓷砖的图像缓冲区渲染到屏幕上时,它们看起来是正确的!但将原始缓冲区写入磁盘的行为不同,为什么?我在十六进制编辑器中比较了源tga文件的头,但它们是相等的。此外,写入的tga文件具有相同的标题。 我能看到的是,tileB.tga的大小是tileA.tga的5倍,但这似乎是正确的,因为gimp/irfanview显示的是正确的。也许你能看到我在这里犯的错误

//一个包含两个tga文件的小型visual studio项目可在此处下载

最简单的例子:


因为我的评论似乎已经解决了问题,见上文。我将在这里展开

在至少有微软CRT的Windows上,以文本模式写入文件和以二进制模式写入文件之间存在显著差异

具体而言,任何与“\n”匹配的字符都将扩展为两个字符序列\r\n。此外,某些函数应用MB和unicode字符之间的转换。有关更多信息,请访问fopen上的MSDN文档,网址为:

因此,在读取/写入非文本数据时,请确保将rb或wb标志传递给fopen(视情况而定)


在Posix系统上,这一考虑不适用,但明确您的意图仍然是一种良好的做法。

以二进制文件而不是文本文件的形式写入,否则换行符将在Windows上展开。哦,天哪,哦,是的!我调试了几个小时,但这是一个简单的解决方案!详细解释请参见Thanx。
#include <vector>
#include <fstream>

//special-sausage for microsoft
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif

//=========================================
// Code for loading a TGA-file 
//=========================================
typedef union PixelInfo
{
    std::uint32_t Colour;
    struct
    {
        std::uint8_t R, G, B, A;
    };
} *PPixelInfo;

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

public:
    Tga(const char* FilePath);
    std::vector<std::uint8_t> GetPixels() { return this->Pixels; }
    std::uint32_t GetWidth() const { return this->width; }
    std::uint32_t GetHeight() const { return this->height; }
    std::uint32_t GetBitsPerPixel() const { return this->BitsPerPixel; }
    bool HasAlphaChannel() { return BitsPerPixel == 32; }
};

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

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

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

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

    hFile.close();
    this->Pixels = ImageData;
}

//=========================================
// code for writing a TGA-file 
//=========================================
void writeTGA(const std::string &refFile, Tga &refTGA)
{
    unsigned short width = static_cast<unsigned short>(refTGA.GetWidth());
    unsigned short height = static_cast<unsigned short>(refTGA.GetWidth());
    unsigned char bitsPerPixel = static_cast<unsigned char>(refTGA.GetBitsPerPixel());
    unsigned char bitsAlphaChannel = (bitsPerPixel == 32 ? 8 : 0);

    FILE * fptr = fopen(refFile.c_str(), "w");

    putc(0, fptr);
    putc(0, fptr);
    putc(2, fptr);                          /* uncompressed RGB */
    putc(0, fptr); putc(0, fptr);
    putc(0, fptr); putc(0, fptr);
    putc(0, fptr);
    putc(0, fptr); putc(0, fptr);           /* X origin */
    putc(0, fptr); putc(0, fptr);           /* y origin */
    putc((width & 0x00FF), fptr);
    putc((width & 0xFF00) / 256, fptr);
    putc((height & 0x00FF), fptr);
    putc((height & 0xFF00) / 256, fptr);
    putc(bitsPerPixel, fptr);               /* 24/32 bit bitmap */
    putc(bitsAlphaChannel, fptr);           /* When 32 bit, write 8, else 0 */

    auto pixelData = refTGA.GetPixels();

    for (size_t i = 0; i < static_cast<size_t>(width) * static_cast<size_t>(height) * (bitsPerPixel/8); i += (bitsPerPixel/8))
    {
        unsigned char r = pixelData[i];
        unsigned char g = pixelData[i + 1];
        unsigned char b = pixelData[i + 2];
        unsigned char a = (bitsAlphaChannel == 8 ? pixelData[i + 3] : 0);

        putc(b, fptr);
        putc(g, fptr);
        putc(r, fptr);

        if (bitsAlphaChannel == 8)
            putc(a, fptr);
    }

    fclose(fptr);
}

//=========================================
// main
//=========================================
int main()
{
    Tga oTgaA("tileA.tga");
    writeTGA("tileA_new.tga", oTgaA);  // works correct as aspected

    Tga oTgaB("tileB.tga");
    writeTGA("tileB_new.tga", oTgaB); // graphic-file has artefacts, why?
}