]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/image.cpp
Hopefully fixed library names generated by wx-config for OS/2's PM port.
[wxWidgets.git] / src / common / image.cpp
index 3f90f3238a6d7e123884dfbea2f8395c519e0b12..cf35689226e15f8141496be70a30af5869036b18 100644 (file)
@@ -68,8 +68,13 @@ public:
     unsigned char  *m_alpha;
 
     bool            m_ok;
+
+    // if true, m_data is pointer to static data and shouldn't be freed
     bool            m_static;
 
+    // same as m_static but for m_alpha
+    bool            m_staticAlpha;
+
 #if wxUSE_PALETTE
     wxPalette       m_palette;
 #endif // wxUSE_PALETTE
@@ -93,16 +98,16 @@ wxImageRefData::wxImageRefData()
     m_hasMask = false;
 
     m_ok = false;
-    m_static = false;
+    m_static =
+    m_staticAlpha = false;
 }
 
 wxImageRefData::~wxImageRefData()
 {
-    if (!m_static)
-    {
+    if ( !m_static )
         free( m_data );
+    if ( !m_staticAlpha )
         free( m_alpha );
-    }
 }
 
 wxList wxImage::sm_handlers;
@@ -177,7 +182,7 @@ bool wxImage::Create( const char** xpmData )
 {
 #if wxUSE_XPM
     UnRef();
-    
+
     wxXPMDecoder decoder;
     (*this) = decoder.ReadData(xpmData);
     return Ok();
@@ -425,7 +430,7 @@ wxImage wxImage::Scale( int width, int height ) const
     unsigned char *target_data = data;
     unsigned char *source_alpha = 0 ;
     unsigned char *target_alpha = 0 ;
-    
+
     if (M_IMGDATA->m_hasMask)
     {
         image.SetMaskColour( M_IMGDATA->m_maskRed,
@@ -452,7 +457,7 @@ wxImage wxImage::Scale( int width, int height ) const
         {
         unsigned char* src_line = &source_data[(y>>16)*old_width*3];
         unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ;
-        
+
         long x = 0;
         for ( long i = 0; i < width; i++ )
         {
@@ -493,25 +498,53 @@ wxImage wxImage::Rotate90( bool clockwise ) const
 
     wxCHECK_MSG( data, image, wxT("unable to create image") );
 
+    unsigned char *source_data = M_IMGDATA->m_data;
+    unsigned char *target_data;
+    unsigned char *alpha_data = 0 ;
+    unsigned char *source_alpha = 0 ;
+    unsigned char *target_alpha = 0 ;
+
     if (M_IMGDATA->m_hasMask)
+    {
         image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
+    }
+    else
+    {
+        source_alpha = M_IMGDATA->m_alpha ;
+        if ( source_alpha )
+        {
+            image.SetAlpha() ;
+            alpha_data = image.GetAlpha() ;
+        }
+    }
 
     long height = M_IMGDATA->m_height;
     long width  = M_IMGDATA->m_width;
 
-    unsigned char *source_data = M_IMGDATA->m_data;
-    unsigned char *target_data;
-
     for (long j = 0; j < height; j++)
     {
         for (long i = 0; i < width; i++)
         {
             if (clockwise)
+            {
                 target_data = data + (((i+1)*height) - j - 1)*3;
+                if(source_alpha)
+                    target_alpha = alpha_data + (((i+1)*height) - j - 1);
+            }
             else
+            {
                 target_data = data + ((height*(width-1)) + j - (i*height))*3;
+                if(source_alpha)
+                    target_alpha = alpha_data + ((height*(width-1)) + j - (i*height));
+            }
             memcpy( target_data, source_data, 3 );
             source_data += 3;
+
+            if(source_alpha)
+            {
+                memcpy( target_alpha, source_alpha, 1 );
+                source_alpha += 1;
+            }
         }
     }
 
@@ -603,7 +636,7 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const
     return image;
 }
 
-wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, 
+wxImage wxImage::Size( const wxSize& size, const wxPoint& pos,
                        int r_, int g_, int b_ ) const
 {
     wxImage image;
@@ -782,16 +815,38 @@ wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char
     return image;
 }
 
-void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
+int wxImage::GetWidth() const
 {
-    wxCHECK_RET( Ok(), wxT("invalid image") );
+    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
 
-    int w = M_IMGDATA->m_width;
-    int h = M_IMGDATA->m_height;
+    return M_IMGDATA->m_width;
+}
 
-    wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
+int wxImage::GetHeight() const
+{
+    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
 
-    long pos = (y * w + x) * 3;
+    return M_IMGDATA->m_height;
+}
+
+long wxImage::XYToIndex(int x, int y) const
+{
+    if ( Ok() &&
+            x >= 0 && y >= 0 &&
+                x < M_IMGDATA->m_width && y < M_IMGDATA->m_height )
+    {
+        return y*M_IMGDATA->m_width + x;
+    }
+
+    return -1;
+}
+
+void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
+{
+    long pos = XYToIndex(x, y);
+    wxCHECK_RET( pos != -1, wxT("invalid image coordinates") );
+
+    pos *= 3;
 
     M_IMGDATA->m_data[ pos   ] = r;
     M_IMGDATA->m_data[ pos+1 ] = g;
@@ -810,8 +865,8 @@ void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, uns
     }
     else
     {
-        wxCHECK_RET( imageRect.Inside(rect.GetTopLeft()) && 
-                     imageRect.Inside(rect.GetBottomRight()), 
+        wxCHECK_RET( imageRect.Inside(rect.GetTopLeft()) &&
+                     imageRect.Inside(rect.GetBottomRight()),
                      wxT("invalid bounding rectangle") );
     }
 
@@ -820,7 +875,7 @@ void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, uns
         x2 = rect.GetRight() + 1,
         y2 = rect.GetBottom() + 1;
 
-    unsigned char *data = NULL;
+    unsigned char *data wxDUMMY_INITIALIZE(NULL);
     int x, y, width = GetWidth();
     for (y = y1; y < y2; y++)
     {
@@ -836,42 +891,30 @@ void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, uns
 
 unsigned char wxImage::GetRed( int x, int y ) const
 {
-    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+    long pos = XYToIndex(x, y);
+    wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
 
-    int w = M_IMGDATA->m_width;
-    int h = M_IMGDATA->m_height;
-
-    wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
-
-    long pos = (y * w + x) * 3;
+    pos *= 3;
 
     return M_IMGDATA->m_data[pos];
 }
 
 unsigned char wxImage::GetGreen( int x, int y ) const
 {
-    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
-
-    int w = M_IMGDATA->m_width;
-    int h = M_IMGDATA->m_height;
+    long pos = XYToIndex(x, y);
+    wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
 
-    wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
-
-    long pos = (y * w + x) * 3;
+    pos *= 3;
 
     return M_IMGDATA->m_data[pos+1];
 }
 
 unsigned char wxImage::GetBlue( int x, int y ) const
 {
-    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
-
-    int w = M_IMGDATA->m_width;
-    int h = M_IMGDATA->m_height;
+    long pos = XYToIndex(x, y);
+    wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
 
-    wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
-
-    long pos = (y * w + x) * 3;
+    pos *= 3;
 
     return M_IMGDATA->m_data[pos+2];
 }
@@ -891,7 +934,7 @@ unsigned char *wxImage::GetData() const
     return M_IMGDATA->m_data;
 }
 
-void wxImage::SetData( unsigned char *data )
+void wxImage::SetData( unsigned char *data, bool static_data  )
 {
     wxCHECK_RET( Ok(), wxT("invalid image") );
 
@@ -905,13 +948,14 @@ void wxImage::SetData( unsigned char *data )
     newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
     newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
     newRefData->m_hasMask = M_IMGDATA->m_hasMask;
+    newRefData->m_static = static_data;
 
     UnRef();
 
     m_refData = newRefData;
 }
 
-void wxImage::SetData( unsigned char *data, int new_width, int new_height )
+void wxImage::SetData( unsigned char *data, int new_width, int new_height, bool static_data )
 {
     wxImageRefData *newRefData = new wxImageRefData();
 
@@ -933,6 +977,7 @@ void wxImage::SetData( unsigned char *data, int new_width, int new_height )
         newRefData->m_data = data;
         newRefData->m_ok = true;
     }
+    newRefData->m_static = static_data;
 
     UnRef();
 
@@ -945,56 +990,50 @@ void wxImage::SetData( unsigned char *data, int new_width, int new_height )
 
 void wxImage::SetAlpha(int x, int y, unsigned char alpha)
 {
-    wxCHECK_RET( Ok() && HasAlpha(), wxT("invalid image or no alpha channel") );
-
-    int w = M_IMGDATA->m_width,
-        h = M_IMGDATA->m_height;
+    wxCHECK_RET( HasAlpha(), wxT("no alpha channel") );
 
-    wxCHECK_RET( x >=0 && y >= 0 && x < w && y < h, wxT("invalid image index") );
+    long pos = XYToIndex(x, y);
+    wxCHECK_RET( pos != -1, wxT("invalid image coordinates") );
 
-    M_IMGDATA->m_alpha[y*w + x] = alpha;
+    M_IMGDATA->m_alpha[pos] = alpha;
 }
 
 unsigned char wxImage::GetAlpha(int x, int y) const
 {
-    wxCHECK_MSG( Ok() && HasAlpha(), 0, wxT("invalid image or no alpha channel") );
+    wxCHECK_MSG( HasAlpha(), 0, wxT("no alpha channel") );
 
-    int w = M_IMGDATA->m_width,
-        h = M_IMGDATA->m_height;
+    long pos = XYToIndex(x, y);
+    wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
 
-    wxCHECK_MSG( x >=0 && y >= 0 && x < w && y < h, 0, wxT("invalid image index") );
-
-    return M_IMGDATA->m_alpha[y*w + x];
+    return M_IMGDATA->m_alpha[pos];
 }
 
-bool wxImage::ConvertColourToAlpha( unsigned char r, unsigned char g, unsigned char b )
+bool
+wxImage::ConvertColourToAlpha(unsigned char r, unsigned char g, unsigned char b)
 {
-    SetAlpha( NULL );
+    SetAlpha(NULL);
 
-    int w = M_IMGDATA->m_width,
-        h = M_IMGDATA->m_height;
+    const int w = M_IMGDATA->m_width;
+    const int 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++;
-            }
+    for ( int y = 0; y < h; y++ )
+    {
+        for ( int x = 0; x < w; x++ )
+        {
+            *alpha++ = *data;
+            *data++ = r;
+            *data++ = g;
+            *data++ = b;
+        }
+    }
 
     return true;
 }
 
-void wxImage::SetAlpha( unsigned char *alpha )
+void wxImage::SetAlpha( unsigned char *alpha, bool static_data )
 {
     wxCHECK_RET( Ok(), wxT("invalid image") );
 
@@ -1005,6 +1044,7 @@ void wxImage::SetAlpha( unsigned char *alpha )
 
     free(M_IMGDATA->m_alpha);
     M_IMGDATA->m_alpha = alpha;
+    M_IMGDATA->m_staticAlpha = static_data;
 }
 
 unsigned char *wxImage::GetAlpha() const
@@ -1024,8 +1064,6 @@ void wxImage::InitAlpha()
     unsigned char *alpha = M_IMGDATA->m_alpha;
     const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height;
 
-    static const unsigned char ALPHA_TRANSPARENT = 0;
-    static const unsigned char ALPHA_OPAQUE = 0xff;
     if ( HasMask() )
     {
         // use the mask to initialize the alpha channel.
@@ -1039,8 +1077,8 @@ void wxImage::InitAlpha()
               src += 3, alpha++ )
         {
             *alpha = (src[0] == mr && src[1] == mg && src[2] == mb)
-                            ? ALPHA_TRANSPARENT
-                            : ALPHA_OPAQUE;
+                            ? wxIMAGE_ALPHA_TRANSPARENT
+                            : wxIMAGE_ALPHA_OPAQUE;
         }
 
         M_IMGDATA->m_hasMask = false;
@@ -1048,7 +1086,7 @@ void wxImage::InitAlpha()
     else // no mask
     {
         // make the image fully opaque
-        memset(alpha, ALPHA_OPAQUE, lenAlpha);
+        memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha);
     }
 }
 
@@ -1119,18 +1157,35 @@ bool wxImage::HasMask() const
     return M_IMGDATA->m_hasMask;
 }
 
-int wxImage::GetWidth() const
+bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const
 {
-    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+    long pos = XYToIndex(x, y);
+    wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") );
 
-    return M_IMGDATA->m_width;
-}
+    // check mask
+    if ( M_IMGDATA->m_hasMask )
+    {
+        const unsigned char *p = M_IMGDATA->m_data + 3*pos;
+        if ( p[0] == M_IMGDATA->m_maskRed &&
+                p[1] == M_IMGDATA->m_maskGreen &&
+                    p[2] == M_IMGDATA->m_maskBlue )
+        {
+            return true;
+        }
+    }
 
-int wxImage::GetHeight() const
-{
-    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+    // then check alpha
+    if ( M_IMGDATA->m_alpha )
+    {
+        if ( M_IMGDATA->m_alpha[pos] < threshold )
+        {
+            // transparent enough
+            return true;
+        }
+    }
 
-    return M_IMGDATA->m_height;
+    // not transparent
+    return false;
 }
 
 bool wxImage::SetMaskFromImage(const wxImage& mask,
@@ -1218,9 +1273,11 @@ bool wxImage::ConvertAlphaToMask(unsigned char threshold)
     return true;
 }
 
-#if wxUSE_PALETTE
-
+// ----------------------------------------------------------------------------
 // Palette functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
 
 bool wxImage::HasPalette() const
 {
@@ -1246,7 +1303,10 @@ void wxImage::SetPalette(const wxPalette& palette)
 
 #endif // wxUSE_PALETTE
 
+// ----------------------------------------------------------------------------
 // Option functions (arbitrary name/value mapping)
+// ----------------------------------------------------------------------------
+
 void wxImage::SetOption(const wxString& name, const wxString& value)
 {
     wxCHECK_RET( Ok(), wxT("invalid image") );
@@ -1294,6 +1354,10 @@ bool wxImage::HasOption(const wxString& name) const
     return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND);
 }
 
+// ----------------------------------------------------------------------------
+// image I/O
+// ----------------------------------------------------------------------------
+
 bool wxImage::LoadFile( const wxString& filename, long type, int index )
 {
 #if wxUSE_STREAMS
@@ -1551,6 +1615,10 @@ bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const
 }
 #endif // wxUSE_STREAMS
 
+// ----------------------------------------------------------------------------
+// image I/O handlers
+// ----------------------------------------------------------------------------
+
 void wxImage::AddHandler( wxImageHandler *handler )
 {
     // Check for an existing handler of the type being added.