// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "image.h"
#endif
#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
wxImageRefData::~wxImageRefData()
{
- if ( !m_static )
+ if (!m_static)
+ {
free( m_data );
-
- free(m_alpha);
+ free( m_alpha );
+ }
}
wxList wxImage::sm_handlers;
IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
-wxImage::wxImage()
-{
-}
-
wxImage::wxImage( int width, int height, bool clear )
{
Create( width, height, clear );
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 );
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();
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;
}
{
if( xFactor == 1 && yFactor == 1 )
return Copy() ;
-
+
wxImage image;
wxCHECK_MSG( Ok(), image, wxT("invalid image") );
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") );
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 ;
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;
-
+ else
+ {
+ source_alpha = M_IMGDATA->m_alpha ;
+ if ( source_alpha )
+ {
+ image.SetAlpha() ;
+ target_alpha = image.GetAlpha() ;
+ }
+ }
+
for (long y = 0; y < height; y++)
{
for (long x = 0; x < width; x++)
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 )
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++ ;
}
}
}
else
{
- *(target_data++) = avgRed / counter ;
- *(target_data++) = avgGreen / counter ;
- *(target_data++) = avgBlue / counter ;
+ 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);
}
}
}
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;
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;
}
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") );
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") );
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;
}
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
// ----------------------------------------------------------------------------
// 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;
}
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 ;
}
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
int wxImage::GetOptionInt(const wxString& name) const
{
- wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
-
return wxAtoi(GetOption(name));
}
bool wxImageHandler::CallDoCanRead(wxInputStream& stream)
{
- off_t posOld = stream.TellI();
+ wxFileOffset posOld = stream.TellI();
if ( posOld == wxInvalidOffset )
{
// can't test unseekable stream
b2++;
if ( b2 >= 255 )
{
- wxLogError(_("GetUnusedColour:: No Unused Color in image ") );
+ wxLogError(_("No unused colour in image.") );
return false;
}
}
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);
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)
{
//
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).
//
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
{
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
*(dst++) = blank_r;
*(dst++) = blank_g;
*(dst++) = blank_b;
+
+ if (has_alpha)
+ *(alpha_dst++) = 0;
}
}
}
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;
}