/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/image.cpp
ViewVC logotype

Annotation of /trunk/3rdparty/wxWidgets/src/common/image.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 10 months ago) by william
File size: 91528 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 31 /////////////////////////////////////////////////////////////////////////////
2     // Name: src/common/image.cpp
3     // Purpose: wxImage
4     // Author: Robert Roebling
5     // RCS-ID: $Id: image.cpp 59197 2009-02-28 15:44:53Z VZ $
6     // Copyright: (c) Robert Roebling
7     // Licence: wxWindows licence
8     /////////////////////////////////////////////////////////////////////////////
9    
10     // For compilers that support precompilation, includes "wx.h".
11     #include "wx/wxprec.h"
12    
13     #ifdef __BORLANDC__
14     #pragma hdrstop
15     #endif
16    
17     #if wxUSE_IMAGE
18    
19     #include "wx/image.h"
20    
21     #ifndef WX_PRECOMP
22     #include "wx/log.h"
23     #include "wx/hash.h"
24     #include "wx/utils.h"
25     #include "wx/math.h"
26     #include "wx/module.h"
27     #include "wx/palette.h"
28     #include "wx/intl.h"
29     #endif
30    
31     #include "wx/filefn.h"
32     #include "wx/wfstream.h"
33     #include "wx/xpmdecod.h"
34    
35     // For memcpy
36     #include <string.h>
37    
38     // make the code compile with either wxFile*Stream or wxFFile*Stream:
39     #define HAS_FILE_STREAMS (wxUSE_STREAMS && (wxUSE_FILE || wxUSE_FFILE))
40    
41     #if HAS_FILE_STREAMS
42     #if wxUSE_FFILE
43     typedef wxFFileInputStream wxImageFileInputStream;
44     typedef wxFFileOutputStream wxImageFileOutputStream;
45     #elif wxUSE_FILE
46     typedef wxFileInputStream wxImageFileInputStream;
47     typedef wxFileOutputStream wxImageFileOutputStream;
48     #endif // wxUSE_FILE/wxUSE_FFILE
49     #endif // HAS_FILE_STREAMS
50    
51     #if wxUSE_VARIANT
52     IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxImage,WXDLLEXPORT)
53     #endif
54    
55     //-----------------------------------------------------------------------------
56     // wxImage
57     //-----------------------------------------------------------------------------
58    
59     class wxImageRefData: public wxObjectRefData
60     {
61     public:
62     wxImageRefData();
63     virtual ~wxImageRefData();
64    
65     int m_width;
66     int m_height;
67     unsigned char *m_data;
68    
69     bool m_hasMask;
70     unsigned char m_maskRed,m_maskGreen,m_maskBlue;
71    
72     // alpha channel data, may be NULL for the formats without alpha support
73     unsigned char *m_alpha;
74    
75     bool m_ok;
76    
77     // if true, m_data is pointer to static data and shouldn't be freed
78     bool m_static;
79    
80     // same as m_static but for m_alpha
81     bool m_staticAlpha;
82    
83     #if wxUSE_PALETTE
84     wxPalette m_palette;
85     #endif // wxUSE_PALETTE
86    
87     wxArrayString m_optionNames;
88     wxArrayString m_optionValues;
89    
90     DECLARE_NO_COPY_CLASS(wxImageRefData)
91     };
92    
93     wxImageRefData::wxImageRefData()
94     {
95     m_width = 0;
96     m_height = 0;
97     m_data =
98     m_alpha = (unsigned char *) NULL;
99    
100     m_maskRed = 0;
101     m_maskGreen = 0;
102     m_maskBlue = 0;
103     m_hasMask = false;
104    
105     m_ok = false;
106     m_static =
107     m_staticAlpha = false;
108     }
109    
110     wxImageRefData::~wxImageRefData()
111     {
112     if ( !m_static )
113     free( m_data );
114     if ( !m_staticAlpha )
115     free( m_alpha );
116     }
117    
118     wxList wxImage::sm_handlers;
119    
120     wxImage wxNullImage;
121    
122     //-----------------------------------------------------------------------------
123    
124     #define M_IMGDATA wx_static_cast(wxImageRefData*, m_refData)
125    
126     IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
127    
128     wxImage::wxImage( int width, int height, bool clear )
129     {
130     Create( width, height, clear );
131     }
132    
133     wxImage::wxImage( int width, int height, unsigned char* data, bool static_data )
134     {
135     Create( width, height, data, static_data );
136     }
137    
138     wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data )
139     {
140     Create( width, height, data, alpha, static_data );
141     }
142    
143     wxImage::wxImage( const wxString& name, long type, int index )
144     {
145     LoadFile( name, type, index );
146     }
147    
148     wxImage::wxImage( const wxString& name, const wxString& mimetype, int index )
149     {
150     LoadFile( name, mimetype, index );
151     }
152    
153     #if wxUSE_STREAMS
154     wxImage::wxImage( wxInputStream& stream, long type, int index )
155     {
156     LoadFile( stream, type, index );
157     }
158    
159     wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index )
160     {
161     LoadFile( stream, mimetype, index );
162     }
163     #endif // wxUSE_STREAMS
164    
165     wxImage::wxImage(const char* const* xpmData)
166     {
167     Create(xpmData);
168     }
169    
170 william 62 #if wxUSE_XPM
171 william 31 bool wxImage::Create(const char* const* xpmData)
172     {
173     UnRef();
174    
175     wxXPMDecoder decoder;
176     (*this) = decoder.ReadData(xpmData);
177     return Ok();
178 william 62 }
179 william 31 #else
180 william 62 bool wxImage::Create( const char* const* WXUNUSED(xpmData) )
181     {
182 william 31 return false;
183 william 62 }
184 william 31 #endif
185    
186     bool wxImage::Create( int width, int height, bool clear )
187     {
188     UnRef();
189    
190     m_refData = new wxImageRefData();
191    
192     M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
193     if (!M_IMGDATA->m_data)
194     {
195     UnRef();
196     return false;
197     }
198    
199     if (clear)
200     memset(M_IMGDATA->m_data, 0, width*height*3);
201    
202     M_IMGDATA->m_width = width;
203     M_IMGDATA->m_height = height;
204     M_IMGDATA->m_ok = true;
205    
206     return true;
207     }
208    
209     bool wxImage::Create( int width, int height, unsigned char* data, bool static_data )
210     {
211     UnRef();
212    
213     wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") );
214    
215     m_refData = new wxImageRefData();
216    
217     M_IMGDATA->m_data = data;
218     M_IMGDATA->m_width = width;
219     M_IMGDATA->m_height = height;
220     M_IMGDATA->m_ok = true;
221     M_IMGDATA->m_static = static_data;
222    
223     return true;
224     }
225    
226     bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data )
227     {
228     UnRef();
229    
230     wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") );
231    
232     m_refData = new wxImageRefData();
233    
234     M_IMGDATA->m_data = data;
235     M_IMGDATA->m_alpha = alpha;
236     M_IMGDATA->m_width = width;
237     M_IMGDATA->m_height = height;
238     M_IMGDATA->m_ok = true;
239     M_IMGDATA->m_static = static_data;
240     M_IMGDATA->m_staticAlpha = static_data;
241    
242     return true;
243     }
244    
245     void wxImage::Destroy()
246     {
247     UnRef();
248     }
249    
250     wxObjectRefData* wxImage::CreateRefData() const
251     {
252     return new wxImageRefData;
253     }
254    
255     wxObjectRefData* wxImage::CloneRefData(const wxObjectRefData* that) const
256     {
257     const wxImageRefData* refData = wx_static_cast(const wxImageRefData*, that);
258     wxCHECK_MSG(refData->m_ok, NULL, wxT("invalid image") );
259    
260     wxImageRefData* refData_new = new wxImageRefData;
261     refData_new->m_width = refData->m_width;
262     refData_new->m_height = refData->m_height;
263     refData_new->m_maskRed = refData->m_maskRed;
264     refData_new->m_maskGreen = refData->m_maskGreen;
265     refData_new->m_maskBlue = refData->m_maskBlue;
266     refData_new->m_hasMask = refData->m_hasMask;
267     refData_new->m_ok = true;
268     unsigned size = unsigned(refData->m_width) * unsigned(refData->m_height);
269     if (refData->m_alpha != NULL)
270     {
271     refData_new->m_alpha = (unsigned char*)malloc(size);
272     memcpy(refData_new->m_alpha, refData->m_alpha, size);
273     }
274     size *= 3;
275     refData_new->m_data = (unsigned char*)malloc(size);
276     memcpy(refData_new->m_data, refData->m_data, size);
277     #if wxUSE_PALETTE
278     refData_new->m_palette = refData->m_palette;
279     #endif
280     refData_new->m_optionNames = refData->m_optionNames;
281     refData_new->m_optionValues = refData->m_optionValues;
282     return refData_new;
283     }
284    
285     wxImage wxImage::Copy() const
286     {
287     wxImage image;
288    
289     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
290    
291     image.m_refData = CloneRefData(m_refData);
292    
293     return image;
294     }
295    
296     wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
297     {
298     if( xFactor == 1 && yFactor == 1 )
299     return *this;
300    
301     wxImage image;
302    
303     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
304    
305     // can't scale to/from 0 size
306     wxCHECK_MSG( (xFactor > 0) && (yFactor > 0), image,
307     wxT("invalid new image size") );
308    
309     long old_height = M_IMGDATA->m_height,
310     old_width = M_IMGDATA->m_width;
311    
312     wxCHECK_MSG( (old_height > 0) && (old_width > 0), image,
313     wxT("invalid old image size") );
314    
315     long width = old_width / xFactor ;
316     long height = old_height / yFactor ;
317    
318     image.Create( width, height, false );
319    
320     char unsigned *data = image.GetData();
321    
322     wxCHECK_MSG( data, image, wxT("unable to create image") );
323    
324     bool hasMask = false ;
325     unsigned char maskRed = 0;
326     unsigned char maskGreen = 0;
327     unsigned char maskBlue =0 ;
328    
329     unsigned char *source_data = M_IMGDATA->m_data;
330     unsigned char *target_data = data;
331     unsigned char *source_alpha = 0 ;
332     unsigned char *target_alpha = 0 ;
333     if (M_IMGDATA->m_hasMask)
334     {
335     hasMask = true ;
336     maskRed = M_IMGDATA->m_maskRed;
337     maskGreen = M_IMGDATA->m_maskGreen;
338     maskBlue =M_IMGDATA->m_maskBlue ;
339    
340     image.SetMaskColour( M_IMGDATA->m_maskRed,
341     M_IMGDATA->m_maskGreen,
342     M_IMGDATA->m_maskBlue );
343     }
344     else
345     {
346     source_alpha = M_IMGDATA->m_alpha ;
347     if ( source_alpha )
348     {
349     image.SetAlpha() ;
350     target_alpha = image.GetAlpha() ;
351     }
352     }
353    
354     for (long y = 0; y < height; y++)
355     {
356     for (long x = 0; x < width; x++)
357     {
358     unsigned long avgRed = 0 ;
359     unsigned long avgGreen = 0;
360     unsigned long avgBlue = 0;
361     unsigned long avgAlpha = 0 ;
362     unsigned long counter = 0 ;
363     // determine average
364     for ( int y1 = 0 ; y1 < yFactor ; ++y1 )
365     {
366     long y_offset = (y * yFactor + y1) * old_width;
367     for ( int x1 = 0 ; x1 < xFactor ; ++x1 )
368     {
369     unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ;
370     unsigned char red = pixel[0] ;
371     unsigned char green = pixel[1] ;
372     unsigned char blue = pixel[2] ;
373     unsigned char alpha = 255 ;
374     if ( source_alpha )
375     alpha = *(source_alpha + y_offset + x * xFactor + x1) ;
376     if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue )
377     {
378     if ( alpha > 0 )
379     {
380     avgRed += red ;
381     avgGreen += green ;
382     avgBlue += blue ;
383     }
384     avgAlpha += alpha ;
385     counter++ ;
386     }
387     }
388     }
389     if ( counter == 0 )
390     {
391     *(target_data++) = M_IMGDATA->m_maskRed ;
392     *(target_data++) = M_IMGDATA->m_maskGreen ;
393     *(target_data++) = M_IMGDATA->m_maskBlue ;
394     }
395     else
396     {
397     if ( source_alpha )
398     *(target_alpha++) = (unsigned char)(avgAlpha / counter ) ;
399     *(target_data++) = (unsigned char)(avgRed / counter);
400     *(target_data++) = (unsigned char)(avgGreen / counter);
401     *(target_data++) = (unsigned char)(avgBlue / counter);
402     }
403     }
404     }
405    
406     // In case this is a cursor, make sure the hotspot is scaled accordingly:
407     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) )
408     image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X,
409     (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X))/xFactor);
410     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) )
411     image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y,
412     (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y))/yFactor);
413    
414     return image;
415     }
416    
417     wxImage wxImage::Scale( int width, int height, int quality ) const
418     {
419     wxImage image;
420    
421     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
422    
423     // can't scale to/from 0 size
424     wxCHECK_MSG( (width > 0) && (height > 0), image,
425     wxT("invalid new image size") );
426    
427     long old_height = M_IMGDATA->m_height,
428     old_width = M_IMGDATA->m_width;
429     wxCHECK_MSG( (old_height > 0) && (old_width > 0), image,
430     wxT("invalid old image size") );
431    
432     // If the image's new width and height are the same as the original, no
433     // need to waste time or CPU cycles
434     if ( old_width == width && old_height == height )
435     return *this;
436    
437     // Scale the image (...or more appropriately, resample the image) using
438     // either the high-quality or normal method as specified
439     if ( quality == wxIMAGE_QUALITY_HIGH )
440     {
441     // We need to check whether we are downsampling or upsampling the image
442     if ( width < old_width && height < old_height )
443     {
444     // Downsample the image using the box averaging method for best results
445     image = ResampleBox(width, height);
446     }
447     else
448     {
449     // For upsampling or other random/wierd image dimensions we'll use
450     // a bicubic b-spline scaling method
451     image = ResampleBicubic(width, height);
452     }
453     }
454     else // Default scaling method == simple pixel replication
455     {
456     if ( old_width % width == 0 && old_width >= width &&
457     old_height % height == 0 && old_height >= height )
458     {
459     return ShrinkBy( old_width / width , old_height / height ) ;
460     }
461     image.Create( width, height, false );
462    
463     unsigned char *data = image.GetData();
464    
465     wxCHECK_MSG( data, image, wxT("unable to create image") );
466    
467     unsigned char *source_data = M_IMGDATA->m_data;
468     unsigned char *target_data = data;
469     unsigned char *source_alpha = 0 ;
470     unsigned char *target_alpha = 0 ;
471    
472     if ( !M_IMGDATA->m_hasMask )
473     {
474     source_alpha = M_IMGDATA->m_alpha ;
475     if ( source_alpha )
476     {
477     image.SetAlpha() ;
478     target_alpha = image.GetAlpha() ;
479     }
480     }
481    
482     long x_delta = (old_width<<16) / width;
483     long y_delta = (old_height<<16) / height;
484    
485     unsigned char* dest_pixel = target_data;
486    
487     long y = 0;
488     for ( long j = 0; j < height; j++ )
489     {
490     unsigned char* src_line = &source_data[(y>>16)*old_width*3];
491     unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ;
492    
493     long x = 0;
494     for ( long i = 0; i < width; i++ )
495     {
496     unsigned char* src_pixel = &src_line[(x>>16)*3];
497     unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ;
498     dest_pixel[0] = src_pixel[0];
499     dest_pixel[1] = src_pixel[1];
500     dest_pixel[2] = src_pixel[2];
501     dest_pixel += 3;
502     if ( source_alpha )
503     *(target_alpha++) = *src_alpha_pixel ;
504     x += x_delta;
505     }
506    
507     y += y_delta;
508     }
509     }
510    
511     // If the original image has a mask, apply the mask to the new image
512     if (M_IMGDATA->m_hasMask)
513     {
514     image.SetMaskColour( M_IMGDATA->m_maskRed,
515     M_IMGDATA->m_maskGreen,
516     M_IMGDATA->m_maskBlue );
517     }
518    
519     // In case this is a cursor, make sure the hotspot is scaled accordingly:
520     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) )
521     image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X,
522     (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width);
523     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) )
524     image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y,
525     (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)*height)/old_height);
526    
527     return image;
528     }
529    
530     wxImage wxImage::ResampleBox(int width, int height) const
531     {
532     // This function implements a simple pre-blur/box averaging method for
533     // downsampling that gives reasonably smooth results To scale the image
534     // down we will need to gather a grid of pixels of the size of the scale
535     // factor in each direction and then do an averaging of the pixels.
536    
537     wxImage ret_image(width, height, false);
538    
539     const double scale_factor_x = double(M_IMGDATA->m_width) / width;
540     const double scale_factor_y = double(M_IMGDATA->m_height) / height;
541    
542     const int scale_factor_x_2 = (int)(scale_factor_x / 2);
543     const int scale_factor_y_2 = (int)(scale_factor_y / 2);
544    
545     unsigned char* src_data = M_IMGDATA->m_data;
546     unsigned char* src_alpha = M_IMGDATA->m_alpha;
547     unsigned char* dst_data = ret_image.GetData();
548     unsigned char* dst_alpha = NULL;
549    
550     if ( src_alpha )
551     {
552     ret_image.SetAlpha();
553     dst_alpha = ret_image.GetAlpha();
554     }
555    
556     int averaged_pixels, src_pixel_index;
557     double sum_r, sum_g, sum_b, sum_a;
558    
559     for ( int y = 0; y < height; y++ ) // Destination image - Y direction
560     {
561     // Source pixel in the Y direction
562     int src_y = (int)(y * scale_factor_y);
563    
564     for ( int x = 0; x < width; x++ ) // Destination image - X direction
565     {
566     // Source pixel in the X direction
567     int src_x = (int)(x * scale_factor_x);
568    
569     // Box of pixels to average
570     averaged_pixels = 0;
571     sum_r = sum_g = sum_b = sum_a = 0.0;
572    
573     for ( int j = int(src_y - scale_factor_y/2.0 + 1);
574     j <= int(src_y + scale_factor_y_2);
575     j++ )
576     {
577     // We don't care to average pixels that don't exist (edges)
578     if ( j < 0 || j > M_IMGDATA->m_height - 1 )
579     continue;
580    
581     for ( int i = int(src_x - scale_factor_x/2.0 + 1);
582     i <= src_x + scale_factor_x_2;
583     i++ )
584     {
585     // Don't average edge pixels
586     if ( i < 0 || i > M_IMGDATA->m_width - 1 )
587     continue;
588    
589     // Calculate the actual index in our source pixels
590     src_pixel_index = j * M_IMGDATA->m_width + i;
591    
592     sum_r += src_data[src_pixel_index * 3 + 0];
593     sum_g += src_data[src_pixel_index * 3 + 1];
594     sum_b += src_data[src_pixel_index * 3 + 2];
595     if ( src_alpha )
596     sum_a += src_alpha[src_pixel_index];
597    
598     averaged_pixels++;
599     }
600     }
601    
602     // Calculate the average from the sum and number of averaged pixels
603     dst_data[0] = (unsigned char)(sum_r / averaged_pixels);
604     dst_data[1] = (unsigned char)(sum_g / averaged_pixels);
605     dst_data[2] = (unsigned char)(sum_b / averaged_pixels);
606     dst_data += 3;
607     if ( src_alpha )
608     *dst_alpha++ = (unsigned char)(sum_a / averaged_pixels);
609     }
610     }
611    
612     return ret_image;
613     }
614    
615     // The following two local functions are for the B-spline weighting of the
616     // bicubic sampling algorithm
617     static inline double spline_cube(double value)
618     {
619     return value <= 0.0 ? 0.0 : value * value * value;
620     }
621    
622     static inline double spline_weight(double value)
623     {
624     return (spline_cube(value + 2) -
625     4 * spline_cube(value + 1) +
626     6 * spline_cube(value) -
627     4 * spline_cube(value - 1)) / 6;
628     }
629    
630     // This is the bicubic resampling algorithm
631     wxImage wxImage::ResampleBicubic(int width, int height) const
632     {
633     // This function implements a Bicubic B-Spline algorithm for resampling.
634     // This method is certainly a little slower than wxImage's default pixel
635     // replication method, however for most reasonably sized images not being
636     // upsampled too much on a fairly average CPU this difference is hardly
637     // noticeable and the results are far more pleasing to look at.
638     //
639     // This particular bicubic algorithm does pixel weighting according to a
640     // B-Spline that basically implements a Gaussian bell-like weighting
641     // kernel. Because of this method the results may appear a bit blurry when
642     // upsampling by large factors. This is basically because a slight
643     // gaussian blur is being performed to get the smooth look of the upsampled
644     // image.
645    
646     // Edge pixels: 3-4 possible solutions
647     // - (Wrap/tile) Wrap the image, take the color value from the opposite
648     // side of the image.
649     // - (Mirror) Duplicate edge pixels, so that pixel at coordinate (2, n),
650     // where n is nonpositive, will have the value of (2, 1).
651     // - (Ignore) Simply ignore the edge pixels and apply the kernel only to
652     // pixels which do have all neighbours.
653     // - (Clamp) Choose the nearest pixel along the border. This takes the
654     // border pixels and extends them out to infinity.
655     //
656     // NOTE: below the y_offset and x_offset variables are being set for edge
657     // pixels using the "Mirror" method mentioned above
658    
659     wxImage ret_image;
660    
661     ret_image.Create(width, height, false);
662    
663     unsigned char* src_data = M_IMGDATA->m_data;
664     unsigned char* src_alpha = M_IMGDATA->m_alpha;
665     unsigned char* dst_data = ret_image.GetData();
666     unsigned char* dst_alpha = NULL;
667    
668     if ( src_alpha )
669     {
670     ret_image.SetAlpha();
671     dst_alpha = ret_image.GetAlpha();
672     }
673    
674     for ( int dsty = 0; dsty < height; dsty++ )
675     {
676     // We need to calculate the source pixel to interpolate from - Y-axis
677     double srcpixy = double(dsty * M_IMGDATA->m_height) / height;
678     double dy = srcpixy - (int)srcpixy;
679    
680     for ( int dstx = 0; dstx < width; dstx++ )
681     {
682     // X-axis of pixel to interpolate from
683     double srcpixx = double(dstx * M_IMGDATA->m_width) / width;
684     double dx = srcpixx - (int)srcpixx;
685    
686     // Sums for each color channel
687     double sum_r = 0, sum_g = 0, sum_b = 0, sum_a = 0;
688    
689     // Here we actually determine the RGBA values for the destination pixel
690     for ( int k = -1; k <= 2; k++ )
691     {
692     // Y offset
693     int y_offset = srcpixy + k < 0.0
694     ? 0
695     : srcpixy + k >= M_IMGDATA->m_height
696     ? M_IMGDATA->m_height - 1
697     : (int)(srcpixy + k);
698    
699     // Loop across the X axis
700     for ( int i = -1; i <= 2; i++ )
701     {
702     // X offset
703     int x_offset = srcpixx + i < 0.0
704     ? 0
705     : srcpixx + i >= M_IMGDATA->m_width
706     ? M_IMGDATA->m_width - 1
707     : (int)(srcpixx + i);
708    
709     // Calculate the exact position where the source data
710     // should be pulled from based on the x_offset and y_offset
711     int src_pixel_index = y_offset*M_IMGDATA->m_width + x_offset;
712    
713     // Calculate the weight for the specified pixel according
714     // to the bicubic b-spline kernel we're using for
715     // interpolation
716     double
717     pixel_weight = spline_weight(i - dx)*spline_weight(k - dy);
718    
719     // Create a sum of all velues for each color channel
720     // adjusted for the pixel's calculated weight
721     sum_r += src_data[src_pixel_index * 3 + 0] * pixel_weight;
722     sum_g += src_data[src_pixel_index * 3 + 1] * pixel_weight;
723     sum_b += src_data[src_pixel_index * 3 + 2] * pixel_weight;
724     if ( src_alpha )
725     sum_a += src_alpha[src_pixel_index] * pixel_weight;
726     }
727     }
728    
729     // Put the data into the destination image. The summed values are
730     // of double data type and are rounded here for accuracy
731     dst_data[0] = (unsigned char)(sum_r + 0.5);
732     dst_data[1] = (unsigned char)(sum_g + 0.5);
733     dst_data[2] = (unsigned char)(sum_b + 0.5);
734     dst_data += 3;
735    
736     if ( src_alpha )
737     *dst_alpha++ = (unsigned char)sum_a;
738     }
739     }
740    
741     return ret_image;
742     }
743    
744     // Blur in the horizontal direction
745     wxImage wxImage::BlurHorizontal(int blurRadius)
746     {
747     wxImage ret_image;
748     ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false);
749    
750     unsigned char* src_data = M_IMGDATA->m_data;
751     unsigned char* dst_data = ret_image.GetData();
752     unsigned char* src_alpha = M_IMGDATA->m_alpha;
753     unsigned char* dst_alpha = NULL;
754    
755     // Check for a mask or alpha
756     if ( M_IMGDATA->m_hasMask )
757     {
758     ret_image.SetMaskColour(M_IMGDATA->m_maskRed,
759     M_IMGDATA->m_maskGreen,
760     M_IMGDATA->m_maskBlue);
761     }
762     else
763     {
764     if ( src_alpha )
765     {
766     ret_image.SetAlpha();
767     dst_alpha = ret_image.GetAlpha();
768     }
769     }
770    
771     // number of pixels we average over
772     const int blurArea = blurRadius*2 + 1;
773    
774     // Horizontal blurring algorithm - average all pixels in the specified blur
775     // radius in the X or horizontal direction
776     for ( int y = 0; y < M_IMGDATA->m_height; y++ )
777     {
778     // Variables used in the blurring algorithm
779     long sum_r = 0,
780     sum_g = 0,
781     sum_b = 0,
782     sum_a = 0;
783    
784     long pixel_idx;
785     const unsigned char *src;
786     unsigned char *dst;
787    
788     // Calculate the average of all pixels in the blur radius for the first
789     // pixel of the row
790     for ( int kernel_x = -blurRadius; kernel_x <= blurRadius; kernel_x++ )
791     {
792     // To deal with the pixels at the start of a row so it's not
793     // grabbing GOK values from memory at negative indices of the
794     // image's data or grabbing from the previous row
795     if ( kernel_x < 0 )
796     pixel_idx = y * M_IMGDATA->m_width;
797     else
798     pixel_idx = kernel_x + y * M_IMGDATA->m_width;
799    
800     src = src_data + pixel_idx*3;
801     sum_r += src[0];
802     sum_g += src[1];
803     sum_b += src[2];
804     if ( src_alpha )
805     sum_a += src_alpha[pixel_idx];
806     }
807    
808     dst = dst_data + y * M_IMGDATA->m_width*3;
809     dst[0] = (unsigned char)(sum_r / blurArea);
810     dst[1] = (unsigned char)(sum_g / blurArea);
811     dst[2] = (unsigned char)(sum_b / blurArea);
812     if ( src_alpha )
813     dst_alpha[y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea);
814    
815     // Now average the values of the rest of the pixels by just moving the
816     // blur radius box along the row
817     for ( int x = 1; x < M_IMGDATA->m_width; x++ )
818     {
819     // Take care of edge pixels on the left edge by essentially
820     // duplicating the edge pixel
821     if ( x - blurRadius - 1 < 0 )
822     pixel_idx = y * M_IMGDATA->m_width;
823     else
824     pixel_idx = (x - blurRadius - 1) + y * M_IMGDATA->m_width;
825    
826     // Subtract the value of the pixel at the left side of the blur
827     // radius box
828     src = src_data + pixel_idx*3;
829     sum_r -= src[0];
830     sum_g -= src[1];
831     sum_b -= src[2];
832     if ( src_alpha )
833     sum_a -= src_alpha[pixel_idx];
834    
835     // Take care of edge pixels on the right edge
836     if ( x + blurRadius > M_IMGDATA->m_width - 1 )
837     pixel_idx = M_IMGDATA->m_width - 1 + y * M_IMGDATA->m_width;
838     else
839     pixel_idx = x + blurRadius + y * M_IMGDATA->m_width;
840    
841     // Add the value of the pixel being added to the end of our box
842     src = src_data + pixel_idx*3;
843     sum_r += src[0];
844     sum_g += src[1];
845     sum_b += src[2];
846     if ( src_alpha )
847     sum_a += src_alpha[pixel_idx];
848    
849     // Save off the averaged data
850     dst = dst_data + x*3 + y*M_IMGDATA->m_width*3;
851     dst[0] = (unsigned char)(sum_r / blurArea);
852     dst[1] = (unsigned char)(sum_g / blurArea);
853     dst[2] = (unsigned char)(sum_b / blurArea);
854     if ( src_alpha )
855     dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea);
856     }
857     }
858    
859     return ret_image;
860     }
861    
862     // Blur in the vertical direction
863     wxImage wxImage::BlurVertical(int blurRadius)
864     {
865     wxImage ret_image;
866     ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false);
867    
868     unsigned char* src_data = M_IMGDATA->m_data;
869     unsigned char* dst_data = ret_image.GetData();
870     unsigned char* src_alpha = M_IMGDATA->m_alpha;
871     unsigned char* dst_alpha = NULL;
872    
873     // Check for a mask or alpha
874     if ( M_IMGDATA->m_hasMask )
875     {
876     ret_image.SetMaskColour(M_IMGDATA->m_maskRed,
877     M_IMGDATA->m_maskGreen,
878     M_IMGDATA->m_maskBlue);
879     }
880     else
881     {
882     if ( src_alpha )
883     {
884     ret_image.SetAlpha();
885     dst_alpha = ret_image.GetAlpha();
886     }
887     }
888    
889     // number of pixels we average over
890     const int blurArea = blurRadius*2 + 1;
891    
892     // Vertical blurring algorithm - same as horizontal but switched the
893     // opposite direction
894     for ( int x = 0; x < M_IMGDATA->m_width; x++ )
895     {
896     // Variables used in the blurring algorithm
897     long sum_r = 0,
898     sum_g = 0,
899     sum_b = 0,
900     sum_a = 0;
901    
902     long pixel_idx;
903     const unsigned char *src;
904     unsigned char *dst;
905    
906     // Calculate the average of all pixels in our blur radius box for the
907     // first pixel of the column
908     for ( int kernel_y = -blurRadius; kernel_y <= blurRadius; kernel_y++ )
909     {
910     // To deal with the pixels at the start of a column so it's not
911     // grabbing GOK values from memory at negative indices of the
912     // image's data or grabbing from the previous column
913     if ( kernel_y < 0 )
914     pixel_idx = x;
915     else
916     pixel_idx = x + kernel_y * M_IMGDATA->m_width;
917    
918     src = src_data + pixel_idx*3;
919     sum_r += src[0];
920     sum_g += src[1];
921     sum_b += src[2];
922     if ( src_alpha )
923     sum_a += src_alpha[pixel_idx];
924     }
925    
926     dst = dst_data + x*3;
927     dst[0] = (unsigned char)(sum_r / blurArea);
928     dst[1] = (unsigned char)(sum_g / blurArea);
929     dst[2] = (unsigned char)(sum_b / blurArea);
930     if ( src_alpha )
931     dst_alpha[x] = (unsigned char)(sum_a / blurArea);
932    
933     // Now average the values of the rest of the pixels by just moving the
934     // box along the column from top to bottom
935     for ( int y = 1; y < M_IMGDATA->m_height; y++ )
936     {
937     // Take care of pixels that would be beyond the top edge by
938     // duplicating the top edge pixel for the column
939     if ( y - blurRadius - 1 < 0 )
940     pixel_idx = x;
941     else
942     pixel_idx = x + (y - blurRadius - 1) * M_IMGDATA->m_width;
943    
944     // Subtract the value of the pixel at the top of our blur radius box
945     src = src_data + pixel_idx*3;
946     sum_r -= src[0];
947     sum_g -= src[1];
948     sum_b -= src[2];
949     if ( src_alpha )
950     sum_a -= src_alpha[pixel_idx];
951    
952     // Take care of the pixels that would be beyond the bottom edge of
953     // the image similar to the top edge
954     if ( y + blurRadius > M_IMGDATA->m_height - 1 )
955     pixel_idx = x + (M_IMGDATA->m_height - 1) * M_IMGDATA->m_width;
956     else
957     pixel_idx = x + (blurRadius + y) * M_IMGDATA->m_width;
958    
959     // Add the value of the pixel being added to the end of our box
960     src = src_data + pixel_idx*3;
961     sum_r += src[0];
962     sum_g += src[1];
963     sum_b += src[2];
964     if ( src_alpha )
965     sum_a += src_alpha[pixel_idx];
966    
967     // Save off the averaged data
968     dst = dst_data + (x + y * M_IMGDATA->m_width) * 3;
969     dst[0] = (unsigned char)(sum_r / blurArea);
970     dst[1] = (unsigned char)(sum_g / blurArea);
971     dst[2] = (unsigned char)(sum_b / blurArea);
972     if ( src_alpha )
973     dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea);
974     }
975     }
976    
977     return ret_image;
978     }
979    
980     // The new blur function
981     wxImage wxImage::Blur(int blurRadius)
982     {
983     wxImage ret_image;
984     ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false);
985    
986     // Blur the image in each direction
987     ret_image = BlurHorizontal(blurRadius);
988     ret_image = ret_image.BlurVertical(blurRadius);
989    
990     return ret_image;
991     }
992    
993     wxImage wxImage::Rotate90( bool clockwise ) const
994     {
995     wxImage image;
996    
997     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
998    
999     image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width, false );
1000    
1001     unsigned char *data = image.GetData();
1002    
1003     wxCHECK_MSG( data, image, wxT("unable to create image") );
1004    
1005     unsigned char *source_data = M_IMGDATA->m_data;
1006     unsigned char *target_data;
1007     unsigned char *alpha_data = 0 ;
1008     unsigned char *source_alpha = 0 ;
1009     unsigned char *target_alpha = 0 ;
1010    
1011     if (M_IMGDATA->m_hasMask)
1012     {
1013     image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
1014     }
1015     else
1016     {
1017     source_alpha = M_IMGDATA->m_alpha ;
1018     if ( source_alpha )
1019     {
1020     image.SetAlpha() ;
1021     alpha_data = image.GetAlpha() ;
1022     }
1023     }
1024    
1025     long height = M_IMGDATA->m_height;
1026     long width = M_IMGDATA->m_width;
1027    
1028     for (long j = 0; j < height; j++)
1029     {
1030     for (long i = 0; i < width; i++)
1031     {
1032     if (clockwise)
1033     {
1034     target_data = data + (((i+1)*height) - j - 1)*3;
1035     if(source_alpha)
1036     target_alpha = alpha_data + (((i+1)*height) - j - 1);
1037     }
1038     else
1039     {
1040     target_data = data + ((height*(width-1)) + j - (i*height))*3;
1041     if(source_alpha)
1042     target_alpha = alpha_data + ((height*(width-1)) + j - (i*height));
1043     }
1044     memcpy( target_data, source_data, 3 );
1045     source_data += 3;
1046    
1047     if(source_alpha)
1048     {
1049     memcpy( target_alpha, source_alpha, 1 );
1050     source_alpha += 1;
1051     }
1052     }
1053     }
1054    
1055     return image;
1056     }
1057    
1058     wxImage wxImage::Mirror( bool horizontally ) const
1059     {
1060     wxImage image;
1061    
1062     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
1063    
1064     image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false );
1065    
1066     unsigned char *data = image.GetData();
1067     unsigned char *alpha = NULL;
1068    
1069     wxCHECK_MSG( data, image, wxT("unable to create image") );
1070    
1071     if (M_IMGDATA->m_alpha != NULL) {
1072     image.SetAlpha();
1073     alpha = image.GetAlpha();
1074     wxCHECK_MSG( alpha, image, wxT("unable to create alpha channel") );
1075     }
1076    
1077     if (M_IMGDATA->m_hasMask)
1078     image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
1079    
1080     long height = M_IMGDATA->m_height;
1081     long width = M_IMGDATA->m_width;
1082    
1083     unsigned char *source_data = M_IMGDATA->m_data;
1084     unsigned char *target_data;
1085    
1086     if (horizontally)
1087     {
1088     for (long j = 0; j < height; j++)
1089     {
1090     data += width*3;
1091     target_data = data-3;
1092     for (long i = 0; i < width; i++)
1093     {
1094     memcpy( target_data, source_data, 3 );
1095     source_data += 3;
1096     target_data -= 3;
1097     }
1098     }
1099    
1100     if (alpha != NULL)
1101     {
1102     // src_alpha starts at the first pixel and increases by 1 after each step
1103     // (a step here is the copy of the alpha value of one pixel)
1104     const unsigned char *src_alpha = M_IMGDATA->m_alpha;
1105     // dest_alpha starts just beyond the first line, decreases before each step,
1106     // and after each line is finished, increases by 2 widths (skipping the line
1107     // just copied and the line that will be copied next)
1108     unsigned char *dest_alpha = alpha + width;
1109    
1110     for (long jj = 0; jj < height; ++jj)
1111     {
1112     for (long i = 0; i < width; ++i) {
1113     *(--dest_alpha) = *(src_alpha++); // copy one pixel
1114     }
1115     dest_alpha += 2 * width; // advance beyond the end of the next line
1116     }
1117     }
1118     }
1119     else
1120     {
1121     for (long i = 0; i < height; i++)
1122     {
1123     target_data = data + 3*width*(height-1-i);
1124     memcpy( target_data, source_data, (size_t)3*width );
1125     source_data += 3*width;
1126     }
1127    
1128     if (alpha != NULL)
1129     {
1130     // src_alpha starts at the first pixel and increases by 1 width after each step
1131     // (a step here is the copy of the alpha channel of an entire line)
1132     const unsigned char *src_alpha = M_IMGDATA->m_alpha;
1133     // dest_alpha starts just beyond the last line (beyond the whole image)
1134     // and decreases by 1 width before each step
1135     unsigned char *dest_alpha = alpha + width * height;
1136    
1137     for (long jj = 0; jj < height; ++jj)
1138     {
1139     dest_alpha -= width;
1140     memcpy( dest_alpha, src_alpha, (size_t)width );
1141     src_alpha += width;
1142     }
1143     }
1144     }
1145    
1146     return image;
1147     }
1148    
1149     wxImage wxImage::GetSubImage( const wxRect &rect ) const
1150     {
1151     wxImage image;
1152    
1153     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
1154    
1155     wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) &&
1156     (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()),
1157     image, wxT("invalid subimage size") );
1158    
1159     const int subwidth = rect.GetWidth();
1160     const int subheight = rect.GetHeight();
1161    
1162     image.Create( subwidth, subheight, false );
1163    
1164     const unsigned char *src_data = GetData();
1165     const unsigned char *src_alpha = M_IMGDATA->m_alpha;
1166     unsigned char *subdata = image.GetData();
1167     unsigned char *subalpha = NULL;
1168    
1169     wxCHECK_MSG( subdata, image, wxT("unable to create image") );
1170    
1171     if (src_alpha != NULL) {
1172     image.SetAlpha();
1173     subalpha = image.GetAlpha();
1174     wxCHECK_MSG( subalpha, image, wxT("unable to create alpha channel"));
1175     }
1176    
1177     if (M_IMGDATA->m_hasMask)
1178     image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
1179    
1180     const int width = GetWidth();
1181     const int pixsoff = rect.GetLeft() + width * rect.GetTop();
1182    
1183     src_data += 3 * pixsoff;
1184     src_alpha += pixsoff; // won't be used if was NULL, so this is ok
1185    
1186     for (long j = 0; j < subheight; ++j)
1187     {
1188     memcpy( subdata, src_data, 3 * subwidth );
1189     subdata += 3 * subwidth;
1190     src_data += 3 * width;
1191     if (subalpha != NULL) {
1192     memcpy( subalpha, src_alpha, subwidth );
1193     subalpha += subwidth;
1194     src_alpha += width;
1195     }
1196     }
1197    
1198     return image;
1199     }
1200    
1201     wxImage wxImage::Size( const wxSize& size, const wxPoint& pos,
1202     int r_, int g_, int b_ ) const
1203     {
1204     wxImage image;
1205    
1206     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
1207     wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") );
1208    
1209     int width = GetWidth(), height = GetHeight();
1210     image.Create(size.GetWidth(), size.GetHeight(), false);
1211    
1212     unsigned char r = (unsigned char)r_;
1213     unsigned char g = (unsigned char)g_;
1214     unsigned char b = (unsigned char)b_;
1215     if ((r_ == -1) && (g_ == -1) && (b_ == -1))
1216     {
1217     GetOrFindMaskColour( &r, &g, &b );
1218     image.SetMaskColour(r, g, b);
1219     }
1220    
1221     image.SetRGB(wxRect(), r, g, b);
1222    
1223     wxRect subRect(pos.x, pos.y, width, height);
1224     wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight());
1225     if (pos.x < 0)
1226     finalRect.width -= pos.x;
1227     if (pos.y < 0)
1228     finalRect.height -= pos.y;
1229    
1230     subRect.Intersect(finalRect);
1231    
1232     if (!subRect.IsEmpty())
1233     {
1234     if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height))
1235     image.Paste(*this, pos.x, pos.y);
1236     else
1237     image.Paste(GetSubImage(subRect), pos.x, pos.y);
1238     }
1239    
1240     return image;
1241     }
1242    
1243     void wxImage::Paste( const wxImage &image, int x, int y )
1244     {
1245     wxCHECK_RET( Ok(), wxT("invalid image") );
1246     wxCHECK_RET( image.Ok(), wxT("invalid image") );
1247    
1248     AllocExclusive();
1249    
1250     int xx = 0;
1251     int yy = 0;
1252     int width = image.GetWidth();
1253     int height = image.GetHeight();
1254    
1255     if (x < 0)
1256     {
1257     xx = -x;
1258     width += x;
1259     }
1260     if (y < 0)
1261     {
1262     yy = -y;
1263     height += y;
1264     }
1265    
1266     if ((x+xx)+width > M_IMGDATA->m_width)
1267     width = M_IMGDATA->m_width - (x+xx);
1268     if ((y+yy)+height > M_IMGDATA->m_height)
1269     height = M_IMGDATA->m_height - (y+yy);
1270    
1271     if (width < 1) return;
1272     if (height < 1) return;
1273    
1274     if ((!HasMask() && !image.HasMask()) ||
1275     (HasMask() && !image.HasMask()) ||
1276     ((HasMask() && image.HasMask() &&
1277     (GetMaskRed()==image.GetMaskRed()) &&
1278     (GetMaskGreen()==image.GetMaskGreen()) &&
1279     (GetMaskBlue()==image.GetMaskBlue()))))
1280     {
1281     unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth();
1282     int source_step = image.GetWidth()*3;
1283    
1284     unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width;
1285     int target_step = M_IMGDATA->m_width*3;
1286     for (int j = 0; j < height; j++)
1287     {
1288     memcpy( target_data, source_data, width*3 );
1289     source_data += source_step;
1290     target_data += target_step;
1291     }
1292     }
1293    
1294     // Copy over the alpha channel from the original image
1295     if ( image.HasAlpha() )
1296     {
1297     if ( !HasAlpha() )
1298     InitAlpha();
1299    
1300     unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth();
1301     int source_step = image.GetWidth();
1302    
1303     unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width;
1304     int target_step = M_IMGDATA->m_width;
1305    
1306     for (int j = 0; j < height; j++,
1307     source_data += source_step,
1308     target_data += target_step)
1309     {
1310     memcpy( target_data, source_data, width );
1311     }
1312     }
1313    
1314     if (!HasMask() && image.HasMask())
1315     {
1316     unsigned char r = image.GetMaskRed();
1317     unsigned char g = image.GetMaskGreen();
1318     unsigned char b = image.GetMaskBlue();
1319    
1320     unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth();
1321     int source_step = image.GetWidth()*3;
1322    
1323     unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width;
1324     int target_step = M_IMGDATA->m_width*3;
1325    
1326     for (int j = 0; j < height; j++)
1327     {
1328     for (int i = 0; i < width*3; i+=3)
1329     {
1330     if ((source_data[i] != r) ||
1331     (source_data[i+1] != g) ||
1332     (source_data[i+2] != b))
1333     {
1334     memcpy( target_data+i, source_data+i, 3 );
1335     }
1336     }
1337     source_data += source_step;
1338     target_data += target_step;
1339     }
1340     }
1341     }
1342    
1343     void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1,
1344     unsigned char r2, unsigned char g2, unsigned char b2 )
1345     {
1346     wxCHECK_RET( Ok(), wxT("invalid image") );
1347    
1348     AllocExclusive();
1349    
1350     unsigned char *data = GetData();
1351    
1352     const int w = GetWidth();
1353     const int h = GetHeight();
1354    
1355     for (int j = 0; j < h; j++)
1356     for (int i = 0; i < w; i++)
1357     {
1358     if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1))
1359     {
1360     data[0] = r2;
1361     data[1] = g2;
1362     data[2] = b2;
1363     }
1364     data += 3;
1365     }
1366     }
1367    
1368     wxImage wxImage::ConvertToGreyscale( double lr, double lg, double lb ) const
1369     {
1370     wxImage image;
1371    
1372     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
1373    
1374     image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false);
1375    
1376     unsigned char *dest = image.GetData();
1377    
1378     wxCHECK_MSG( dest, image, wxT("unable to create image") );
1379    
1380     unsigned char *src = M_IMGDATA->m_data;
1381     bool hasMask = M_IMGDATA->m_hasMask;
1382     unsigned char maskRed = M_IMGDATA->m_maskRed;
1383     unsigned char maskGreen = M_IMGDATA->m_maskGreen;
1384     unsigned char maskBlue = M_IMGDATA->m_maskBlue;
1385    
1386     if ( hasMask )
1387     image.SetMaskColour(maskRed, maskGreen, maskBlue);
1388    
1389     const long size = M_IMGDATA->m_width * M_IMGDATA->m_height;
1390     for ( long i = 0; i < size; i++, src += 3, dest += 3 )
1391     {
1392     // don't modify the mask
1393     if ( hasMask && src[0] == maskRed && src[1] == maskGreen && src[2] == maskBlue )
1394     {
1395     memcpy(dest, src, 3);
1396     }
1397     else
1398     {
1399     // calculate the luma
1400     double luma = (src[0] * lr + src[1] * lg + src[2] * lb) + 0.5;
1401     dest[0] = dest[1] = dest[2] = wx_static_cast(unsigned char, luma);
1402     }
1403     }
1404    
1405     // copy the alpha channel, if any
1406     if (HasAlpha())
1407     {
1408     const size_t alphaSize = GetWidth() * GetHeight();
1409     unsigned char *alpha = (unsigned char*)malloc(alphaSize);
1410     memcpy(alpha, GetAlpha(), alphaSize);
1411     image.InitAlpha();
1412     image.SetAlpha(alpha);
1413     }
1414    
1415     return image;
1416     }
1417    
1418     wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const
1419     {
1420     wxImage image;
1421    
1422     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
1423    
1424     image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false );
1425    
1426     unsigned char *data = image.GetData();
1427    
1428     wxCHECK_MSG( data, image, wxT("unable to create image") );
1429    
1430     if (M_IMGDATA->m_hasMask)
1431     {
1432     if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g &&
1433     M_IMGDATA->m_maskBlue == b)
1434     image.SetMaskColour( 255, 255, 255 );
1435     else
1436     image.SetMaskColour( 0, 0, 0 );
1437     }
1438    
1439     long size = M_IMGDATA->m_height * M_IMGDATA->m_width;
1440    
1441     unsigned char *srcd = M_IMGDATA->m_data;
1442     unsigned char *tard = image.GetData();
1443    
1444     for ( long i = 0; i < size; i++, srcd += 3, tard += 3 )
1445     {
1446     if (srcd[0] == r && srcd[1] == g && srcd[2] == b)
1447     tard[0] = tard[1] = tard[2] = 255;
1448     else
1449     tard[0] = tard[1] = tard[2] = 0;
1450     }
1451    
1452     return image;
1453     }
1454    
1455     int wxImage::GetWidth() const
1456     {
1457     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
1458    
1459     return M_IMGDATA->m_width;
1460     }
1461    
1462     int wxImage::GetHeight() const
1463     {
1464     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
1465    
1466     return M_IMGDATA->m_height;
1467     }
1468    
1469     long wxImage::XYToIndex(int x, int y) const
1470     {
1471     if ( Ok() &&
1472     x >= 0 && y >= 0 &&
1473     x < M_IMGDATA->m_width && y < M_IMGDATA->m_height )
1474     {
1475     return y*M_IMGDATA->m_width + x;
1476     }
1477    
1478     return -1;
1479     }
1480    
1481     void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
1482     {
1483     long pos = XYToIndex(x, y);
1484     wxCHECK_RET( pos != -1, wxT("invalid image coordinates") );
1485    
1486     AllocExclusive();
1487    
1488     pos *= 3;
1489    
1490     M_IMGDATA->m_data[ pos ] = r;
1491     M_IMGDATA->m_data[ pos+1 ] = g;
1492     M_IMGDATA->m_data[ pos+2 ] = b;
1493     }
1494    
1495     void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b )
1496     {
1497     wxCHECK_RET( Ok(), wxT("invalid image") );
1498    
1499     AllocExclusive();
1500    
1501     wxRect rect(rect_);
1502     wxRect imageRect(0, 0, GetWidth(), GetHeight());
1503     if ( rect == wxRect() )
1504     {
1505     rect = imageRect;
1506     }
1507     else
1508     {
1509     wxCHECK_RET( imageRect.Contains(rect.GetTopLeft()) &&
1510     imageRect.Contains(rect.GetBottomRight()),
1511     wxT("invalid bounding rectangle") );
1512     }
1513    
1514     int x1 = rect.GetLeft(),
1515     y1 = rect.GetTop(),
1516     x2 = rect.GetRight() + 1,
1517     y2 = rect.GetBottom() + 1;
1518    
1519     unsigned char *data wxDUMMY_INITIALIZE(NULL);
1520     int x, y, width = GetWidth();
1521     for (y = y1; y < y2; y++)
1522     {
1523     data = M_IMGDATA->m_data + (y*width + x1)*3;
1524     for (x = x1; x < x2; x++)
1525     {
1526     *data++ = r;
1527     *data++ = g;
1528     *data++ = b;
1529     }
1530     }
1531     }
1532    
1533     unsigned char wxImage::GetRed( int x, int y ) const
1534     {
1535     long pos = XYToIndex(x, y);
1536     wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
1537    
1538     pos *= 3;
1539    
1540     return M_IMGDATA->m_data[pos];
1541     }
1542    
1543     unsigned char wxImage::GetGreen( int x, int y ) const
1544     {
1545     long pos = XYToIndex(x, y);
1546     wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
1547    
1548     pos *= 3;
1549    
1550     return M_IMGDATA->m_data[pos+1];
1551     }
1552    
1553     unsigned char wxImage::GetBlue( int x, int y ) const
1554     {
1555     long pos = XYToIndex(x, y);
1556     wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
1557    
1558     pos *= 3;
1559    
1560     return M_IMGDATA->m_data[pos+2];
1561     }
1562    
1563     bool wxImage::IsOk() const
1564     {
1565     // image of 0 width or height can't be considered ok - at least because it
1566     // causes crashes in ConvertToBitmap() if we don't catch it in time
1567     wxImageRefData *data = M_IMGDATA;
1568     return data && data->m_ok && data->m_width && data->m_height;
1569     }
1570    
1571     unsigned char *wxImage::GetData() const
1572     {
1573     wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") );
1574    
1575     return M_IMGDATA->m_data;
1576     }
1577    
1578     void wxImage::SetData( unsigned char *data, bool static_data )
1579     {
1580     wxCHECK_RET( Ok(), wxT("invalid image") );
1581    
1582     wxImageRefData *newRefData = new wxImageRefData();
1583    
1584     newRefData->m_width = M_IMGDATA->m_width;
1585     newRefData->m_height = M_IMGDATA->m_height;
1586     newRefData->m_data = data;
1587     newRefData->m_ok = true;
1588     newRefData->m_maskRed = M_IMGDATA->m_maskRed;
1589     newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
1590     newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
1591     newRefData->m_hasMask = M_IMGDATA->m_hasMask;
1592     newRefData->m_static = static_data;
1593    
1594     UnRef();
1595    
1596     m_refData = newRefData;
1597     }
1598    
1599     void wxImage::SetData( unsigned char *data, int new_width, int new_height, bool static_data )
1600     {
1601     wxImageRefData *newRefData = new wxImageRefData();
1602    
1603     if (m_refData)
1604     {
1605     newRefData->m_width = new_width;
1606     newRefData->m_height = new_height;
1607     newRefData->m_data = data;
1608     newRefData->m_ok = true;
1609     newRefData->m_maskRed = M_IMGDATA->m_maskRed;
1610     newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
1611     newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
1612     newRefData->m_hasMask = M_IMGDATA->m_hasMask;
1613     }
1614     else
1615     {
1616     newRefData->m_width = new_width;
1617     newRefData->m_height = new_height;
1618     newRefData->m_data = data;
1619     newRefData->m_ok = true;
1620     }
1621     newRefData->m_static = static_data;
1622    
1623     UnRef();
1624    
1625     m_refData = newRefData;
1626     }
1627    
1628     // ----------------------------------------------------------------------------
1629     // alpha channel support
1630     // ----------------------------------------------------------------------------
1631    
1632     void wxImage::SetAlpha(int x, int y, unsigned char alpha)
1633     {
1634     wxCHECK_RET( HasAlpha(), wxT("no alpha channel") );
1635    
1636     long pos = XYToIndex(x, y);
1637     wxCHECK_RET( pos != -1, wxT("invalid image coordinates") );
1638    
1639     AllocExclusive();
1640    
1641     M_IMGDATA->m_alpha[pos] = alpha;
1642     }
1643    
1644     unsigned char wxImage::GetAlpha(int x, int y) const
1645     {
1646     wxCHECK_MSG( HasAlpha(), 0, wxT("no alpha channel") );
1647    
1648     long pos = XYToIndex(x, y);
1649     wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") );
1650    
1651     return M_IMGDATA->m_alpha[pos];
1652     }
1653    
1654     bool
1655     wxImage::ConvertColourToAlpha(unsigned char r, unsigned char g, unsigned char b)
1656     {
1657     SetAlpha(NULL);
1658    
1659     const int w = M_IMGDATA->m_width;
1660     const int h = M_IMGDATA->m_height;
1661    
1662     unsigned char *alpha = GetAlpha();
1663     unsigned char *data = GetData();
1664    
1665     for ( int y = 0; y < h; y++ )
1666     {
1667     for ( int x = 0; x < w; x++ )
1668     {
1669     *alpha++ = *data;
1670     *data++ = r;
1671     *data++ = g;
1672     *data++ = b;
1673     }
1674     }
1675    
1676     return true;
1677     }
1678    
1679     void wxImage::SetAlpha( unsigned char *alpha, bool static_data )
1680     {
1681     wxCHECK_RET( Ok(), wxT("invalid image") );
1682    
1683     AllocExclusive();
1684    
1685     if ( !alpha )
1686     {
1687     alpha = (unsigned char *)malloc(M_IMGDATA->m_width*M_IMGDATA->m_height);
1688     }
1689    
1690     if( !M_IMGDATA->m_staticAlpha )
1691     free(M_IMGDATA->m_alpha);
1692    
1693     M_IMGDATA->m_alpha = alpha;
1694     M_IMGDATA->m_staticAlpha = static_data;
1695     }
1696    
1697     unsigned char *wxImage::GetAlpha() const
1698     {
1699     wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") );
1700    
1701     return M_IMGDATA->m_alpha;
1702     }
1703    
1704     void wxImage::InitAlpha()
1705     {
1706     wxCHECK_RET( !HasAlpha(), wxT("image already has an alpha channel") );
1707    
1708     // initialize memory for alpha channel
1709     SetAlpha();
1710    
1711     unsigned char *alpha = M_IMGDATA->m_alpha;
1712     const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height;
1713    
1714     if ( HasMask() )
1715     {
1716     // use the mask to initialize the alpha channel.
1717     const unsigned char * const alphaEnd = alpha + lenAlpha;
1718    
1719     const unsigned char mr = M_IMGDATA->m_maskRed;
1720     const unsigned char mg = M_IMGDATA->m_maskGreen;
1721     const unsigned char mb = M_IMGDATA->m_maskBlue;
1722     for ( unsigned char *src = M_IMGDATA->m_data;
1723     alpha < alphaEnd;
1724     src += 3, alpha++ )
1725     {
1726     *alpha = (src[0] == mr && src[1] == mg && src[2] == mb)
1727     ? wxIMAGE_ALPHA_TRANSPARENT
1728     : wxIMAGE_ALPHA_OPAQUE;
1729     }
1730    
1731     M_IMGDATA->m_hasMask = false;
1732     }
1733     else // no mask
1734     {
1735     // make the image fully opaque
1736     memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha);
1737     }
1738     }
1739    
1740     // ----------------------------------------------------------------------------
1741     // mask support
1742     // ----------------------------------------------------------------------------
1743    
1744     void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
1745     {
1746     wxCHECK_RET( Ok(), wxT("invalid image") );
1747    
1748     AllocExclusive();
1749    
1750     M_IMGDATA->m_maskRed = r;
1751     M_IMGDATA->m_maskGreen = g;
1752     M_IMGDATA->m_maskBlue = b;
1753     M_IMGDATA->m_hasMask = true;
1754     }
1755    
1756     bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const
1757     {
1758     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
1759    
1760     if (M_IMGDATA->m_hasMask)
1761     {
1762     if (r) *r = M_IMGDATA->m_maskRed;
1763     if (g) *g = M_IMGDATA->m_maskGreen;
1764     if (b) *b = M_IMGDATA->m_maskBlue;
1765     return true;
1766     }
1767     else
1768     {
1769     FindFirstUnusedColour(r, g, b);
1770     return false;
1771     }
1772     }
1773    
1774     unsigned char wxImage::GetMaskRed() const
1775     {
1776     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
1777    
1778     return M_IMGDATA->m_maskRed;
1779     }
1780    
1781     unsigned char wxImage::GetMaskGreen() const
1782     {
1783     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
1784    
1785     return M_IMGDATA->m_maskGreen;
1786     }
1787    
1788     unsigned char wxImage::GetMaskBlue() const
1789     {
1790     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
1791    
1792     return M_IMGDATA->m_maskBlue;
1793     }
1794    
1795     void wxImage::SetMask( bool mask )
1796     {
1797     wxCHECK_RET( Ok(), wxT("invalid image") );
1798    
1799     AllocExclusive();
1800    
1801     M_IMGDATA->m_hasMask = mask;
1802     }
1803    
1804     bool wxImage::HasMask() const
1805     {
1806     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
1807    
1808     return M_IMGDATA->m_hasMask;
1809     }
1810    
1811     bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const
1812     {
1813     long pos = XYToIndex(x, y);
1814     wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") );
1815    
1816     // check mask
1817     if ( M_IMGDATA->m_hasMask )
1818     {
1819     const unsigned char *p = M_IMGDATA->m_data + 3*pos;
1820     if ( p[0] == M_IMGDATA->m_maskRed &&
1821     p[1] == M_IMGDATA->m_maskGreen &&
1822     p[2] == M_IMGDATA->m_maskBlue )
1823     {
1824     return true;
1825     }
1826     }
1827    
1828     // then check alpha
1829     if ( M_IMGDATA->m_alpha )
1830     {
1831     if ( M_IMGDATA->m_alpha[pos] < threshold )
1832     {
1833     // transparent enough
1834     return true;
1835     }
1836     }
1837    
1838     // not transparent
1839     return false;
1840     }
1841    
1842     bool wxImage::SetMaskFromImage(const wxImage& mask,
1843     unsigned char mr, unsigned char mg, unsigned char mb)
1844     {
1845     // check that the images are the same size
1846     if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) )
1847     {
1848     wxLogError( _("Image and mask have different sizes.") );
1849     return false;
1850     }
1851    
1852     // find unused colour
1853     unsigned char r,g,b ;
1854     if (!FindFirstUnusedColour(&r, &g, &b))
1855     {
1856     wxLogError( _("No unused colour in image being masked.") );
1857     return false ;
1858     }
1859    
1860     AllocExclusive();
1861    
1862     unsigned char *imgdata = GetData();
1863     unsigned char *maskdata = mask.GetData();
1864    
1865     const int w = GetWidth();
1866     const int h = GetHeight();
1867    
1868     for (int j = 0; j < h; j++)
1869     {
1870     for (int i = 0; i < w; i++)
1871     {
1872     if ((maskdata[0] == mr) && (maskdata[1] == mg) && (maskdata[2] == mb))
1873     {
1874     imgdata[0] = r;
1875     imgdata[1] = g;
1876     imgdata[2] = b;
1877     }
1878     imgdata += 3;
1879     maskdata += 3;
1880     }
1881     }
1882    
1883     SetMaskColour(r, g, b);
1884     SetMask(true);
1885    
1886     return true;
1887     }
1888    
1889     bool wxImage::ConvertAlphaToMask(unsigned char threshold)
1890     {
1891     if (!HasAlpha())
1892     return true;
1893    
1894     unsigned char mr, mg, mb;
1895     if (!FindFirstUnusedColour(&mr, &mg, &mb))
1896     {
1897     wxLogError( _("No unused colour in image being masked.") );
1898     return false;
1899     }
1900    
1901     AllocExclusive();
1902    
1903     SetMask(true);
1904     SetMaskColour(mr, mg, mb);
1905    
1906     unsigned char *imgdata = GetData();
1907     unsigned char *alphadata = GetAlpha();
1908    
1909     int w = GetWidth();
1910     int h = GetHeight();
1911    
1912     for (int y = 0; y < h; y++)
1913     {
1914     for (int x = 0; x < w; x++, imgdata += 3, alphadata++)
1915     {
1916     if (*alphadata < threshold)
1917     {
1918     imgdata[0] = mr;
1919     imgdata[1] = mg;
1920     imgdata[2] = mb;
1921     }
1922     }
1923     }
1924    
1925     if( !M_IMGDATA->m_staticAlpha )
1926     free(M_IMGDATA->m_alpha);
1927    
1928     M_IMGDATA->m_alpha = NULL;
1929     M_IMGDATA->m_staticAlpha = false;
1930    
1931     return true;
1932     }
1933    
1934     // ----------------------------------------------------------------------------
1935     // Palette functions
1936     // ----------------------------------------------------------------------------
1937    
1938     #if wxUSE_PALETTE
1939    
1940     bool wxImage::HasPalette() const
1941     {
1942     if (!Ok())
1943     return false;
1944    
1945     return M_IMGDATA->m_palette.Ok();
1946     }
1947    
1948     const wxPalette& wxImage::GetPalette() const
1949     {
1950     wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") );
1951    
1952     return M_IMGDATA->m_palette;
1953     }
1954    
1955     void wxImage::SetPalette(const wxPalette& palette)
1956     {
1957     wxCHECK_RET( Ok(), wxT("invalid image") );
1958    
1959     AllocExclusive();
1960    
1961     M_IMGDATA->m_palette = palette;
1962     }
1963    
1964     #endif // wxUSE_PALETTE
1965    
1966     // ----------------------------------------------------------------------------
1967     // Option functions (arbitrary name/value mapping)
1968     // ----------------------------------------------------------------------------
1969    
1970     void wxImage::SetOption(const wxString& name, const wxString& value)
1971     {
1972     wxCHECK_RET( Ok(), wxT("invalid image") );
1973    
1974     AllocExclusive();
1975    
1976     int idx = M_IMGDATA->m_optionNames.Index(name, false);
1977     if (idx == wxNOT_FOUND)
1978     {
1979     M_IMGDATA->m_optionNames.Add(name);
1980     M_IMGDATA->m_optionValues.Add(value);
1981     }
1982     else
1983     {
1984     M_IMGDATA->m_optionNames[idx] = name;
1985     M_IMGDATA->m_optionValues[idx] = value;
1986     }
1987     }
1988    
1989     void wxImage::SetOption(const wxString& name, int value)
1990     {
1991     wxString valStr;
1992     valStr.Printf(wxT("%d"), value);
1993     SetOption(name, valStr);
1994     }
1995    
1996     wxString wxImage::GetOption(const wxString& name) const
1997     {
1998     wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid image") );
1999    
2000     int idx = M_IMGDATA->m_optionNames.Index(name, false);
2001     if (idx == wxNOT_FOUND)
2002     return wxEmptyString;
2003     else
2004     return M_IMGDATA->m_optionValues[idx];
2005     }
2006    
2007     int wxImage::GetOptionInt(const wxString& name) const
2008     {
2009     return wxAtoi(GetOption(name));
2010     }
2011    
2012     bool wxImage::HasOption(const wxString& name) const
2013     {
2014     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
2015    
2016     return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND);
2017     }
2018    
2019     // ----------------------------------------------------------------------------
2020     // image I/O
2021     // ----------------------------------------------------------------------------
2022    
2023     bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename),
2024     long WXUNUSED_UNLESS_STREAMS(type),
2025     int WXUNUSED_UNLESS_STREAMS(index) )
2026     {
2027     #if HAS_FILE_STREAMS
2028     if (wxFileExists(filename))
2029     {
2030     wxImageFileInputStream stream(filename);
2031     wxBufferedInputStream bstream( stream );
2032     return LoadFile(bstream, type, index);
2033     }
2034     else
2035     {
2036     wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
2037    
2038     return false;
2039     }
2040     #else // !HAS_FILE_STREAMS
2041     return false;
2042     #endif // HAS_FILE_STREAMS
2043     }
2044    
2045     bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename),
2046     const wxString& WXUNUSED_UNLESS_STREAMS(mimetype),
2047     int WXUNUSED_UNLESS_STREAMS(index) )
2048     {
2049     #if HAS_FILE_STREAMS
2050     if (wxFileExists(filename))
2051     {
2052     wxImageFileInputStream stream(filename);
2053     wxBufferedInputStream bstream( stream );
2054     return LoadFile(bstream, mimetype, index);
2055     }
2056     else
2057     {
2058     wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
2059    
2060     return false;
2061     }
2062     #else // !HAS_FILE_STREAMS
2063     return false;
2064     #endif // HAS_FILE_STREAMS
2065     }
2066    
2067    
2068    
2069     bool wxImage::SaveFile( const wxString& filename ) const
2070     {
2071     wxString ext = filename.AfterLast('.').Lower();
2072    
2073     wxImageHandler * pHandler = FindHandler(ext, -1);
2074     if (pHandler)
2075     {
2076     return SaveFile(filename, pHandler->GetType());
2077     }
2078    
2079     wxLogError(_("Can't save image to file '%s': unknown extension."), filename.c_str());
2080    
2081     return false;
2082     }
2083    
2084     bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename),
2085     int WXUNUSED_UNLESS_STREAMS(type) ) const
2086     {
2087     #if HAS_FILE_STREAMS
2088     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
2089    
2090     ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
2091    
2092     wxImageFileOutputStream stream(filename);
2093    
2094     if ( stream.IsOk() )
2095     {
2096     wxBufferedOutputStream bstream( stream );
2097     return SaveFile(bstream, type);
2098     }
2099     #endif // HAS_FILE_STREAMS
2100    
2101     return false;
2102     }
2103    
2104     bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename),
2105     const wxString& WXUNUSED_UNLESS_STREAMS(mimetype) ) const
2106     {
2107     #if HAS_FILE_STREAMS
2108     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
2109    
2110     ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
2111    
2112     wxImageFileOutputStream stream(filename);
2113    
2114     if ( stream.IsOk() )
2115     {
2116     wxBufferedOutputStream bstream( stream );
2117     return SaveFile(bstream, mimetype);
2118     }
2119     #endif // HAS_FILE_STREAMS
2120    
2121     return false;
2122     }
2123    
2124     bool wxImage::CanRead( const wxString& WXUNUSED_UNLESS_STREAMS(name) )
2125     {
2126     #if HAS_FILE_STREAMS
2127     wxImageFileInputStream stream(name);
2128     return CanRead(stream);
2129     #else
2130     return false;
2131     #endif
2132     }
2133    
2134     int wxImage::GetImageCount( const wxString& WXUNUSED_UNLESS_STREAMS(name),
2135     long WXUNUSED_UNLESS_STREAMS(type) )
2136     {
2137     #if HAS_FILE_STREAMS
2138     wxImageFileInputStream stream(name);
2139     if (stream.Ok())
2140     return GetImageCount(stream, type);
2141     #endif
2142    
2143     return 0;
2144     }
2145    
2146     #if wxUSE_STREAMS
2147    
2148     bool wxImage::CanRead( wxInputStream &stream )
2149     {
2150     const wxList& list = GetHandlers();
2151    
2152     for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() )
2153     {
2154     wxImageHandler *handler=(wxImageHandler*)node->GetData();
2155     if (handler->CanRead( stream ))
2156     return true;
2157     }
2158    
2159     return false;
2160     }
2161    
2162     int wxImage::GetImageCount( wxInputStream &stream, long type )
2163     {
2164     wxImageHandler *handler;
2165    
2166     if ( type == wxBITMAP_TYPE_ANY )
2167     {
2168     wxList &list=GetHandlers();
2169    
2170     for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
2171     {
2172     handler=(wxImageHandler*)node->GetData();
2173     if ( handler->CanRead(stream) )
2174     return handler->GetImageCount(stream);
2175    
2176     }
2177    
2178     wxLogWarning(_("No handler found for image type."));
2179     return 0;
2180     }
2181    
2182     handler = FindHandler(type);
2183    
2184     if ( !handler )
2185     {
2186     wxLogWarning(_("No image handler for type %ld defined."), type);
2187     return false;
2188     }
2189    
2190     if ( handler->CanRead(stream) )
2191     {
2192     return handler->GetImageCount(stream);
2193     }
2194     else
2195     {
2196     wxLogError(_("Image file is not of type %ld."), type);
2197     return 0;
2198     }
2199     }
2200    
2201     bool wxImage::LoadFile( wxInputStream& stream, long type, int index )
2202     {
2203     UnRef();
2204    
2205     m_refData = new wxImageRefData;
2206    
2207     wxImageHandler *handler;
2208    
2209     if ( type == wxBITMAP_TYPE_ANY )
2210     {
2211     wxList &list=GetHandlers();
2212    
2213     for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() )
2214     {
2215     handler=(wxImageHandler*)node->GetData();
2216     if ( handler->CanRead(stream) )
2217     return handler->LoadFile(this, stream, true/*verbose*/, index);
2218    
2219     }
2220    
2221     wxLogWarning( _("No handler found for image type.") );
2222     return false;
2223     }
2224    
2225     handler = FindHandler(type);
2226    
2227     if (handler == 0)
2228     {
2229     wxLogWarning( _("No image handler for type %ld defined."), type );
2230    
2231     return false;
2232     }
2233    
2234     if (stream.IsSeekable() && !handler->CanRead(stream))
2235     {
2236     wxLogError(_("Image file is not of type %ld."), type);
2237     return false;
2238     }
2239     else
2240     return handler->LoadFile(this, stream, true/*verbose*/, index);
2241     }
2242    
2243     bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index )
2244     {
2245     UnRef();
2246    
2247     m_refData = new wxImageRefData;
2248    
2249     wxImageHandler *handler = FindHandlerMime(mimetype);
2250    
2251     if (handler == 0)
2252     {
2253     wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
2254    
2255     return false;
2256     }
2257    
2258     if (stream.IsSeekable() && !handler->CanRead(stream))
2259     {
2260     wxLogError(_("Image file is not of type %s."), (const wxChar*) mimetype);
2261     return false;
2262     }
2263     else
2264     return handler->LoadFile( this, stream, true/*verbose*/, index );
2265     }
2266    
2267     bool wxImage::SaveFile( wxOutputStream& stream, int type ) const
2268     {
2269     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
2270    
2271     wxImageHandler *handler = FindHandler(type);
2272     if ( !handler )
2273     {
2274     wxLogWarning( _("No image handler for type %d defined."), type );
2275    
2276     return false;
2277     }
2278    
2279     return handler->SaveFile( (wxImage*)this, stream );
2280     }
2281    
2282     bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const
2283     {
2284     wxCHECK_MSG( Ok(), false, wxT("invalid image") );
2285    
2286     wxImageHandler *handler = FindHandlerMime(mimetype);
2287     if ( !handler )
2288     {
2289     wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
2290    
2291     return false;
2292     }
2293    
2294     return handler->SaveFile( (wxImage*)this, stream );
2295     }
2296     #endif // wxUSE_STREAMS
2297    
2298     // ----------------------------------------------------------------------------
2299     // image I/O handlers
2300     // ----------------------------------------------------------------------------
2301    
2302     void wxImage::AddHandler( wxImageHandler *handler )
2303     {
2304     // Check for an existing handler of the type being added.
2305     if (FindHandler( handler->GetType() ) == 0)
2306     {
2307     sm_handlers.Append( handler );
2308     }
2309     else
2310     {
2311     // This is not documented behaviour, merely the simplest 'fix'
2312     // for preventing duplicate additions. If someone ever has
2313     // a good reason to add and remove duplicate handlers (and they
2314     // may) we should probably refcount the duplicates.
2315     // also an issue in InsertHandler below.
2316    
2317     wxLogDebug( _T("Adding duplicate image handler for '%s'"),
2318     handler->GetName().c_str() );
2319     delete handler;
2320     }
2321     }
2322    
2323     void wxImage::InsertHandler( wxImageHandler *handler )
2324     {
2325     // Check for an existing handler of the type being added.
2326     if (FindHandler( handler->GetType() ) == 0)
2327     {
2328     sm_handlers.Insert( handler );
2329     }
2330     else
2331     {
2332     // see AddHandler for additional comments.
2333     wxLogDebug( _T("Inserting duplicate image handler for '%s'"),
2334     handler->GetName().c_str() );
2335     delete handler;
2336     }
2337     }
2338    
2339     bool wxImage::RemoveHandler( const wxString& name )
2340     {
2341     wxImageHandler *handler = FindHandler(name);
2342     if (handler)
2343     {
2344     sm_handlers.DeleteObject(handler);
2345     delete handler;
2346     return true;
2347     }
2348     else
2349     return false;
2350     }
2351    
2352     wxImageHandler *wxImage::FindHandler( const wxString& name )
2353     {
2354     wxList::compatibility_iterator node = sm_handlers.GetFirst();
2355     while (node)
2356     {
2357     wxImageHandler *handler = (wxImageHandler*)node->GetData();
2358     if (handler->GetName().Cmp(name) == 0) return handler;
2359    
2360     node = node->GetNext();
2361     }
2362     return 0;
2363     }
2364    
2365     wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
2366     {
2367     wxList::compatibility_iterator node = sm_handlers.GetFirst();
2368     while (node)
2369     {
2370     wxImageHandler *handler = (wxImageHandler*)node->GetData();
2371     if ( (handler->GetExtension().Cmp(extension) == 0) &&
2372     (bitmapType == -1 || handler->GetType() == bitmapType) )
2373     return handler;
2374     node = node->GetNext();
2375     }
2376     return 0;
2377     }
2378    
2379     wxImageHandler *wxImage::FindHandler( long bitmapType )
2380     {
2381     wxList::compatibility_iterator node = sm_handlers.GetFirst();
2382     while (node)
2383     {
2384     wxImageHandler *handler = (wxImageHandler *)node->GetData();
2385     if (handler->GetType() == bitmapType) return handler;
2386     node = node->GetNext();
2387     }
2388     return 0;
2389     }
2390    
2391     wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
2392     {
2393     wxList::compatibility_iterator node = sm_handlers.GetFirst();
2394     while (node)
2395     {
2396     wxImageHandler *handler = (wxImageHandler *)node->GetData();
2397     if (handler->GetMimeType().IsSameAs(mimetype, false)) return handler;
2398     node = node->GetNext();
2399     }
2400     return 0;
2401     }
2402    
2403     void wxImage::InitStandardHandlers()
2404     {
2405     #if wxUSE_STREAMS
2406     AddHandler(new wxBMPHandler);
2407     #endif // wxUSE_STREAMS
2408     }
2409    
2410     void wxImage::CleanUpHandlers()
2411     {
2412     wxList::compatibility_iterator node = sm_handlers.GetFirst();
2413     while (node)
2414     {
2415     wxImageHandler *handler = (wxImageHandler *)node->GetData();
2416     wxList::compatibility_iterator next = node->GetNext();
2417     delete handler;
2418     node = next;
2419     }
2420    
2421     sm_handlers.Clear();
2422     }
2423    
2424     wxString wxImage::GetImageExtWildcard()
2425     {
2426     wxString fmts;
2427    
2428     wxList& Handlers = wxImage::GetHandlers();
2429     wxList::compatibility_iterator Node = Handlers.GetFirst();
2430     while ( Node )
2431     {
2432     wxImageHandler* Handler = (wxImageHandler*)Node->GetData();
2433     fmts += wxT("*.") + Handler->GetExtension();
2434     Node = Node->GetNext();
2435     if ( Node ) fmts += wxT(";");
2436     }
2437    
2438     return wxT("(") + fmts + wxT(")|") + fmts;
2439     }
2440    
2441     wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb)
2442     {
2443     const double red = rgb.red / 255.0,
2444     green = rgb.green / 255.0,
2445     blue = rgb.blue / 255.0;
2446    
2447     // find the min and max intensity (and remember which one was it for the
2448     // latter)
2449     double minimumRGB = red;
2450     if ( green < minimumRGB )
2451     minimumRGB = green;
2452     if ( blue < minimumRGB )
2453     minimumRGB = blue;
2454    
2455     enum { RED, GREEN, BLUE } chMax = RED;
2456     double maximumRGB = red;
2457     if ( green > maximumRGB )
2458     {
2459     chMax = GREEN;
2460     maximumRGB = green;
2461     }
2462     if ( blue > maximumRGB )
2463     {
2464     chMax = BLUE;
2465     maximumRGB = blue;
2466     }
2467    
2468     const double value = maximumRGB;
2469    
2470     double hue = 0.0, saturation;
2471     const double deltaRGB = maximumRGB - minimumRGB;
2472     if ( wxIsNullDouble(deltaRGB) )
2473     {
2474     // Gray has no color
2475     hue = 0.0;
2476     saturation = 0.0;
2477     }
2478     else
2479     {
2480     switch ( chMax )
2481     {
2482     case RED:
2483     hue = (green - blue) / deltaRGB;
2484     break;
2485    
2486     case GREEN:
2487     hue = 2.0 + (blue - red) / deltaRGB;
2488     break;
2489    
2490     case BLUE:
2491     hue = 4.0 + (red - green) / deltaRGB;
2492     break;
2493    
2494     default:
2495     wxFAIL_MSG(wxT("hue not specified"));
2496     break;
2497     }
2498    
2499     hue /= 6.0;
2500    
2501     if ( hue < 0.0 )
2502     hue += 1.0;
2503    
2504     saturation = deltaRGB / maximumRGB;
2505     }
2506    
2507     return HSVValue(hue, saturation, value);
2508     }
2509    
2510     wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv)
2511     {
2512     double red, green, blue;
2513    
2514     if ( wxIsNullDouble(hsv.saturation) )
2515     {
2516     // Grey
2517     red = hsv.value;
2518     green = hsv.value;
2519     blue = hsv.value;
2520     }
2521     else // not grey
2522     {
2523     double hue = hsv.hue * 6.0; // sector 0 to 5
2524     int i = (int)floor(hue);
2525     double f = hue - i; // fractional part of h
2526     double p = hsv.value * (1.0 - hsv.saturation);
2527    
2528     switch (i)
2529     {
2530     case 0:
2531     red = hsv.value;
2532     green = hsv.value * (1.0 - hsv.saturation * (1.0 - f));
2533     blue = p;
2534     break;
2535    
2536     case 1:
2537     red = hsv.value * (1.0 - hsv.saturation * f);
2538     green = hsv.value;
2539     blue = p;
2540     break;
2541    
2542     case 2:
2543     red = p;
2544     green = hsv.value;
2545     blue = hsv.value * (1.0 - hsv.saturation * (1.0 - f));
2546     break;
2547    
2548     case 3:
2549     red = p;
2550     green = hsv.value * (1.0 - hsv.saturation * f);
2551     blue = hsv.value;
2552     break;
2553    
2554     case 4:
2555     red = hsv.value * (1.0 - hsv.saturation * (1.0 - f));
2556     green = p;
2557     blue = hsv.value;
2558     break;
2559    
2560     default: // case 5:
2561     red = hsv.value;
2562     green = p;
2563     blue = hsv.value * (1.0 - hsv.saturation * f);
2564     break;
2565     }
2566     }
2567    
2568     return RGBValue((unsigned char)(red * 255.0),
2569     (unsigned char)(green * 255.0),
2570     (unsigned char)(blue * 255.0));
2571     }
2572    
2573     /*
2574     * Rotates the hue of each pixel of the image. angle is a double in the range
2575     * -1.0..1.0 where -1.0 is -360 degrees and 1.0 is 360 degrees
2576     */
2577     void wxImage::RotateHue(double angle)
2578     {