Need urgent help: TGA file read write and then Smoothing



  • The example code from my link reads some "image descriptor" data and some "color map" data depending on color map type. This is missing in your code, but as I wrote earlier, I'm not very familiar with the TGA file format, so I'm not sure about it.
    I would suggest to write some unit tests, so you can verify that you read the data you assume to read.


  • Gesperrt



  • @tampere2021: @wob gave you a link to a PDF describing the format and a decoder implementation. So read the PDF and start writing your own TGA parser/reader/decoder/however you like to call it. If something isn't 100% clear from the PDF, look it up in the decoder.

    The code you posted is not nearly enough to read a TGA, so I'd suggest you drop it and start from scratch.

    Or you might want to start with writing a TGA. Since you probably only have to support one format, this will be much easier. And in case your application only needs to be able to read TGA files that were created by it, then the reader/parser code will also be easy. I'd still recommend you start with the writer, because you can test the writer on its own - just use any standard image viewer/editor to test whether the files your program writes are OK.


  • Gesperrt

    @hustbaer Sure will go through the PDF. I am trying to read .tga file, then write another .tga file by applying smoothing using filters,so that the newly created .tga file will have the smoothing effects


  • Gesperrt

    @tampere2021 I wrote tga writer, but cant get it to work. what could be wrong here? please help me.

    [code]
    #include <fstream.h>
    #include <iostream.h>

    typedef unsigned char UCHAR;
    typedef signed char SCHAR;
    typedef unsigned short int USINT;

    class TARGA
    {
    public:
    TARGA();
    UCHAR idLength; // no. of chars in id field.
    UCHAR colorMapType; // 1 = map 0 = no map
    UCHAR imageType; // 1 = color mapped, 2 = rgb, 3 = b&w. All uncompressed
    USINT colorMapStart; // index of first entry (lo-hi)
    USINT colorMapNumEntries; // no. of color map entries (lo-hi)
    UCHAR bitPerEntry; // 16 for 16bit, 24 for 24bit...
    USINT xOrigin; // lower left corner (lo-hi)
    USINT yOrigin; // lower left corner (lo-hi)
    USINT width; // width of image (lo-hi)
    USINT height; // height of image (lo-hi)
    UCHAR bitsPerPixel; // 16 for 16bit, 24 for 24bit...
    UCHAR pixelData;
    UCHAR* image_data; // data stored differently depending on bitrate and colormap etc.
    // The footer is ignored
    };
    TARGA::TARGA()
    {
    idLength = 0;
    colorMapType = 0;
    imageType = 2; // truecolor
    colorMapStart = 0;
    colorMapNumEntries = 0;
    bitPerEntry = 24; // 24 bit
    xOrigin = 0;
    yOrigin = 0;
    width = 2; // width
    height = 2; // height
    bitsPerPixel = 24; // 24 bit
    pixelData = 0;

    image_data = new UCHAR[width*height*3];
    
    for (int n=0; n<width*height*3; n++)
    {
    	image_data[n]= 128; // should make all pixels gray
    }
    

    }

    main(int argc, char* argv)
    {
    fstream file;
    TARGA targa;

    char outfile[] = "outtest.tga";
    
    file.open(outfile, ios::out | ios::binary);	
    if (!file)
    {
    	cout << "Error in opening " << outfile << " for writing tga" << endl;
    	return 1;
    }
    
    file.write((UCHAR *)&targa,sizeof(targa));
    file.close();
    
    file.open(outfile, ios::in | ios::binary);
    if (!file)
    {
    	cout << "Error in opening " << outfile << " for reading tga" << endl;
    	return 1;
    }
    
    char c;
    int n=0;
    while (true)
    {
    	file.get(c);
    	cout << n << ": " << int(c) << endl;
    
    	if (file.eof()) { break; }
    	
    	n++;
    }
    //file.read((UCHAR *)&targa,sizeof(targa));
    file.close();
    
    
    return 0;
    

    }
    [/code]


  • Gesperrt

    @tampere2021 Can someone help here to make the code working?



  • @tampere2021 The code you posted doesn't compile on my system.

    Edit:

    I don't thing this will work

    file.write((UCHAR *)&targa,sizeof(targa));
    

    with

    UCHAR* image_data;
    

    Futhermore: Can you edit your post, mark your code and click on </> right next to the drop down box?



  • @tampere2021
    I had some minutes, so I adjusted your code in a way that produces a valid tga image:

    #include <vector>
    #include <fstream>
    #include <iostream>
    
    typedef unsigned char UCHAR;
    typedef signed char SCHAR;
    typedef unsigned short int USINT;
    
    class TARGA
    {
    public:
      TARGA();
    
      void write(std::ostream& f);
      
      UCHAR idLength; // no. of chars in id field.
      UCHAR colorMapType; // 1 = map 0 = no map
      UCHAR imageType; // 1 = color mapped, 2 = rgb, 3 = b&w. All uncompressed
      USINT colorMapStart; // index of first entry (lo-hi)
      USINT colorMapNumEntries; // no. of color map entries (lo-hi)
      UCHAR bitPerEntry; // 16 for 16bit, 24 for 24bit...
      USINT xOrigin; // lower left corner (lo-hi)
      USINT yOrigin; // lower left corner (lo-hi)
      USINT width; // width of image (lo-hi)
      USINT height; // height of image (lo-hi)
      UCHAR bitsPerPixel; // 16 for 16bit, 24 for 24bit...
      UCHAR pixelData; //descriptor
      std::vector<UCHAR> image_data; // data stored differently depending on bitrate and colormap etc.
      // The footer is ignored
    };
    
    TARGA::TARGA():
      idLength(0),
    colorMapType(0),
    imageType(2), // truecolor
    colorMapStart(0),
    colorMapNumEntries(0),
    bitPerEntry(24), // 24 bi
    xOrigin(0),
    yOrigin(0),
    width(2), // width
    height(2), // height
    bitsPerPixel(24), // 24 bit
    pixelData(0),
    image_data(width*height*3, 128)
    {
    
    void TARGA::write(std::ostream& f)
    {
      f.write(reinterpret_cast<char*>(&idLength), sizeof(idLength));
      f.write(reinterpret_cast<char*>(&colorMapType), sizeof(colorMapType));
      f.write(reinterpret_cast<char*>(&imageType), sizeof(imageType));
      f.write(reinterpret_cast<char*>(&colorMapStart), sizeof(colorMapStart));
      f.write(reinterpret_cast<char*>(&colorMapNumEntries), sizeof(colorMapNumEntries));
      f.write(reinterpret_cast<char*>(&bitPerEntry), sizeof(bitPerEntry));
      f.write(reinterpret_cast<char*>(&xOrigin), sizeof(xOrigin));
      f.write(reinterpret_cast<char*>(&yOrigin), sizeof(yOrigin));
      f.write(reinterpret_cast<char*>(&width), sizeof(width));
      f.write(reinterpret_cast<char*>(&height), sizeof(height));
      f.write(reinterpret_cast<char*>(&bitsPerPixel), sizeof(bitsPerPixel));
      f.write(reinterpret_cast<char*>(&pixelData), sizeof(pixelData));
      f.write(reinterpret_cast<char*>(&image_data[0]), sizeof(UCHAR) * image_data.size());
    }
    
    int main(int argc, char* argv)
    {
      using namespace std;
      fstream file;
      TARGA targa;
    
      char outfile[] = "outtest.tga";
    
      file.open(outfile, ios::out | ios::binary);
      if (!file)
      {
        cout << "Error in opening " << outfile << " for writing tga" << endl;
        return 1;
      }
    
      targa.write(file);
      file.close();
    
      return 0;
    }
    

    Instead of an C-Style array I used a vector for saving the data to prevent memory leaks.


  • Gesperrt

    @tampere2021 Thanks a lot for your quick help. i will test your code and get back to you soon.


  • Gesperrt

    @tampere2021 While compile the code,I got few errors.
    In line 56: void TARGA::write(std::ostream& f)
    [Error] qualified-id in declaration before '(' token
    In line 74: int main(int argc, char* argv)
    {
    [Error] a function-definition is not allowed here before '{' token


  • Gesperrt

    I have written a new code to handle both loading TGA file(tile.tga) and writing. But after I execute the code, it creates some weird glitchy patterns on the new TGA file(tilenew.tga). The tilenew.tga file seems broken when written from memory (containing RGBA pixel data loaded from a tga file) to the file back as tga. Below is my code. What am I doing wrong here?

    [code]
    #include <vector>
    #include <fstream>

    //=========================================
    // 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::vectorstd::uint8_t Pixels;
    bool ImageCompressed;
    std::uint32_t width, height, size, BitsPerPixel;

    public:
    Tga(const char* FilePath);
    std::vectorstd::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(), "wb");
    
    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 oTga("tile.tga");
    writeTGA("tile_new.tga", oTga);

    Tga oTga("tile.tga");
    writeTGA("tile_new.tga", oTga); 
    

    }

    [/code]



  • @tampere2021 sagte in Need urgent help: TGA file read write and then Smoothing:

    @tampere2021 While compile the code,I got few errors.
    In line 56: void TARGA::write(std::ostream& f)
    [Error] qualified-id in declaration before '(' token
    In line 74: int main(int argc, char* argv)
    {
    [Error] a function-definition is not allowed here before '{' token

    Oh, I just copied the code, but there is a closing brace missing in the ctor . Just add a } in line 46.

    Please edit your post and use code tags. It's really hard to read your code without them. Just write "```cpp" in the line in before your code

    and "```" in the line behind your code.


  • Gesperrt

    @Schlangenmensch Ok. understood. I have provided a new code here, for your review, Will resend it again with code tags for you to review. Please check and provide your comments for this new code.

    "```cpp"
    #include <vector>
    #include <fstream>

    //=========================================
    // 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::vectorstd::uint8_t Pixels;
    bool ImageCompressed;
    std::uint32_t width, height, size, BitsPerPixel;

    public:
    Tga(const char* FilePath);
    std::vectorstd::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::vectorstd::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(), "wb");

    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 oTga("tile.tga");
    writeTGA("tile_new.tga", oTga);

    Tga oTga("tile.tga");
    writeTGA("tile_new.tga", oTga);
    }
    "```"


  • Gesperrt

    @Schlangenmensch sagte in Need urgent help: TGA file read write and then Smoothing:

    "```"

    Reposting new code here again.

    "```cpp"
    #include <vector>
    #include <fstream>

    //=========================================
    // 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::vectorstd::uint8_t Pixels;
    bool ImageCompressed;
    std::uint32_t width, height, size, BitsPerPixel;

    public:
    Tga(const char* FilePath);
    std::vectorstd::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::vectorstd::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(), "wb");

    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 oTga("tile.tga");
    writeTGA("tile_new.tga", oTga);

    }

    "```"



  • not only does this forum feature a very nice preview of what you're about to post, it also offers the ability to edit your previous posts. I know, very advanced things to take into consideration...

    Also, markdown really isn't that hard

    ```cpp

    // some code

    ```



  • @tampere2021 please without the "" around the markdown tag


  • Gesperrt

    @Schlangenmensch Sorry for the tag, as I am new here. I have corrected it now and also added new code here, Please review it.
    I have written a new code to handle both loading TGA file(tile.tga) and writing. But after I execute the code, it creates some weird glitchy patterns on the new TGA file(tilenew.tga). The tilenew.tga file seems broken when written from memory (containing RGBA pixel data loaded from a tga file) to the file back as tga. Below is my code. What am I doing wrong here?

    #include <vector>
    #include <fstream>
    
    //=========================================
    // 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::vectorstd::uint8_t Pixels;
    bool ImageCompressed;
    std::uint32_t width, height, size, BitsPerPixel;
    
    public:
    Tga(const char* FilePath);
    std::vectorstd::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(), "wb");
    
    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 oTga("tile.tga");
    writeTGA("tile_new.tga", oTga);
    
    }
    
    

  • Gesperrt

    @tampere2021 Once this code works fine in writing tga , then I need to apply smoothing to the tile_new.tga file.



  • In the wiki article you find some smoothing algorithms: Smoothing



  • @tampere2021
    You may also look at documentation of opencv, a library for image processing. There several smoothing methods are documented.

    OpenCV: Smoothing images


Anmelden zum Antworten