]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/imagpng.cpp
support for huge files (patch 1002226)
[wxWidgets.git] / src / common / imagpng.cpp
index bdbe0c5267e22894de8b155cf7bcd1a58c6ee0e7..f3fe5cbce85e73338baa90219eb1d47bdac220e4 100644 (file)
@@ -11,7 +11,7 @@
 // declarations
 // ============================================================================
 
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 #pragma implementation "imagpng.h"
 #endif
 
@@ -74,7 +74,7 @@ enum Transparency
 // return the kind of transparency needed for this image assuming that it does
 // have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask
 static Transparency
-CheckTransparency(const unsigned char *ptr,
+CheckTransparency(unsigned char **lines,
                   png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h,
                   size_t numColBytes);
 
@@ -160,12 +160,14 @@ struct wxPNGInfoStruct
 extern "C"
 {
 
-void PNGLINKAGEMODE _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
+void PNGLINKAGEMODE wx_PNG_stream_reader( png_structp png_ptr, png_bytep data,
+                                          png_size_t length )
 {
     WX_PNG_INFO(png_ptr)->stream.in->Read(data, length);
 }
 
-void PNGLINKAGEMODE _PNG_stream_writer( png_structp png_ptr, png_bytep data, png_size_t length )
+void PNGLINKAGEMODE wx_PNG_stream_writer( png_structp png_ptr, png_bytep data,
+                                          png_size_t length )
 {
     WX_PNG_INFO(png_ptr)->stream.out->Write(data, length);
 }
@@ -210,30 +212,30 @@ PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message)
 // need a full blown alpha channel in wxImage
 //
 // parameters:
-//      ptr             the start of the data to examine
+//      lines           raw PNG data
 //      x, y            starting position
 //      w, h            size of the image
 //      numColBytes     number of colour bytes (1 for grey scale, 3 for RGB)
 //                      (NB: alpha always follows the colour bytes)
 Transparency
-CheckTransparency(const unsigned char *ptr,
+CheckTransparency(unsigned char **lines,
                   png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h,
                   size_t numColBytes)
 {
-    // we start from (x + 1, y)
-    x++;
-
     // suppose that a mask will suffice and check all the remaining alpha
     // values to see if it does
-    unsigned const char *ptr2 = ptr;
-    for ( png_uint_32 y2 = y; y2 < h; y2++ )
+    for ( ; y < h; y++ )
     {
+        // each pixel is numColBytes+1 bytes, offset into the current line by
+        // the current x position
+        unsigned const char *ptr = lines[y] + (x * (numColBytes + 1));
+
         for ( png_uint_32 x2 = x; x2 < w; x2++ )
         {
             // skip the grey or colour byte(s)
-            ptr2 += numColBytes;
+            ptr += numColBytes;
 
-            unsigned char a2 = *ptr2++;
+            unsigned char a2 = *ptr++;
 
             if ( !IsTransparent(a2) && !IsOpaque(a2) )
             {
@@ -319,7 +321,7 @@ bool wxPNGHandler::DoCanRead( wxInputStream& stream )
     unsigned char hdr[4];
 
     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
-        return FALSE;
+        return false;
 
     return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0;
 }
@@ -365,7 +367,7 @@ void CopyDataFromPNG(wxImage *image,
                     // only, otherwisewe need the latter
                     transparency = CheckTransparency
                                    (
-                                        ptrSrc,
+                                        lines,
                                         x, y,
                                         width, height,
                                         1
@@ -437,7 +439,7 @@ void CopyDataFromPNG(wxImage *image,
                 {
                     transparency = CheckTransparency
                                    (
-                                        ptrSrc,
+                                        lines,
                                         x, y,
                                         width, height,
                                         3
@@ -460,25 +462,27 @@ void CopyDataFromPNG(wxImage *image,
                     case Transparency_Mask:
                         if ( IsTransparent(a) )
                         {
-                            // if we couldn't find a unique colour for the mask, we
-                            // can have real pixels with the same value as the mask
-                            // and it's better to slightly change their colour than
-                            // to make them transparent
-                            if ( r == rMask && g == gMask && b == bMask )
-                            {
-                                r++;
-                            }
-
                             *ptrDst++ = rMask;
                             *ptrDst++ = bMask;
                             *ptrDst++ = gMask;
                             break;
                         }
-                        // else: !transparent
-
-                        // must be opaque then as otherwise we shouldn't be
-                        // using the mask at all
-                        wxASSERT_MSG( IsOpaque(a), _T("logic error") );
+                        else // !transparent
+                        {
+                            // must be opaque then as otherwise we shouldn't be
+                            // using the mask at all
+                            wxASSERT_MSG( IsOpaque(a), _T("logic error") );
+
+                            // if we couldn't find a unique colour for the
+                            // mask, we can have real pixels with the same
+                            // value as the mask and it's better to slightly
+                            // change their colour than to make them
+                            // transparent
+                            if ( r == rMask && g == gMask && b == bMask )
+                            {
+                                r++;
+                            }
+                        }
 
                         // fall through
 
@@ -538,7 +542,7 @@ wxPNGHandler::LoadFile(wxImage *image,
 
     // NB: please see the comment near wxPNGInfoStruct declaration for
     //     explanation why this line is mandatory
-    png_set_read_fn( png_ptr, &wxinfo, _PNG_stream_reader);
+    png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader);
 
     info_ptr = png_create_info_struct( png_ptr );
     if (!info_ptr)
@@ -566,7 +570,7 @@ wxPNGHandler::LoadFile(wxImage *image,
         png_set_expand( png_ptr );
     png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
 
-    image->Create( (int)width, (int)height );
+    image->Create((int)width, (int)height, false /* no need to init pixels */);
 
     if (!image->Ok())
         goto error;
@@ -596,7 +600,7 @@ wxPNGHandler::LoadFile(wxImage *image,
         free( lines[i] );
     free( lines );
 
-    return TRUE;
+    return true;
 
 error:
     if (verbose)
@@ -622,7 +626,7 @@ error:
         else
             png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
     }
-    return FALSE;
+    return false;
 }
 
 // ----------------------------------------------------------------------------
@@ -641,7 +645,7 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
     {
         if (verbose)
            wxLogError(_("Couldn't save PNG image."));
-        return FALSE;
+        return false;
     }
 
     png_set_error_fn(png_ptr, (png_voidp)NULL, wx_png_error, wx_png_warning);
@@ -652,7 +656,7 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
         png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
         if (verbose)
            wxLogError(_("Couldn't save PNG image."));
-        return FALSE;
+        return false;
     }
 
     if (setjmp(wxinfo.jmpbuf))
@@ -660,12 +664,12 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
         png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
         if (verbose)
            wxLogError(_("Couldn't save PNG image."));
-        return FALSE;
+        return false;
     }
 
     // NB: please see the comment near wxPNGInfoStruct declaration for
     //     explanation why this line is mandatory
-    png_set_write_fn( png_ptr, &wxinfo, _PNG_stream_writer, NULL);
+    png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);
 
     png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
         PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
@@ -685,7 +689,7 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
     if (!data)
     {
         png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
-        return FALSE;
+        return false;
     }
 
     for (int y = 0; y < image->GetHeight(); y++)
@@ -696,7 +700,11 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
             data[(x << 2) + 0] = *ptr++;
             data[(x << 2) + 1] = *ptr++;
             data[(x << 2) + 2] = *ptr++;
-            if (( !image->HasMask() ) || \
+            if ( image->HasAlpha() )
+            {
+                data[(x << 2) + 3] = image->GetAlpha(x, y);
+            }
+            else if (( !image->HasMask() ) || \
                 (data[(x << 2) + 0] != image->GetMaskRed()) || \
                 (data[(x << 2) + 1] != image->GetMaskGreen()) || \
                 (data[(x << 2) + 2] != image->GetMaskBlue()))
@@ -716,7 +724,7 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
     png_write_end( png_ptr, info_ptr );
     png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );
 
-    return TRUE;
+    return true;
 }
 
 #ifdef __VISUALC__