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