]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/imagtga.cpp
non-pch build fix
[wxWidgets.git] / src / common / imagtga.cpp
index 281682cbb9f6773bdcb49d090d1011a649abfeae..e3b5473995a80754ac2fded21dc3cb68835ba18d 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "wx/imagtga.h"
 #include "wx/log.h"
+#include "wx/scopeguard.h"
 
 // ----------------------------------------------------------------------------
 // constants
 // TGA error codes.
 enum
 {
-    wxTGA_OK = 0,
-    wxTGA_INVFORMAT = 1,
-    wxTGA_MEMERR = 2
+    wxTGA_OK,
+    wxTGA_INVFORMAT,
+    wxTGA_MEMERR,
+    wxTGA_IOERR
 };
 
 // TGA header bytes.
@@ -99,8 +101,9 @@ void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize)
     }
 }
 
+// return wxTGA_OK or wxTGA_IOERR
 static
-void DecodeRLE(unsigned char* imageData, unsigned long imageSize,
+int DecodeRLE(unsigned char* imageData, unsigned long imageSize,
                short pixelSize, wxInputStream& stream)
 {
     unsigned long index = 0;
@@ -110,7 +113,11 @@ void DecodeRLE(unsigned char* imageData, unsigned long imageSize,
 
     while (index < imageSize)
     {
-        current = stream.GetC();
+        int ch = stream.GetC();
+        if ( ch == wxEOF )
+            return wxTGA_IOERR;
+
+        current = ch;
 
         // RLE packet.
         if ( current & 0x80 )
@@ -125,7 +132,8 @@ void DecodeRLE(unsigned char* imageData, unsigned long imageSize,
             index += current * pixelSize;
 
             // Repeat the pixel length times.
-            stream.Read(buf, pixelSize);
+            if ( !stream.Read(buf, pixelSize) )
+                return wxTGA_IOERR;
 
             for (unsigned int i = 0; i < length; i++)
             {
@@ -144,11 +152,14 @@ void DecodeRLE(unsigned char* imageData, unsigned long imageSize,
             index += length;
 
             // Write the next length pixels directly to the image data.
-            stream.Read(imageData, length);
+            if ( !stream.Read(imageData, length) )
+                return wxTGA_IOERR;
 
             imageData += length;
         }
     }
+
+    return wxTGA_OK;
 }
 
 static
@@ -187,6 +198,8 @@ int ReadTGA(wxImage* image, wxInputStream& stream)
         return wxTGA_MEMERR;
     }
 
+    wxON_BLOCK_EXIT1(free, imageData);
+
     unsigned char *dst = image->GetData();
 
     unsigned char* alpha = NULL;
@@ -198,7 +211,8 @@ int ReadTGA(wxImage* image, wxInputStream& stream)
     }
 
     // Seek from the offset we got from the TGA header.
-    stream.SeekI(offset, wxFromStart);
+    if (stream.SeekI(offset, wxFromStart) == wxInvalidOffset)
+        return wxTGA_INVFORMAT;
 
     // Load a palette if we have one.
     if (colorType == wxTGA_MAPPED)
@@ -439,7 +453,9 @@ int ReadTGA(wxImage* image, wxInputStream& stream)
 
             // Decode the RLE data.
 
-            DecodeRLE(imageData, imageSize, pixelSize, stream);
+            int rc =  DecodeRLE(imageData, imageSize, pixelSize, stream);
+            if ( rc != wxTGA_OK )
+                return rc;
 
             // If orientation == 0, then the image is stored upside down.
             // We need to store it right side up.
@@ -497,7 +513,9 @@ int ReadTGA(wxImage* image, wxInputStream& stream)
         {
             // Decode the RLE data.
 
-            DecodeRLE(imageData, imageSize, pixelSize, stream);
+            int rc = DecodeRLE(imageData, imageSize, pixelSize, stream);
+            if ( rc != wxTGA_OK )
+                return rc;
 
             // If orientation == 0, then the image is stored upside down.
             // We need to store it right side up.
@@ -575,7 +593,9 @@ int ReadTGA(wxImage* image, wxInputStream& stream)
         {
             // Decode the RLE data.
 
-            DecodeRLE(imageData, imageSize, pixelSize, stream);
+            int rc = DecodeRLE(imageData, imageSize, pixelSize, stream);
+            if ( rc != wxTGA_OK )
+                return rc;
 
             // If orientation == 0, then the image is stored upside down.
             // We need to store it right side up.
@@ -626,15 +646,74 @@ int ReadTGA(wxImage* image, wxInputStream& stream)
             return wxTGA_INVFORMAT;
     }
 
-    free(imageData);
-
     return wxTGA_OK;
 }
 
 static
-int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream))
+int SaveTGA(const wxImage& image, wxOutputStream *stream)
 {
-    wxLogError(wxT("Saving in TGA format is not implemented."));
+    bool hasAlpha = image.HasAlpha();
+    unsigned bytesPerPixel = 3 + (hasAlpha ? 1 : 0);
+    wxSize size = image.GetSize();
+    size_t scanlineSize = size.x * bytesPerPixel;
+    unsigned char *scanlineData = (unsigned char *) malloc(scanlineSize);
+    if (!scanlineData)
+    {
+        return wxTGA_MEMERR;
+    }
+
+    wxON_BLOCK_EXIT1(free, scanlineData);
+
+    // Compose and write the TGA header
+    unsigned char hdr[HDR_SIZE];
+    (void) memset(&hdr, 0, HDR_SIZE);
+
+    hdr[HDR_COLORTYPE] = wxTGA_UNMAPPED;
+    hdr[HDR_IMAGETYPE] = 2 /* Uncompressed truecolour */;
+
+    hdr[HDR_WIDTH] =  size.x & 0xFF;
+    hdr[HDR_WIDTH + 1] =  (size.x >> 8) & 0xFF;
+
+    hdr[HDR_HEIGHT] =  size.y & 0xFF;
+    hdr[HDR_HEIGHT + 1] =  (size.y >> 8) & 0xFF;
+
+    hdr[HDR_BPP] = hasAlpha ? 32 : 24;
+    hdr[HDR_ORIENTATION] = 1 << 5; // set bit to indicate top-down order
+    if (hasAlpha)
+    {
+        hdr[HDR_ORIENTATION] |= 8; // number of alpha bits
+    }
+
+    if ( !stream->Write(hdr, HDR_SIZE) )
+    {
+        return wxTGA_IOERR;
+    }
+
+
+    // Write image data, converting RGB to BGR and adding alpha if applicable
+
+    unsigned char *src = image.GetData();
+    unsigned char *alpha = image.GetAlpha();
+    for (int y = 0; y < size.y; ++y)
+    {
+        unsigned char *dst = scanlineData;
+        for (int x = 0; x < size.x; ++x)
+        {
+            dst[0] = src[2];
+            dst[1] = src[1];
+            dst[2] = src[0];
+            if (alpha)
+            {
+                dst[3] = *(alpha++);
+            }
+            src += 3;
+            dst += bytesPerPixel;
+        }
+        if ( !stream->Write(scanlineData, scanlineSize) )
+        {
+            return wxTGA_IOERR;
+        }
+    }
 
     return wxTGA_OK;
 }
@@ -651,7 +730,9 @@ bool wxTGAHandler::LoadFile(wxImage* image,
     if ( !CanRead(stream) )
     {
         if ( verbose )
+        {
             wxLogError(wxT("TGA: this is not a TGA file."));
+        }
 
         return false;
     }
@@ -673,6 +754,10 @@ bool wxTGAHandler::LoadFile(wxImage* image,
                     wxLogError(wxT("TGA: couldn't allocate memory."));
                     break;
 
+                case wxTGA_IOERR:
+                    wxLogError(wxT("TGA: couldn't read image data."));
+                    break;
+
                 default:
                     wxLogError(wxT("TGA: unknown error!"));
             }
@@ -688,7 +773,7 @@ bool wxTGAHandler::LoadFile(wxImage* image,
 
 bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose)
 {
-    int error = SaveTGA(image, stream);
+    int error = SaveTGA(*image, &stream);
 
     if ( error != wxTGA_OK )
     {
@@ -696,14 +781,14 @@ bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose
         {
             switch ( error )
             {
-                case wxTGA_INVFORMAT:
-                    wxLogError(wxT("TGA: invalid image."));
-                    break;
-
                 case wxTGA_MEMERR:
                     wxLogError(wxT("TGA: couldn't allocate memory."));
                     break;
 
+                case wxTGA_IOERR:
+                    wxLogError(wxT("TGA: couldn't write image data."));
+                    break;
+
                 default:
                     wxLogError(wxT("TGA: unknown error!"));
             }
@@ -719,7 +804,7 @@ bool wxTGAHandler::DoCanRead(wxInputStream& stream)
 {
     // read the fixed-size TGA headers
     unsigned char hdr[HDR_SIZE];
-    stream.Read(hdr, HDR_SIZE);
+    stream.Read(hdr, HDR_SIZE);     // it's ok to modify the stream position here
 
     // Check wether we can read the file or not.