]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/image.cpp
added debug/release DLL configurations so that VC++ chooses the right one when buildi...
[wxWidgets.git] / src / common / image.cpp
index 73dde3ecafcfa5216e5183acaa8df5a4f9b0adc8..204c4b665740e2ed47e4ea436eff91a85d85fdbb 100644 (file)
 #include "wx/module.h"
 #include "wx/hash.h"
 #include "wx/utils.h"
+#include "wx/math.h"
 
 // For memcpy
 #include <string.h>
-#include <math.h>
 
 #ifdef __SALFORDC__
     #undef FAR
@@ -94,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;
@@ -110,10 +111,6 @@ wxImage wxNullImage;
 
 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
 
-wxImage::wxImage()
-{
-}
-
 wxImage::wxImage( int width, int height, bool clear )
 {
     Create( width, height, clear );
@@ -124,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 );
@@ -197,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();
@@ -259,6 +279,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 ;
@@ -270,8 +295,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++)
     {
@@ -280,6 +312,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 )
@@ -291,11 +324,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++ ;
                     }
                 }
@@ -308,6 +348,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);
@@ -352,15 +394,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;
@@ -371,15 +424,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;
         }
 
@@ -808,6 +865,33 @@ unsigned char wxImage::GetAlpha(int x, int y) const
     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") );
@@ -828,6 +912,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
 // ----------------------------------------------------------------------------
@@ -1042,8 +1164,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));
 }
 
@@ -1485,7 +1605,7 @@ bool wxImageHandler::CanRead( const wxString& name )
 
 bool wxImageHandler::CallDoCanRead(wxInputStream& stream)
 {
-    wxFileSize_t posOld = stream.TellI();
+    wxFileOffset posOld = stream.TellI();
     if ( posOld == wxInvalidOffset )
     {
         // can't test unseekable stream
@@ -1673,14 +1793,24 @@ 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);
@@ -1702,7 +1832,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)
     {
@@ -1715,6 +1849,10 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
     //
     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).
     //
@@ -1800,28 +1938,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
                     {
@@ -1847,6 +2009,19 @@ 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);
+                            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
@@ -1854,6 +2029,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;
                 }
             }
         }
@@ -1876,12 +2054,21 @@ 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);
+                        *(alpha_dst++) = *p;
+                    }
                 }
                 else
                 {
                     *(dst++) = blank_r;
                     *(dst++) = blank_g;
                     *(dst++) = blank_b;
+
+                    if (has_alpha)
+                        *(alpha_dst++) = 255;
                 }
             }
         }
@@ -1889,6 +2076,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
 
     delete [] data;
 
+    if (has_alpha)
+        delete [] alpha;
+
     return rotated;
 }