]> 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 16d436bbed147112ed78edc6d4f2dcdd58f96deb..cf35689226e15f8141496be70a30af5869036b18 100644 (file)
 #include "wx/utils.h"
 #include "wx/math.h"
 
+#if wxUSE_XPM
+#include "wx/xpmdecod.h"
+#endif
+
 // For memcpy
 #include <string.h>
 
@@ -64,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
@@ -89,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;
@@ -159,6 +168,29 @@ wxImage::wxImage( const wxImage* image )
     if (image) Ref(*image);
 }
 
+wxImage::wxImage( const char** xpmData )
+{
+    Create(xpmData);
+}
+
+wxImage::wxImage( char** xpmData )
+{
+    Create((const char**) xpmData);
+}
+
+bool wxImage::Create( const char** xpmData )
+{
+#if wxUSE_XPM
+    UnRef();
+
+    wxXPMDecoder decoder;
+    (*this) = decoder.ReadData(xpmData);
+    return Ok();
+#else
+    return false;
+#endif
+}
+
 bool wxImage::Create( int width, int height, bool clear )
 {
     UnRef();
@@ -398,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,
@@ -425,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++ )
         {
@@ -466,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;
+            }
         }
     }
 
@@ -576,6 +636,44 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const
     return image;
 }
 
+wxImage wxImage::Size( const wxSize& size, const wxPoint& pos,
+                       int r_, int g_, int b_ ) const
+{
+    wxImage image;
+
+    wxCHECK_MSG( Ok(), image, wxT("invalid image") );
+    wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") );
+
+    int width = GetWidth(), height = GetHeight();
+    image.Create(size.GetWidth(), size.GetHeight(), false);
+
+    unsigned char r = (unsigned char)r_;
+    unsigned char g = (unsigned char)g_;
+    unsigned char b = (unsigned char)b_;
+    if ((r_ == -1) && (g_ == -1) && (b_ == -1))
+    {
+        GetOrFindMaskColour( &r, &g, &b );
+        image.SetMaskColour(r, g, b);
+    }
+
+    image.SetRGB(wxRect(), r, g, b);
+
+    wxRect subRect(pos.x, pos.y, width, height);
+    wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight());
+
+    subRect.Intersect(finalRect);
+
+    if (!subRect.IsEmpty())
+    {
+        if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height))
+            image.Paste(*this, pos.x, pos.y);
+        else
+            image.Paste(GetSubImage(subRect), pos.x, pos.y);
+    }
+
+    return image;
+}
+
 void wxImage::Paste( const wxImage &image, int x, int y )
 {
     wxCHECK_RET( Ok(), wxT("invalid image") );
@@ -606,6 +704,7 @@ void wxImage::Paste( const wxImage &image, int x, int y )
     if (height < 1) return;
 
     if ((!HasMask() && !image.HasMask()) ||
+        (HasMask() && !image.HasMask()) ||
        ((HasMask() && image.HasMask() &&
          (GetMaskRed()==image.GetMaskRed()) &&
          (GetMaskGreen()==image.GetMaskGreen()) &&
@@ -716,60 +815,106 @@ 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") );
+
+    return M_IMGDATA->m_width;
+}
+
+int wxImage::GetHeight() const
+{
+    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+
+    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;
+    }
 
-    int w = M_IMGDATA->m_width;
-    int h = M_IMGDATA->m_height;
+    return -1;
+}
 
-    wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
+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") );
 
-    long pos = (y * w + x) * 3;
+    pos *= 3;
 
     M_IMGDATA->m_data[ pos   ] = r;
     M_IMGDATA->m_data[ pos+1 ] = g;
     M_IMGDATA->m_data[ pos+2 ] = b;
 }
 
-unsigned char wxImage::GetRed( int x, int y ) const
+void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b )
 {
-    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
+    wxCHECK_RET( Ok(), wxT("invalid image") );
+
+    wxRect rect(rect_);
+    wxRect imageRect(0, 0, GetWidth(), GetHeight());
+    if ( rect == wxRect() )
+    {
+        rect = imageRect;
+    }
+    else
+    {
+        wxCHECK_RET( imageRect.Inside(rect.GetTopLeft()) &&
+                     imageRect.Inside(rect.GetBottomRight()),
+                     wxT("invalid bounding rectangle") );
+    }
 
-    int w = M_IMGDATA->m_width;
-    int h = M_IMGDATA->m_height;
+    int x1 = rect.GetLeft(),
+        y1 = rect.GetTop(),
+        x2 = rect.GetRight() + 1,
+        y2 = rect.GetBottom() + 1;
 
-    wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
+    unsigned char *data wxDUMMY_INITIALIZE(NULL);
+    int x, y, width = GetWidth();
+    for (y = y1; y < y2; y++)
+    {
+        data = M_IMGDATA->m_data + (y*width + x1)*3;
+        for (x = x1; x < x2; x++)
+        {
+            *data++ = r;
+            *data++ = g;
+            *data++ = b;
+        }
+    }
+}
+
+unsigned char wxImage::GetRed( int x, int y ) const
+{
+    long pos = XYToIndex(x, y);
+    wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
 
-    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") );
+    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+1];
 }
 
 unsigned char wxImage::GetBlue( 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+2];
 }
@@ -789,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") );
 
@@ -803,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();
 
@@ -831,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();
 
@@ -843,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") );
 
@@ -903,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
@@ -912,6 +1054,42 @@ unsigned char *wxImage::GetAlpha() const
     return M_IMGDATA->m_alpha;
 }
 
+void wxImage::InitAlpha()
+{
+    wxCHECK_RET( !HasAlpha(), wxT("image already has an alpha channel") );
+
+    // initialize memory for alpha channel
+    SetAlpha();
+
+    unsigned char *alpha = M_IMGDATA->m_alpha;
+    const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height;
+
+    if ( HasMask() )
+    {
+        // use the mask to initialize the alpha channel.
+        const unsigned char * const alphaEnd = alpha + lenAlpha;
+
+        const unsigned char mr = M_IMGDATA->m_maskRed;
+        const unsigned char mg = M_IMGDATA->m_maskGreen;
+        const unsigned char mb = M_IMGDATA->m_maskBlue;
+        for ( unsigned char *src = M_IMGDATA->m_data;
+              alpha < alphaEnd;
+              src += 3, alpha++ )
+        {
+            *alpha = (src[0] == mr && src[1] == mg && src[2] == mb)
+                            ? wxIMAGE_ALPHA_TRANSPARENT
+                            : wxIMAGE_ALPHA_OPAQUE;
+        }
+
+        M_IMGDATA->m_hasMask = false;
+    }
+    else // no mask
+    {
+        // make the image fully opaque
+        memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha);
+    }
+}
+
 // ----------------------------------------------------------------------------
 // mask support
 // ----------------------------------------------------------------------------
@@ -926,6 +1104,24 @@ void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
     M_IMGDATA->m_hasMask = true;
 }
 
+bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const
+{
+    wxCHECK_MSG( Ok(), false, wxT("invalid image") );
+
+    if (M_IMGDATA->m_hasMask)
+    {
+        if (r) *r = M_IMGDATA->m_maskRed;
+        if (g) *g = M_IMGDATA->m_maskGreen;
+        if (b) *b = M_IMGDATA->m_maskBlue;
+        return true;
+    }
+    else
+    {
+        FindFirstUnusedColour(r, g, b);
+        return false;
+    }
+}
+
 unsigned char wxImage::GetMaskRed() const
 {
     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
@@ -961,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,
@@ -1060,9 +1273,11 @@ bool wxImage::ConvertAlphaToMask(unsigned char threshold)
     return true;
 }
 
-#if wxUSE_PALETTE
-
+// ----------------------------------------------------------------------------
 // Palette functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
 
 bool wxImage::HasPalette() const
 {
@@ -1088,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") );
@@ -1126,8 +1344,6 @@ wxString wxImage::GetOption(const wxString& name) const
 
 int wxImage::GetOptionInt(const wxString& name) const
 {
-    wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
-
     return wxAtoi(GetOption(name));
 }
 
@@ -1138,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
@@ -1199,6 +1419,8 @@ bool wxImage::SaveFile( const wxString& filename ) const
 bool wxImage::SaveFile( const wxString& filename, int type ) const
 {
 #if wxUSE_STREAMS
+    wxCHECK_MSG( Ok(), false, wxT("invalid image") );
+
     ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
 
     wxFileOutputStream stream(filename);
@@ -1216,6 +1438,8 @@ bool wxImage::SaveFile( const wxString& filename, int type ) const
 bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype ) const
 {
 #if wxUSE_STREAMS
+    wxCHECK_MSG( Ok(), false, wxT("invalid image") );
+
     ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
 
     wxFileOutputStream stream(filename);
@@ -1365,8 +1589,7 @@ bool wxImage::SaveFile( wxOutputStream& stream, int type ) const
     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
 
     wxImageHandler *handler = FindHandler(type);
-
-    if (handler == 0)
+    if ( !handler )
     {
         wxLogWarning( _("No image handler for type %d defined."), type );
 
@@ -1381,8 +1604,7 @@ bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const
     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
 
     wxImageHandler *handler = FindHandlerMime(mimetype);
-
-    if (handler == 0)
+    if ( !handler )
     {
         wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
 
@@ -1393,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.