c++c++11directxdirectx-11tga

TGA File Header is not correct on Windows


I'm trying to read a TGA header of the file I created in Paint.net. It seems that there is something wrong with it. If I use the header structure from the specification, like this one:

typedef struct {
    CHAR  idlength;
    CHAR  colourmaptype;
    CHAR  datatypecode;
    WORD colourmaporigin;
    WORD colourmaplength;
    CHAR  colourmapdepth;
    WORD x_origin;
    WORD y_origin;
    WORD width;
    WORD height;
    CHAR  bitsperpixel;
    CHAR  imagedescriptor;
} TGAHEADER;

I get this:

Data size: 0
Color Map type: 0
Data Type code: 2
Bits per-pixel: 0
Size: 501 x 2080

Which is wrong, since my image is 501x501, 32-bits per pixel. However, if I comment out two bytes from the structure, f.e. this one colourmaporigin, I get this:

Data size: 0
Color Map type: 0
Data Type code: 2
Bits per-pixel: 32
Size: 501 x 501

Which is correct. I was reading everything I found on this file format. It never says that any of those fields are optional or something.

How come I get results like this?

Here's the code for reading the data:

void Image::readTGA()
{
    TGAHEADER fileHeader;

    std::ifstream fileHandle(fileName, std::ios::binary);
    if (fileHandle.is_open())
    {
        fileHandle.read((char*)(&fileHeader), sizeof(TGAHEADER));
        fileHandle.close();
    }
    else
    {
        std::cout << "An error occured when opening a file." << std::endl;
    }
}

I'm using VS2015, targeting x86 platform.


Solution

  • It's a padding issue. With Visual Studio you can use the #pragma pack(1) compiler directive disable any padding of structures.

    Demonstration

    #include<stdio.h>
    #include<windows.h>
    
    // Default packing of structure with padding
    
    typedef struct {
      CHAR  idlength;
      CHAR  colourmaptype;
      CHAR  datatypecode;
      WORD colourmaporigin;
      WORD colourmaplength;
      CHAR  colourmapdepth;
      WORD x_origin;
      WORD y_origin;
      WORD width;
      WORD height;
      CHAR  bitsperpixel;
      CHAR  imagedescriptor;
    } TGAHEADER;
    
    
    #pragma pack(1) // structure fields are aligned to byte boundary (no padding)
    
    typedef struct {
      CHAR  idlength;
      CHAR  colourmaptype;
      CHAR  datatypecode;
      WORD colourmaporigin;
      WORD colourmaplength;
      CHAR  colourmapdepth;
      WORD x_origin;
      WORD y_origin;
      WORD width;
      WORD height;
      CHAR  bitsperpixel;
      CHAR  imagedescriptor;
    } TGAHEADER_PACKED;
    
    int main()
    {
      printf("Offset of field bitsperpixel in TGAHEADER structure %d\n", offsetof(TGAHEADER, bitsperpixel));
      printf("Offset of field bitsperpixel in packed TGAHEADER structure %d\n", offsetof(TGAHEADER_PACKED, bitsperpixel));
    }
    

    Output:

    Offset of field bitsperpixel in TGAHEADER structure 18
    Offset of field bitsperpixel in packed TGAHEADER structure 16