title: Load 24 bit TGA
body: <p>I wrote a TGA loader to load TGA files. It loads and saves 32-bit TGA files just fine but when it comes to loading and saving 24-bit, it messed up.</p>
  
  <p>Example TGA 24-bit file from Photoshop:</p>
  
  <p><img src="https://i.stack.imgur.com/W1gxo.png" alt="enter image description here"></p>
  
  <p>My output:</p>
  
  <p><img src="https://i.stack.imgur.com/wZAso.png" alt="enter image description here"></p>
  
  <p>Any idea what is wrong with it? I did the padding the same way as my bitmap loader and it works but the TGA doesn't.. :S The code below can compile and load TGA's just in case anyone is wanting to test it.</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;vector&gt;
  #include &lt;stdexcept&gt;
  #include &lt;fstream&gt;
  #include &lt;cstring&gt;
  
  typedef union RGB
  {
      std::uint32_t Color;
      struct
      {
          std::uint8_t B, G, R, A;
      } RGBA;
  } *PRGB;
  
  class Tga
  {
      private:
          std::vector&lt;RGB&gt; Pixels;
          bool ImageCompressed;
          std::uint32_t width, height, size, BitsPerPixel;
  
      public:
          Tga(const char* FilePath);
          void Save(const char* FilePath);
  };
  
  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&lt;std::uint8_t&gt; 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&lt;char*&gt;(&amp;Header), sizeof(Header));
  
      if (!std::memcmp(DeCompressed, &amp;Header, sizeof(DeCompressed)))
      {
          BitsPerPixel = Header[16];
          width  = Header[13] * 0xFF + Header[12];
          height = Header[15] * 0xFF + Header[14];
          size  = ((width * BitsPerPixel + 31) / 32) * 4 * height;
  
          if ((BitsPerPixel != 24) &amp;&amp; (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&lt;char*&gt;(ImageData.data()), size);
      }
      else if (!std::memcmp(IsCompressed, &amp;Header, sizeof(IsCompressed)))
      {
          BitsPerPixel = Header[16];
          width  = Header[13] * 0xFF + Header[12];
          height = Header[15] * 0xFF + Header[14];
          size  = ((width * BitsPerPixel + 31) / 32) * 4 * height;
  
          if ((BitsPerPixel != 24) &amp;&amp; (BitsPerPixel != 32))
          {
              hFile.close();
              throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image.");
          }
  
          RGB Pixel = {0};
          int CurrentByte = 0;
          std::size_t CurrentPixel = 0;
          ImageCompressed = true;
          std::uint8_t ChunkHeader = {0};
          int BytesPerPixel = (BitsPerPixel / 8);
          ImageData.resize(width * height * sizeof(RGB));
  
          do
          {
              hFile.read(reinterpret_cast&lt;char*&gt;(&amp;ChunkHeader), sizeof(ChunkHeader));
  
              if(ChunkHeader &lt; 128)
              {
                  ++ChunkHeader;
                  for(int I = 0; I &lt; ChunkHeader; ++I, ++CurrentPixel)
                  {
                      hFile.read(reinterpret_cast&lt;char*&gt;(&amp;Pixel), BytesPerPixel);
  
                      ImageData[CurrentByte++] = Pixel.RGBA.B;
                      ImageData[CurrentByte++] = Pixel.RGBA.G;
                      ImageData[CurrentByte++] = Pixel.RGBA.R;
                      if (BitsPerPixel &gt; 24) ImageData[CurrentByte++] = Pixel.RGBA.A;
                  }
              }
              else
              {
                  ChunkHeader -= 127;
                  hFile.read(reinterpret_cast&lt;char*&gt;(&amp;Pixel), BytesPerPixel);
  
                  for(int I = 0; I &lt; ChunkHeader; ++I, ++CurrentPixel)
                  {
                      ImageData[CurrentByte++] = Pixel.RGBA.B;
                      ImageData[CurrentByte++] = Pixel.RGBA.G;
                      ImageData[CurrentByte++] = Pixel.RGBA.R;
                      if (BitsPerPixel &gt; 24) ImageData[CurrentByte++] = Pixel.RGBA.A;
                  }
              }
          } while(CurrentPixel &lt; (width * height));
      }
      else
      {
          hFile.close();
          throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File.");
      }
  
      hFile.close();
      std::uint8_t* BuffPos = ImageData.data();
      Pixels.resize(width * height);
  
      //Flip the pixels and store them in my vector..
  
      for (std::size_t I = 0; I &lt; height; ++I)
      {
          for (std::size_t J = 0; J &lt; width; ++J)
          {
              Pixels[(height - 1 - I) * width + J].RGBA.B = *(BuffPos++);
              Pixels[(height - 1 - I) * width + J].RGBA.G = *(BuffPos++);
              Pixels[(height - 1 - I) * width + J].RGBA.R = *(BuffPos++);
              Pixels[(height - 1 - I) * width + J].RGBA.A = (BitsPerPixel &gt; 24 ? *(BuffPos++) : 0xFF);
          }
          if(BitsPerPixel == 24)
              BuffPos += (-width * 3) &amp; 3;
      }
  }
  
  void Tga::Save(const char* FilePath)
  {
      std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
      if (!hFile.is_open()) {throw std::invalid_argument("Cannot open file for writing.");}
  
      std::vector&lt;std::uint8_t&gt; ImageData(size);
      std::uint8_t* BuffPos = ImageData.data();
  
  
      //Flip it back to how it was when we loaded it.. 
      for (std::size_t I = 0; I &lt; height; ++I)
      {
          for (std::size_t J = 0; J &lt; width; ++J)
          {                                                                   //Flip The ScanLines/Rows back to normal.
              *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.B;
              *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.G;
              *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.R;
  
              if (BitsPerPixel &gt; 24)
                  *(BuffPos++) = Pixels[(height - 1 - I) * width + J].RGBA.A;
          }
          if(BitsPerPixel == 24)
              BuffPos += (-width * 3) &amp; 3;
      }
  
      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};
  
      if (!ImageCompressed)
      {
          hFile.write(reinterpret_cast&lt;char*&gt;(&amp;DeCompressed), sizeof(DeCompressed));
          hFile.put((width &amp; 0xFF));
          hFile.put((width &amp; 0xFF) / 0xFF);
          hFile.put((height &amp; 0xFF));
          hFile.put(((height &amp; 0xFF) / 0xFF));
          hFile.put(BitsPerPixel);
          hFile.put(0x0);
          hFile.write(reinterpret_cast&lt;char*&gt;(ImageData.data()), ImageData.size());
          hFile.close();
      }
      else
      {
          hFile.write(reinterpret_cast&lt;char*&gt;(&amp;IsCompressed), sizeof(IsCompressed));
          hFile.put((width &amp; 0xFF));
          hFile.put((width &amp; 0xFF) / 0xFF);
          hFile.put((height &amp; 0xFF));
          hFile.put(((height &amp; 0xFF) / 0xFF));
          hFile.put(BitsPerPixel);
          hFile.put(0x0);
      }
      hFile.close();
  }
  
  
  
  int main()
  {
  }
  </code></pre>