]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/image.cpp
fixed bug in Set(double jdn): don't test whether the date is valid before setting...
[wxWidgets.git] / src / common / image.cpp
index ba3653b18f5443d7c92937450b9384847a856d6a..bf0c2ee8cfe1b9d46b1a2eccc12f06838fbfe58a 100644 (file)
 #include "wx/module.h"
 #include "wx/hash.h"
 #include "wx/utils.h"
+#include "wx/math.h"
+
+#if wxUSE_XPM
+#include "wx/xpmdecod.h"
+#endif
 
 // For memcpy
 #include <string.h>
-#include <math.h>
 
 #ifdef __SALFORDC__
     #undef FAR
@@ -159,6 +163,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();
@@ -279,6 +306,11 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
     unsigned char maskRed = 0;
     unsigned char maskGreen = 0;
     unsigned char maskBlue =0 ;
+
+    unsigned char *source_data = M_IMGDATA->m_data;
+    unsigned char *target_data = data;
+    unsigned char *source_alpha = 0 ;
+    unsigned char *target_alpha = 0 ;
     if (M_IMGDATA->m_hasMask)
     {
         hasMask = true ;
@@ -290,8 +322,15 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
                              M_IMGDATA->m_maskGreen,
                              M_IMGDATA->m_maskBlue );
     }
-    char unsigned *source_data = M_IMGDATA->m_data;
-    char unsigned *target_data = data;
+    else
+    {
+        source_alpha = M_IMGDATA->m_alpha ;
+        if ( source_alpha )
+        {
+            image.SetAlpha() ;
+            target_alpha = image.GetAlpha() ;
+        }
+    }
 
     for (long y = 0; y < height; y++)
     {
@@ -300,6 +339,7 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
             unsigned long avgRed = 0 ;
             unsigned long avgGreen = 0;
             unsigned long avgBlue = 0;
+            unsigned long avgAlpha = 0 ;
             unsigned long counter = 0 ;
             // determine average
             for ( int y1 = 0 ; y1 < yFactor ; ++y1 )
@@ -311,11 +351,18 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
                     unsigned char red = pixel[0] ;
                     unsigned char green = pixel[1] ;
                     unsigned char blue = pixel[2] ;
+                    unsigned char alpha = 255  ;
+                    if ( source_alpha )
+                        alpha = *(source_alpha + y_offset + x * xFactor + x1) ;
                     if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue )
                     {
-                        avgRed += red ;
-                        avgGreen += green ;
-                        avgBlue += blue ;
+                        if ( alpha > 0 )
+                        {
+                            avgRed += red ;
+                            avgGreen += green ;
+                            avgBlue += blue ;
+                        }
+                        avgAlpha += alpha ;
                         counter++ ;
                     }
                 }
@@ -328,6 +375,8 @@ wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
             }
             else
             {
+                if ( source_alpha )
+                    *(target_alpha++) = (unsigned char)(avgAlpha / counter ) ;
                 *(target_data++) = (unsigned char)(avgRed / counter);
                 *(target_data++) = (unsigned char)(avgGreen / counter);
                 *(target_data++) = (unsigned char)(avgBlue / counter);
@@ -372,15 +421,26 @@ wxImage wxImage::Scale( int width, int height ) const
 
     wxCHECK_MSG( data, image, wxT("unable to create image") );
 
+    unsigned char *source_data = M_IMGDATA->m_data;
+    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,
                              M_IMGDATA->m_maskGreen,
                              M_IMGDATA->m_maskBlue );
     }
-
-    unsigned char *source_data = M_IMGDATA->m_data;
-    unsigned char *target_data = data;
+    else
+    {
+        source_alpha = M_IMGDATA->m_alpha ;
+        if ( source_alpha )
+        {
+            image.SetAlpha() ;
+            target_alpha = image.GetAlpha() ;
+        }
+    }
 
     long x_delta = (old_width<<16) / width;
     long y_delta = (old_height<<16) / height;
@@ -391,15 +451,19 @@ wxImage wxImage::Scale( int width, int height ) const
     for ( long j = 0; j < height; j++ )
         {
         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++ )
         {
              unsigned char* src_pixel = &src_line[(x>>16)*3];
+             unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ;
              dest_pixel[0] = src_pixel[0];
              dest_pixel[1] = src_pixel[1];
              dest_pixel[2] = src_pixel[2];
              dest_pixel += 3;
+             if ( source_alpha )
+                *(target_alpha++) = *src_alpha_pixel ;
              x += x_delta;
         }
 
@@ -539,6 +603,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") );
@@ -569,6 +671,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()) &&
@@ -695,6 +798,42 @@ void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned c
     M_IMGDATA->m_data[ pos+2 ] = b;
 }
 
+void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b )
+{
+    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 x1 = rect.GetLeft(),
+        y1 = rect.GetTop(),
+        x2 = rect.GetRight() + 1,
+        y2 = rect.GetBottom() + 1;
+
+    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
 {
     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
@@ -831,13 +970,13 @@ unsigned char wxImage::GetAlpha(int x, int y) const
 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++)
@@ -875,6 +1014,44 @@ 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;
+
+    static const unsigned char ALPHA_TRANSPARENT = 0;
+    static const unsigned char ALPHA_OPAQUE = 0xff;
+    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)
+                            ? ALPHA_TRANSPARENT
+                            : ALPHA_OPAQUE;
+        }
+
+        M_IMGDATA->m_hasMask = false;
+    }
+    else // no mask
+    {
+        // make the image fully opaque
+        memset(alpha, ALPHA_OPAQUE, lenAlpha);
+    }
+}
+
 // ----------------------------------------------------------------------------
 // mask support
 // ----------------------------------------------------------------------------
@@ -889,6 +1066,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") );
@@ -1089,8 +1284,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));
 }
 
@@ -1162,6 +1355,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);
@@ -1179,6 +1374,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);
@@ -1328,8 +1525,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 );
 
@@ -1344,8 +1540,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() );
 
@@ -1719,7 +1914,7 @@ 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
@@ -1728,7 +1923,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
     for (i = 1; i < GetHeight(); i++)
         data[i] = data[i - 1] + (3 * GetWidth());
 
-    // Same for alpha channel    
+    // Same for alpha channel
     unsigned char ** alpha = NULL;
     if (has_alpha)
     {
@@ -1775,7 +1970,7 @@ 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();
@@ -1866,7 +2061,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
                         *(dst++) = *p;
-                        
+
                         if (has_alpha)
                         {
                             unsigned char *p = alpha[y1] + x1;
@@ -1879,7 +2074,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
                         *(dst++) = *p;
-                        
+
                         if (has_alpha)
                         {
                             unsigned char *p = alpha[y1] + x2;
@@ -1892,7 +2087,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
                         *(dst++) = *p;
-                        
+
                         if (has_alpha)
                         {
                             unsigned char *p = alpha[y2] + x2;
@@ -1905,7 +2100,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                         *(dst++) = *(p++);
                         *(dst++) = *(p++);
                         *(dst++) = *p;
-                        
+
                         if (has_alpha)
                         {
                             unsigned char *p = alpha[y2] + x1;
@@ -1936,7 +2131,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                             ( (w1 * *v1 + w2 * *v2 +
                                w3 * *v3 + w4 * *v4) /
                               (w1 + w2 + w3 + w4) );
-                              
+
                         if (has_alpha)
                         {
                             unsigned char *v1 = alpha[y1] + (x1);
@@ -1956,7 +2151,7 @@ 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;
                 }
@@ -1981,7 +2176,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
                     *(dst++) = *(p++);
                     *(dst++) = *(p++);
                     *(dst++) = *p;
-                    
+
                     if (has_alpha)
                     {
                         unsigned char *p = alpha[ys] + (xs);
@@ -1993,7 +2188,7 @@ 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++) = 255;
                 }
@@ -2002,7 +2197,7 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
     }
 
     delete [] data;
-    
+
     if (has_alpha)
         delete [] alpha;