Need urgent help: TGA file read write and then Smoothing


  • 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


  • Gesperrt

    I need to apply smoothing for TGA image without using any 3rd party libraries. How can i implement the smooth filter using c++ std library functions? Also my above code posted above has some issues. 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. Is it because of my asumption with 128x128 pixels? The code has some issue and need help to fix it first, before I smoothing it.



  • First I see a C&P error in line 130: width <-> height

    And you should use a Hexview program to compare your two files: Comparison of hex editors

    And why are you using the C-based FILE functions instead of ofstream (in comparison to the use of (i)fstream for reading)?

    PS: Nearly all 3rd party libraries also only use the C++ std library functions!



  • @tampere2021
    Your code has some issues in how it treats 24 vs. 32 bit images. The write function also contains a mistake in how it handles 32 bit alignment (it doesn't).

    E.g. in the read function (ctor), you always compute the size as ((width * BitsPerPixel + 31) / 32) * 4 * height, i.e. with 4 bytes per pixel. Then you allocate an array of that size. That's OK if you want to always use 4 bytes per pixel in memory - makes things easier.

    But then, in the uncompressed case, you read the file data into the buffer without any adjustment. Which won't work for 24 bit images, after all they only have 3 bytes per pixel in the file. The first thing I'd do is to check the return value of the read function. It's always a good idea to check return values. And in this case, I think the read function will return that it has read less data than what you requested it to read. (You request 4 bytes per pixel but the file probably only contains 3 -- unless you really have a TGA with an alpha channel.)

    To fix this, you first need to decide how you want to hold the data in memory. Either as it is in the file (3 or 4 bytes per pixel, depending on the file). Or always use 4 bytes per pixel in memory.

    Holding the data in memory as it is in the file means the read and write code becomes a bit easier, but everything else becomes more complicated.

    Holding the data in memory with fixed 4 bytes per pixel makes the read and write code a bit more complicated, but everything else becomes a lot easier, because it can always deal with the same format in memory. Personally I'd prefer this version.

    Once you have made a choice, go over your read and write code again, and make sure it does what it's supposed to do. Because as I already wrote, there are some mistakes.


Anmelden zum Antworten