Need urgent help: TGA file read write and then Smoothing



  • Ok, so you don't want to answer the "why" question. I guess then you will have to study the specification: http://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf

    You could also look at libraries, for example here: https://github.com/aseprite/tga/blob/main/decoder.cpp - but that would be "using" a 3rd party lib for help. (no idea if this lib is any good)


  • Gesperrt

    @tampere2021 This link has only read TGA .How about write TGA? I need to handle uncompressed TGA image file first for both 24 and 32bit cases.


  • Gesperrt

    @wob Hi Wob, I had mentioned here already that this is CPU intensive application and so want to stick onto to using only c++ std libraries and not use any 3rd party tools or libraries.



  • @tampere2021

    Hi Wob, I had mentioned here already that this is CPU intensive application and so want to stick onto to using only c++ std libraries and not use any 3rd party tools or libraries.

    Ah, the explanation arrived was the same minute I wrote my reply. Didn't see it, sorry.

    However, I don't understand the connection here - do you think all existing libraries are slow? So your real question is "What is the best (i.e. fastest) library to read tga files?" - benchmark a few libraries, select the fastest, maybe even try to optimize an existing library, done. That will very likely be much faster than starting from scratch.

    This link has only read TGA .How about write TGA?

    No idea who you did reply to. The link I gave also has an encoder...



  • @tampere2021 So, you've no idea how to implement it by yourself but you think you can still do better than a 3rd party lib. That's ambitious.
    My link has no further dependencies, but, yes it's just reading. You'd to implement the writing part by yourself. But my link was more thought as inspiration how you could start from scratch.


  • Gesperrt

    @Schlangenmensch Ok. I will take it as a reference.


  • Gesperrt

    @wob Hi Wob, I am not doing any benchmarking for libraries here, rather want to just do a read TGA image file,then write the same TGA image file to another file by applying smoothing with the help of filters. This is to identify how well we can do smoothing of TGA image files. Hope you understood what I am trying to do here.


  • Gesperrt

    @Schlangenmensch Hi Contortionist, I tried to read targa file, fetch some header values by check them, but none of the values gets changed and I then write to another targa file, but it doesnt seem to work. any idea what is wrong here?

    [code]
    struct TARGAFILE {
    char idLength;
    char colourMapType;
    char imageType;
    short colourMapStart;
    short colourMapNumEntries;
    char bitsPerEntry;
    short xOrigin;
    short yOrigin;
    short width;
    short height;
    char bitsPerPixel;
    char* pixelData;
    };

    TARGAFILE fetchImage(const std::string& pathToImage) {
    std::ifstream image(pathToImage, std::ios::binary);
    if (!image.is_open()) {
    throw FileNotFound();
    }
    TARGAFILE targaFile;
    image.read(&targaFile.idLength, sizeof(targaFile.idLength));
    image.read(&targaFile.colourMapType, sizeof(targaFile.colourMapType));
    image.read(&targaFile.imageType, sizeof(targaFile.imageType));
    image.read((char*)(&targaFile.colourMapStart), sizeof(targaFile.colourMapStart));
    image.read((char*)(&targaFile.colourMapNumEntries), sizeof(targaFile.colourMapNumEntries));
    image.read(&targaFile.bitsPerEntry, sizeof(targaFile.bitsPerEntry));
    image.read((char*)(&targaFile.xOrigin), sizeof(targaFile.xOrigin));
    image.read((char*)(&targaFile.yOrigin), sizeof(targaFile.yOrigin));
    image.read((char*)(&targaFile.width), sizeof(targaFile.width));
    image.read((char*)(&targaFile.height), sizeof(targaFile.height));
    image.read(&targaFile.bitsPerPixel, sizeof(targaFile.bitsPerPixel));

    int imageDataSize = targaFile.width * targaFile.height * (targaFile.bitsPerPixel / 8);
    
    targaFile.pixelData = new char[imageDataSize];
    
    int originalPosition = (int)image.tellg();
    image.read(targaFile.pixelData, imageDataSize);
    return targaFile;
    

    }

    void CheckHdrImage(TARGAFILE targaFile){
    std::ofstream output("test.tga", std::ios::binary);
    output.write(&targaFile.idLength, sizeof(targaFile.idLength));
    output.write(&targaFile.colourMapType, sizeof(targaFile.colourMapType));
    output.write(&targaFile.imageType, sizeof(targaFile.imageType));
    output.write(reinterpret_cast<const char*>(&targaFile.colourMapStart), sizeof(targaFile.colourMapStart));
    output.write(reinterpret_cast<const char*>(&targaFile.colourMapNumEntries), sizeof(targaFile.colourMapNumEntries));
    output.write(&targaFile.bitsPerEntry, sizeof(targaFile.bitsPerEntry));
    output.write(reinterpret_cast<const char*>(&targaFile.xOrigin), sizeof(targaFile.xOrigin));
    output.write(reinterpret_cast<const char*>(&targaFile.yOrigin), sizeof(targaFile.yOrigin));
    output.write(reinterpret_cast<const char*>(&targaFile.width), sizeof(targaFile.width));
    output.write(reinterpret_cast<const char*>(&targaFile.height), sizeof(targaFile.height));
    output.write(&targaFile.bitsPerPixel, sizeof(targaFile.bitsPerPixel));
    output.write(reinterpret_cast<const char*>(&targaFile.pixelData), sizeof(targaFile.pixelData));
    output.close();
    }
    [/code]



  • 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.


Anmelden zum Antworten