]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/image.cpp
Backed-out PNG8 patch (no time to look at why
[wxWidgets.git] / src / common / image.cpp
index 179dae70ec0d2ec82f8a4dff5e533c5b6af89022..ba3653b18f5443d7c92937450b9384847a856d6a 100644 (file)
@@ -7,7 +7,7 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 #pragma implementation "image.h"
 #endif
 
@@ -32,6 +32,7 @@
 #include "wx/intl.h"
 #include "wx/module.h"
 #include "wx/hash.h"
+#include "wx/utils.h"
 
 // For memcpy
 #include <string.h>
@@ -93,10 +94,11 @@ wxImageRefData::wxImageRefData()
 
 wxImageRefData::~wxImageRefData()
 {
-    if ( !m_static )
+    if (!m_static)
+    {
         free( m_data );
-
-    free(m_alpha);
+        free( m_alpha );
+    }
 }
 
 wxList wxImage::sm_handlers;
@@ -109,10 +111,6 @@ wxImage wxNullImage;
 
 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
 
-wxImage::wxImage()
-{
-}
-
 wxImage::wxImage( int width, int height, bool clear )
 {
     Create( width, height, clear );
@@ -123,6 +121,11 @@ wxImage::wxImage( int width, int height, unsigned char* data, bool static_data )
     Create( width, height, data, static_data );
 }
 
+wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data )
+{
+    Create( width, height, data, alpha, static_data );
+}
+
 wxImage::wxImage( const wxString& name, long type, int index )
 {
     LoadFile( name, type, index );
@@ -196,6 +199,24 @@ bool wxImage::Create( int width, int height, unsigned char* data, bool static_da
     return true;
 }
 
+bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data )
+{
+    UnRef();
+
+    wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") );
+
+    m_refData = new wxImageRefData();
+
+    M_IMGDATA->m_data = data;
+    M_IMGDATA->m_alpha = alpha;
+    M_IMGDATA->m_width = width;
+    M_IMGDATA->m_height = height;
+    M_IMGDATA->m_ok = true;
+    M_IMGDATA->m_static = static_data;
+
+    return true;
+}
+
 void wxImage::Destroy()
 {
     UnRef();
@@ -218,6 +239,11 @@ wxImage wxImage::Copy() const
 
     memcpy( data, GetData(), M_IMGDATA->m_width*M_IMGDATA->m_height*3 );
 
+    // also copy the image options
+    wxImageRefData *imgData = (wxImageRefData *)image.m_refData;
+    imgData->m_optionNames = M_IMGDATA->m_optionNames;
+    imgData->m_optionValues = M_IMGDATA->m_optionValues;
+
     return image;
 }
 
@@ -225,7 +251,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
 {
     if( xFactor == 1 && yFactor == 1 )
         return Copy() ;
-        
+
     wxImage image;
 
     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
@@ -236,7 +262,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
 
     long old_height = M_IMGDATA->m_height,
          old_width  = M_IMGDATA->m_width;
-         
+
     wxCHECK_MSG( (old_height > 0) && (old_width > 0), image,
                  wxT("invalid old image size") );
 
@@ -259,14 +285,14 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
         maskRed = M_IMGDATA->m_maskRed;
         maskGreen = M_IMGDATA->m_maskGreen;
         maskBlue =M_IMGDATA->m_maskBlue ;
-      
+
         image.SetMaskColour( M_IMGDATA->m_maskRed,
                              M_IMGDATA->m_maskGreen,
                              M_IMGDATA->m_maskBlue );
     }
     char unsigned *source_data = M_IMGDATA->m_data;
     char unsigned *target_data = data;
-    
+
     for (long y = 0; y < height; y++)
     {
         for (long x = 0; x < width; x++)
@@ -302,9 +328,9 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
             }
             else
             {
-                *(target_data++) = avgRed / counter ;
-                *(target_data++) = avgGreen / counter ;
-                *(target_data++) = avgBlue / counter ;
+                *(target_data++) = (unsigned char)(avgRed / counter);
+                *(target_data++) = (unsigned char)(avgGreen / counter);
+                *(target_data++) = (unsigned char)(avgBlue / counter);
             }
         }
     }
@@ -790,7 +816,7 @@ void wxImage::SetAlpha(int x, int y, unsigned char alpha)
     M_IMGDATA->m_alpha[y*w + x] = alpha;
 }
 
-unsigned char wxImage::GetAlpha(int x, int y)
+unsigned char wxImage::GetAlpha(int x, int y) const
 {
     wxCHECK_MSG( Ok() && HasAlpha(), 0, wxT("invalid image or no alpha channel") );
 
@@ -802,6 +828,33 @@ unsigned char wxImage::GetAlpha(int x, int y)
     return M_IMGDATA->m_alpha[y*w + x];
 }
 
+bool wxImage::ConvertColourToAlpha( unsigned char r, unsigned char g, unsigned char b )
+{
+    SetAlpha( NULL );
+    
+    int w = M_IMGDATA->m_width,
+        h = M_IMGDATA->m_height;
+    
+    unsigned char *alpha = GetAlpha();
+    unsigned char *data = GetData();
+    
+    int x,y;
+    for (y = 0; y < h; y++)
+        for (x = 0; x < w; x++)
+            {
+                *alpha = *data;
+                alpha++;
+                *data = r;
+                data++;
+                *data = g;
+                data++;
+                *data = b;
+                data++;
+            }
+
+    return true;
+}
+
 void wxImage::SetAlpha( unsigned char *alpha )
 {
     wxCHECK_RET( Ok(), wxT("invalid image") );
@@ -811,7 +864,7 @@ void wxImage::SetAlpha( unsigned char *alpha )
         alpha = (unsigned char *)malloc(M_IMGDATA->m_width*M_IMGDATA->m_height);
     }
 
-    delete [] M_IMGDATA->m_alpha;
+    free(M_IMGDATA->m_alpha);
     M_IMGDATA->m_alpha = alpha;
 }
 
@@ -891,7 +944,7 @@ bool wxImage::SetMaskFromImage(const wxImage& mask,
     // check that the images are the same size
     if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) )
     {
-        wxLogError( _("Image and Mask have different sizes") );
+        wxLogError( _("Image and mask have different sizes.") );
         return false;
     }
 
@@ -899,7 +952,7 @@ bool wxImage::SetMaskFromImage(const wxImage& mask,
     unsigned char r,g,b ;
     if (!FindFirstUnusedColour(&r, &g, &b))
     {
-        wxLogError( _("No Unused Color in image being masked") );
+        wxLogError( _("No unused colour in image being masked.") );
         return false ;
     }
 
@@ -930,6 +983,46 @@ bool wxImage::SetMaskFromImage(const wxImage& mask,
     return true;
 }
 
+bool wxImage::ConvertAlphaToMask(unsigned char threshold)
+{
+    if (!HasAlpha())
+        return true;
+
+    unsigned char mr, mg, mb;
+    if (!FindFirstUnusedColour(&mr, &mg, &mb))
+    {
+        wxLogError( _("No unused colour in image being masked.") );
+        return false;
+    }
+
+    SetMask(true);
+    SetMaskColour(mr, mg, mb);
+
+    unsigned char *imgdata = GetData();
+    unsigned char *alphadata = GetAlpha();
+
+    int w = GetWidth();
+    int h = GetHeight();
+
+    for (int y = 0; y < h; y++)
+    {
+        for (int x = 0; x < w; x++, imgdata += 3, alphadata++)
+        {
+            if (*alphadata < threshold)
+            {
+                imgdata[0] = mr;
+                imgdata[1] = mg;
+                imgdata[2] = mb;
+            }
+        }
+    }
+
+    free(M_IMGDATA->m_alpha);
+    M_IMGDATA->m_alpha = NULL;
+
+    return true;
+}
+
 #if wxUSE_PALETTE
 
 // Palette functions
@@ -1127,7 +1220,7 @@ bool wxImage::CanRead( wxInputStream &stream )
 {
     const wxList& list = GetHandlers();
 
-    for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
+    for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() )
     {
         wxImageHandler *handler=(wxImageHandler*)node->GetData();
         if (handler->CanRead( stream ))
@@ -1145,7 +1238,7 @@ int wxImage::GetImageCount( wxInputStream &stream, long type )
     {
         wxList &list=GetHandlers();
 
-        for (wxList::Node *node = list.GetFirst(); node; node = node->GetNext())
+        for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
         {
              handler=(wxImageHandler*)node->GetData();
              if ( handler->CanRead(stream) )
@@ -1188,7 +1281,7 @@ bool wxImage::LoadFile( wxInputStream& stream, long type, int index )
     {
         wxList &list=GetHandlers();
 
-        for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
+        for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() )
         {
              handler=(wxImageHandler*)node->GetData();
              if ( handler->CanRead(stream) )
@@ -1265,9 +1358,6 @@ bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const
 
 void wxImage::AddHandler( wxImageHandler *handler )
 {
-    // make sure that the memory will be freed at the program end
-    sm_handlers.DeleteContents(true);
-
     // Check for an existing handler of the type being added.
     if (FindHandler( handler->GetType() ) == 0)
     {
@@ -1289,9 +1379,6 @@ void wxImage::AddHandler( wxImageHandler *handler )
 
 void wxImage::InsertHandler( wxImageHandler *handler )
 {
-    // make sure that the memory will be freed at the program end
-    sm_handlers.DeleteContents(true);
-
     // Check for an existing handler of the type being added.
     if (FindHandler( handler->GetType() ) == 0)
     {
@@ -1312,6 +1399,7 @@ bool wxImage::RemoveHandler( const wxString& name )
     if (handler)
     {
         sm_handlers.DeleteObject(handler);
+        delete handler;
         return true;
     }
     else
@@ -1320,7 +1408,7 @@ bool wxImage::RemoveHandler( const wxString& name )
 
 wxImageHandler *wxImage::FindHandler( const wxString& name )
 {
-    wxNode *node = sm_handlers.GetFirst();
+    wxList::compatibility_iterator node = sm_handlers.GetFirst();
     while (node)
     {
         wxImageHandler *handler = (wxImageHandler*)node->GetData();
@@ -1333,7 +1421,7 @@ wxImageHandler *wxImage::FindHandler( const wxString& name )
 
 wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
 {
-    wxNode *node = sm_handlers.GetFirst();
+    wxList::compatibility_iterator node = sm_handlers.GetFirst();
     while (node)
     {
         wxImageHandler *handler = (wxImageHandler*)node->GetData();
@@ -1347,7 +1435,7 @@ wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType
 
 wxImageHandler *wxImage::FindHandler( long bitmapType )
 {
-    wxNode *node = sm_handlers.GetFirst();
+    wxList::compatibility_iterator node = sm_handlers.GetFirst();
     while (node)
     {
         wxImageHandler *handler = (wxImageHandler *)node->GetData();
@@ -1359,7 +1447,7 @@ wxImageHandler *wxImage::FindHandler( long bitmapType )
 
 wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
 {
-    wxNode *node = sm_handlers.GetFirst();
+    wxList::compatibility_iterator node = sm_handlers.GetFirst();
     while (node)
     {
         wxImageHandler *handler = (wxImageHandler *)node->GetData();
@@ -1378,24 +1466,24 @@ void wxImage::InitStandardHandlers()
 
 void wxImage::CleanUpHandlers()
 {
-    wxNode *node = sm_handlers.GetFirst();
+    wxList::compatibility_iterator node = sm_handlers.GetFirst();
     while (node)
     {
         wxImageHandler *handler = (wxImageHandler *)node->GetData();
-        wxNode *next = node->GetNext();
+        wxList::compatibility_iterator next = node->GetNext();
         delete handler;
-        delete node;
         node = next;
     }
-}
 
+    sm_handlers.Clear();
+}
 
 wxString wxImage::GetImageExtWildcard()
 {
     wxString fmts;
 
     wxList& Handlers = wxImage::GetHandlers();
-    wxNode* Node = Handlers.GetFirst();
+    wxList::compatibility_iterator Node = Handlers.GetFirst();
     while ( Node )
     {
         wxImageHandler* Handler = (wxImageHandler*)Node->GetData();
@@ -1407,7 +1495,6 @@ wxString wxImage::GetImageExtWildcard()
     return wxT("(") + fmts + wxT(")|") + fmts;
 }
 
-
 //-----------------------------------------------------------------------------
 // wxImageHandler
 //-----------------------------------------------------------------------------
@@ -1445,7 +1532,7 @@ bool wxImageHandler::CanRead( const wxString& name )
 
 bool wxImageHandler::CallDoCanRead(wxInputStream& stream)
 {
-    off_t posOld = stream.TellI();
+    wxFileOffset posOld = stream.TellI();
     if ( posOld == wxInvalidOffset )
     {
         // can't test unseekable stream
@@ -1496,7 +1583,7 @@ wxImageHistogram::FindFirstUnusedColour(unsigned char *r,
                 b2++;
                 if ( b2 >= 255 )
                 {
-                    wxLogError(_("GetUnusedColour:: No Unused Color in image ") );
+                    wxLogError(_("No unused colour in image.") );
                     return false;
                 }
             }
@@ -1632,15 +1719,25 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
 {
     int i;
     angle = -angle;     // screen coordinates are a mirror image of "real" coordinates
+    
+    bool has_alpha = HasAlpha();
 
     // Create pointer-based array to accelerate access to wxImage's data
     unsigned char ** data = new unsigned char * [GetHeight()];
-
     data[0] = GetData();
-
     for (i = 1; i < GetHeight(); i++)
         data[i] = data[i - 1] + (3 * GetWidth());
 
+    // Same for alpha channel    
+    unsigned char ** alpha = NULL;
+    if (has_alpha)
+    {
+        alpha = new unsigned char * [GetHeight()];
+        alpha[0] = GetAlpha();
+        for (i = 1; i < GetHeight(); i++)
+            alpha[i] = alpha[i - 1] + GetWidth();
+    }
+
     // precompute coefficients for rotation formula
     // (sine and cosine of the angle)
     const double cos_angle = cos(angle);
@@ -1662,7 +1759,11 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
     int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
     int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
 
+    // Create rotated image
     wxImage rotated (x2 - x1 + 1, y2 - y1 + 1, false);
+    // With alpha channel
+    if (has_alpha)
+        rotated.SetAlpha();
 
     if (offset_after_rotation != NULL)
     {
@@ -1674,6 +1775,10 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
     //      array here (and in fact it would be slower).
     //
     unsigned char * dst = rotated.GetData();
+    
+    unsigned char * alpha_dst = NULL;
+    if (has_alpha)
+        alpha_dst = rotated.GetAlpha();
 
     // GRG: if the original image has a mask, use its RGB values
     //      as the blank pixel, else, fall back to default (black).
@@ -1760,28 +1865,52 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                         unsigned char *p = data[y1] + (3 * x1);
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
-                        *(dst++) = *(p++);
+                        *(dst++) = *p;
+                        
+                        if (has_alpha)
+                        {
+                            unsigned char *p = alpha[y1] + x1;
+                            *(alpha_dst++) = *p;
+                        }
                     }
                     else if (d2 < gs_Epsilon)
                     {
                         unsigned char *p = data[y1] + (3 * x2);
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
-                        *(dst++) = *(p++);
+                        *(dst++) = *p;
+                        
+                        if (has_alpha)
+                        {
+                            unsigned char *p = alpha[y1] + x2;
+                            *(alpha_dst++) = *p;
+                        }
                     }
                     else if (d3 < gs_Epsilon)
                     {
                         unsigned char *p = data[y2] + (3 * x2);
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
-                        *(dst++) = *(p++);
+                        *(dst++) = *p;
+                        
+                        if (has_alpha)
+                        {
+                            unsigned char *p = alpha[y2] + x2;
+                            *(alpha_dst++) = *p;
+                        }
                     }
                     else if (d4 < gs_Epsilon)
                     {
                         unsigned char *p = data[y2] + (3 * x1);
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
-                        *(dst++) = *(p++);
+                        *(dst++) = *p;
+                        
+                        if (has_alpha)
+                        {
+                            unsigned char *p = alpha[y2] + x1;
+                            *(alpha_dst++) = *p;
+                        }
                     }
                     else
                     {
@@ -1804,9 +1933,22 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                                w3 * *(v3++) + w4 * *(v4++)) /
                               (w1 + w2 + w3 + w4) );
                         *(dst++) = (unsigned char)
-                            ( (w1 * *(v1++) + w2 * *(v2++) +
-                               w3 * *(v3++) + w4 * *(v4++)) /
+                            ( (w1 * *v1 + w2 * *v2 +
+                               w3 * *v3 + w4 * *v4) /
                               (w1 + w2 + w3 + w4) );
+                              
+                        if (has_alpha)
+                        {
+                            unsigned char *v1 = alpha[y1] + (x1);
+                            unsigned char *v2 = alpha[y1] + (x2);
+                            unsigned char *v3 = alpha[y2] + (x2);
+                            unsigned char *v4 = alpha[y2] + (x1);
+
+                            *(alpha_dst++) = (unsigned char)
+                                ( (w1 * *v1 + w2 * *v2 +
+                                   w3 * *v3 + w4 * *v4) /
+                                  (w1 + w2 + w3 + w4) );
+                        }
                     }
                 }
                 else
@@ -1814,6 +1956,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                     *(dst++) = blank_r;
                     *(dst++) = blank_g;
                     *(dst++) = blank_b;
+                   
+                    if (has_alpha)
+                        *(alpha_dst++) = 0;
                 }
             }
         }
@@ -1835,19 +1980,31 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                     unsigned char *p = data[ys] + (3 * xs);
                     *(dst++) = *(p++);
                     *(dst++) = *(p++);
-                    *(dst++) = *(p++);
+                    *(dst++) = *p;
+                    
+                    if (has_alpha)
+                    {
+                        unsigned char *p = alpha[ys] + (xs);
+                        *(alpha_dst++) = *p;
+                    }
                 }
                 else
                 {
                     *(dst++) = blank_r;
                     *(dst++) = blank_g;
                     *(dst++) = blank_b;
+                    
+                    if (has_alpha)
+                        *(alpha_dst++) = 255;
                 }
             }
         }
     }
 
     delete [] data;
+    
+    if (has_alpha)
+        delete [] alpha;
 
     return rotated;
 }