1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "image.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  26 #include "wx/bitmap.h" 
  30 #include "wx/filefn.h" 
  31 #include "wx/wfstream.h" 
  33 #include "wx/module.h" 
  45 //----------------------------------------------------------------------------- 
  47 //----------------------------------------------------------------------------- 
  49 class wxImageRefData
: public wxObjectRefData
 
  53     virtual ~wxImageRefData(); 
  57     unsigned char  *m_data
; 
  60     unsigned char   m_maskRed
,m_maskGreen
,m_maskBlue
; 
  62     // alpha channel data, may be NULL for the formats without alpha support 
  63     unsigned char  *m_alpha
; 
  70 #endif // wxUSE_PALETTE 
  72     wxArrayString   m_optionNames
; 
  73     wxArrayString   m_optionValues
; 
  75     DECLARE_NO_COPY_CLASS(wxImageRefData
) 
  78 wxImageRefData::wxImageRefData() 
  83     m_alpha 
= (unsigned char *) NULL
; 
  94 wxImageRefData::~wxImageRefData() 
 102 wxList 
wxImage::sm_handlers
; 
 106 //----------------------------------------------------------------------------- 
 108 #define M_IMGDATA ((wxImageRefData *)m_refData) 
 110 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
) 
 116 wxImage::wxImage( int width
, int height
, bool clear 
) 
 118     Create( width
, height
, clear 
); 
 121 wxImage::wxImage( int width
, int height
, unsigned char* data
, bool static_data 
) 
 123     Create( width
, height
, data
, static_data 
); 
 126 wxImage::wxImage( const wxString
& name
, long type
, int index 
) 
 128     LoadFile( name
, type
, index 
); 
 131 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
, int index 
) 
 133     LoadFile( name
, mimetype
, index 
); 
 137 wxImage::wxImage( wxInputStream
& stream
, long type
, int index 
) 
 139     LoadFile( stream
, type
, index 
); 
 142 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
, int index 
) 
 144     LoadFile( stream
, mimetype
, index 
); 
 146 #endif // wxUSE_STREAMS 
 148 wxImage::wxImage( const wxImage
& image 
) 
 154 wxImage::wxImage( const wxImage
* image 
) 
 156     if (image
) Ref(*image
); 
 159 void wxImage::Create( int width
, int height
, bool clear 
) 
 163     m_refData 
= new wxImageRefData(); 
 165     M_IMGDATA
->m_data 
= (unsigned char *) malloc( width
*height
*3 ); 
 166     if (M_IMGDATA
->m_data
) 
 168         if (clear
) memset(M_IMGDATA
->m_data
, 0, width
*height
*3); 
 170         M_IMGDATA
->m_width 
= width
; 
 171         M_IMGDATA
->m_height 
= height
; 
 172         M_IMGDATA
->m_ok 
= TRUE
; 
 180 void wxImage::Create( int width
, int height
, unsigned char* data
, bool static_data 
) 
 184     m_refData 
= new wxImageRefData(); 
 186     M_IMGDATA
->m_data 
= data
; 
 187     if (M_IMGDATA
->m_data
) 
 189         M_IMGDATA
->m_width 
= width
; 
 190         M_IMGDATA
->m_height 
= height
; 
 191         M_IMGDATA
->m_ok 
= TRUE
; 
 192         M_IMGDATA
->m_static 
= static_data
; 
 200 void wxImage::Destroy() 
 205 wxImage 
wxImage::Copy() const 
 209     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 211     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
, false ); 
 213     unsigned char *data 
= image
.GetData(); 
 215     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 217     image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 218     image
.SetMask( M_IMGDATA
->m_hasMask 
); 
 220     memcpy( data
, GetData(), M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3 ); 
 225 wxImage 
wxImage::ShrinkBy( int xFactor 
, int yFactor 
) const 
 227     if( xFactor 
== 1 && yFactor 
== 1 ) 
 232     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 234     // can't scale to/from 0 size 
 235     wxCHECK_MSG( (xFactor 
> 0) && (yFactor 
> 0), image
, 
 236                  wxT("invalid new image size") ); 
 238     long old_height 
= M_IMGDATA
->m_height
, 
 239          old_width  
= M_IMGDATA
->m_width
; 
 241     wxCHECK_MSG( (old_height 
> 0) && (old_width 
> 0), image
, 
 242                  wxT("invalid old image size") ); 
 244     long width 
= old_width 
/ xFactor 
; 
 245     long height 
= old_height 
/ yFactor 
; 
 247     image
.Create( width
, height
, false ); 
 249     char unsigned *data 
= image
.GetData(); 
 251     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 253     bool hasMask 
= false ; 
 254     unsigned char maskRed 
= 0; 
 255     unsigned char maskGreen 
= 0; 
 256     unsigned char maskBlue 
=0 ; 
 257     if (M_IMGDATA
->m_hasMask
) 
 260         maskRed 
= M_IMGDATA
->m_maskRed
; 
 261         maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 262         maskBlue 
=M_IMGDATA
->m_maskBlue 
; 
 264         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, 
 265                              M_IMGDATA
->m_maskGreen
, 
 266                              M_IMGDATA
->m_maskBlue 
); 
 268     char unsigned *source_data 
= M_IMGDATA
->m_data
; 
 269     char unsigned *target_data 
= data
; 
 271     for (long y 
= 0; y 
< height
; y
++) 
 273         for (long x 
= 0; x 
< width
; x
++) 
 275             unsigned long avgRed 
= 0 ; 
 276             unsigned long avgGreen 
= 0; 
 277             unsigned long avgBlue 
= 0; 
 278             unsigned long counter 
= 0 ; 
 280             for ( int y1 
= 0 ; y1 
< yFactor 
; ++y1 
) 
 282                 long y_offset 
= (y 
* yFactor 
+ y1
) * old_width
; 
 283                 for ( int x1 
= 0 ; x1 
< xFactor 
; ++x1 
) 
 285                     unsigned char *pixel 
= source_data 
+ 3 * ( y_offset 
+ x 
* xFactor 
+ x1 
) ; 
 286                     unsigned char red 
= pixel
[0] ; 
 287                     unsigned char green 
= pixel
[1] ; 
 288                     unsigned char blue 
= pixel
[2] ; 
 289                     if ( !hasMask 
|| red 
!= maskRed 
|| green 
!= maskGreen 
|| blue 
!= maskBlue 
) 
 300                 *(target_data
++) = M_IMGDATA
->m_maskRed 
; 
 301                 *(target_data
++) = M_IMGDATA
->m_maskGreen 
; 
 302                 *(target_data
++) = M_IMGDATA
->m_maskBlue 
; 
 306                 *(target_data
++) = avgRed 
/ counter 
; 
 307                 *(target_data
++) = avgGreen 
/ counter 
; 
 308                 *(target_data
++) = avgBlue 
/ counter 
; 
 313     // In case this is a cursor, make sure the hotspot is scalled accordingly: 
 314     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
) ) 
 315         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
, 
 316                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
))/xFactor
); 
 317     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
) ) 
 318         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
, 
 319                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))/yFactor
); 
 324 wxImage 
wxImage::Scale( int width
, int height 
) const 
 328     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 330     // can't scale to/from 0 size 
 331     wxCHECK_MSG( (width 
> 0) && (height 
> 0), image
, 
 332                  wxT("invalid new image size") ); 
 334     long old_height 
= M_IMGDATA
->m_height
, 
 335          old_width  
= M_IMGDATA
->m_width
; 
 336     wxCHECK_MSG( (old_height 
> 0) && (old_width 
> 0), image
, 
 337                  wxT("invalid old image size") ); 
 339     if ( old_width 
% width 
== 0 && old_width 
>= width 
&& 
 340         old_height 
% height 
== 0 && old_height 
>= height 
) 
 342         return ShrinkBy( old_width 
/ width 
, old_height 
/ height 
) ; 
 344     image
.Create( width
, height
, false ); 
 346     unsigned char *data 
= image
.GetData(); 
 348     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 350     if (M_IMGDATA
->m_hasMask
) 
 352         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, 
 353                              M_IMGDATA
->m_maskGreen
, 
 354                              M_IMGDATA
->m_maskBlue 
); 
 357     unsigned char *source_data 
= M_IMGDATA
->m_data
; 
 358     unsigned char *target_data 
= data
; 
 360     long x_delta 
= (old_width
<<16) / width
; 
 361     long y_delta 
= (old_height
<<16) / height
; 
 363     unsigned char* dest_pixel 
= target_data
; 
 366     for ( long j 
= 0; j 
< height
; j
++ ) 
 368         unsigned char* src_line 
= &source_data
[(y
>>16)*old_width
*3]; 
 371         for ( long i 
= 0; i 
< width
; i
++ ) 
 373              unsigned char* src_pixel 
= &src_line
[(x
>>16)*3]; 
 374              dest_pixel
[0] = src_pixel
[0]; 
 375              dest_pixel
[1] = src_pixel
[1]; 
 376              dest_pixel
[2] = src_pixel
[2]; 
 384     // In case this is a cursor, make sure the hotspot is scalled accordingly: 
 385     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
) ) 
 386         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
, 
 387                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
)*width
)/old_width
); 
 388     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
) ) 
 389         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
, 
 390                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)*height
)/old_height
); 
 395 wxImage 
wxImage::Rotate90( bool clockwise 
) const 
 399     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 401     image
.Create( M_IMGDATA
->m_height
, M_IMGDATA
->m_width
, false ); 
 403     unsigned char *data 
= image
.GetData(); 
 405     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 407     if (M_IMGDATA
->m_hasMask
) 
 408         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 410     long height 
= M_IMGDATA
->m_height
; 
 411     long width  
= M_IMGDATA
->m_width
; 
 413     unsigned char *source_data 
= M_IMGDATA
->m_data
; 
 414     unsigned char *target_data
; 
 416     for (long j 
= 0; j 
< height
; j
++) 
 418         for (long i 
= 0; i 
< width
; i
++) 
 421                 target_data 
= data 
+ (((i
+1)*height
) - j 
- 1)*3; 
 423                 target_data 
= data 
+ ((height
*(width
-1)) + j 
- (i
*height
))*3; 
 424             memcpy( target_data
, source_data
, 3 ); 
 432 wxImage 
wxImage::Mirror( bool horizontally 
) const 
 436     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 438     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
, false ); 
 440     unsigned char *data 
= image
.GetData(); 
 442     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 444     if (M_IMGDATA
->m_hasMask
) 
 445         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 447     long height 
= M_IMGDATA
->m_height
; 
 448     long width  
= M_IMGDATA
->m_width
; 
 450     unsigned char *source_data 
= M_IMGDATA
->m_data
; 
 451     unsigned char *target_data
; 
 455         for (long j 
= 0; j 
< height
; j
++) 
 458             target_data 
= data
-3; 
 459             for (long i 
= 0; i 
< width
; i
++) 
 461                 memcpy( target_data
, source_data
, 3 ); 
 469         for (long i 
= 0; i 
< height
; i
++) 
 471             target_data 
= data 
+ 3*width
*(height
-1-i
); 
 472             memcpy( target_data
, source_data
, (size_t)3*width 
); 
 473             source_data 
+= 3*width
; 
 480 wxImage 
wxImage::GetSubImage( const wxRect 
&rect 
) const 
 484     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 486     wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()), 
 487                  image
, wxT("invalid subimage size") ); 
 489     int subwidth
=rect
.GetWidth(); 
 490     const int subheight
=rect
.GetHeight(); 
 492     image
.Create( subwidth
, subheight
, false ); 
 494     unsigned char *subdata 
= image
.GetData(), *data
=GetData(); 
 496     wxCHECK_MSG( subdata
, image
, wxT("unable to create image") ); 
 498     if (M_IMGDATA
->m_hasMask
) 
 499         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 501     const int subleft
=3*rect
.GetLeft(); 
 502     const int width
=3*GetWidth(); 
 505     data
+=rect
.GetTop()*width
+subleft
; 
 507     for (long j 
= 0; j 
< subheight
; ++j
) 
 509         memcpy( subdata
, data
, subwidth
); 
 517 void wxImage::Paste( const wxImage 
&image
, int x
, int y 
) 
 519     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 520     wxCHECK_RET( image
.Ok(), wxT("invalid image") ); 
 524     int width 
= image
.GetWidth(); 
 525     int height 
= image
.GetHeight(); 
 538     if ((x
+xx
)+width 
> M_IMGDATA
->m_width
) 
 539         width 
= M_IMGDATA
->m_width 
- (x
+xx
); 
 540     if ((y
+yy
)+height 
> M_IMGDATA
->m_height
) 
 541         height 
= M_IMGDATA
->m_height 
- (y
+yy
); 
 543     if (width 
< 1) return; 
 544     if (height 
< 1) return; 
 546     if ((!HasMask() && !image
.HasMask()) || 
 547        ((HasMask() && image
.HasMask() && 
 548          (GetMaskRed()==image
.GetMaskRed()) && 
 549          (GetMaskGreen()==image
.GetMaskGreen()) && 
 550          (GetMaskBlue()==image
.GetMaskBlue())))) 
 553         unsigned char* source_data 
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth(); 
 554         int source_step 
= image
.GetWidth()*3; 
 556         unsigned char* target_data 
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
; 
 557         int target_step 
= M_IMGDATA
->m_width
*3; 
 558         for (int j 
= 0; j 
< height
; j
++) 
 560             memcpy( target_data
, source_data
, width 
); 
 561             source_data 
+= source_step
; 
 562             target_data 
+= target_step
; 
 567     if (!HasMask() && image
.HasMask()) 
 569         unsigned char r 
= image
.GetMaskRed(); 
 570         unsigned char g 
= image
.GetMaskGreen(); 
 571         unsigned char b 
= image
.GetMaskBlue(); 
 574         unsigned char* source_data 
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth(); 
 575         int source_step 
= image
.GetWidth()*3; 
 577         unsigned char* target_data 
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
; 
 578         int target_step 
= M_IMGDATA
->m_width
*3; 
 580         for (int j 
= 0; j 
< height
; j
++) 
 582             for (int i 
= 0; i 
< width
; i
+=3) 
 584                 if ((source_data
[i
]   != r
) && 
 585                     (source_data
[i
+1] != g
) && 
 586                     (source_data
[i
+2] != b
)) 
 588                     memcpy( target_data
+i
, source_data
+i
, 3 ); 
 591             source_data 
+= source_step
; 
 592             target_data 
+= target_step
; 
 597 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
, 
 598                        unsigned char r2
, unsigned char g2
, unsigned char b2 
) 
 600     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 602     unsigned char *data 
= GetData(); 
 604     const int w 
= GetWidth(); 
 605     const int h 
= GetHeight(); 
 607     for (int j 
= 0; j 
< h
; j
++) 
 608         for (int i 
= 0; i 
< w
; i
++) 
 610             if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
)) 
 620 wxImage 
wxImage::ConvertToMono( unsigned char r
, unsigned char g
, unsigned char b 
) const 
 624     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 626     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
, false ); 
 628     unsigned char *data 
= image
.GetData(); 
 630     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 632     if (M_IMGDATA
->m_hasMask
) 
 634         if (M_IMGDATA
->m_maskRed 
== r 
&& M_IMGDATA
->m_maskGreen 
== g 
&& 
 635                                          M_IMGDATA
->m_maskBlue 
== b
) 
 636             image
.SetMaskColour( 255, 255, 255 ); 
 638             image
.SetMaskColour( 0, 0, 0 ); 
 641     long size 
= M_IMGDATA
->m_height 
* M_IMGDATA
->m_width
; 
 643     unsigned char *srcd 
= M_IMGDATA
->m_data
; 
 644     unsigned char *tard 
= image
.GetData(); 
 646     for ( long i 
= 0; i 
< size
; i
++, srcd 
+= 3, tard 
+= 3 ) 
 648         if (srcd
[0] == r 
&& srcd
[1] == g 
&& srcd
[2] == b
) 
 649             tard
[0] = tard
[1] = tard
[2] = 255; 
 651             tard
[0] = tard
[1] = tard
[2] = 0; 
 657 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b 
) 
 659     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 661     int w 
= M_IMGDATA
->m_width
; 
 662     int h 
= M_IMGDATA
->m_height
; 
 664     wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") ); 
 666     long pos 
= (y 
* w 
+ x
) * 3; 
 668     M_IMGDATA
->m_data
[ pos   
] = r
; 
 669     M_IMGDATA
->m_data
[ pos
+1 ] = g
; 
 670     M_IMGDATA
->m_data
[ pos
+2 ] = b
; 
 673 unsigned char wxImage::GetRed( int x
, int y 
) const 
 675     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 677     int w 
= M_IMGDATA
->m_width
; 
 678     int h 
= M_IMGDATA
->m_height
; 
 680     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 682     long pos 
= (y 
* w 
+ x
) * 3; 
 684     return M_IMGDATA
->m_data
[pos
]; 
 687 unsigned char wxImage::GetGreen( int x
, int y 
) const 
 689     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 691     int w 
= M_IMGDATA
->m_width
; 
 692     int h 
= M_IMGDATA
->m_height
; 
 694     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 696     long pos 
= (y 
* w 
+ x
) * 3; 
 698     return M_IMGDATA
->m_data
[pos
+1]; 
 701 unsigned char wxImage::GetBlue( int x
, int y 
) const 
 703     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 705     int w 
= M_IMGDATA
->m_width
; 
 706     int h 
= M_IMGDATA
->m_height
; 
 708     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 710     long pos 
= (y 
* w 
+ x
) * 3; 
 712     return M_IMGDATA
->m_data
[pos
+2]; 
 715 bool wxImage::Ok() const 
 717     // image of 0 width or height can't be considered ok - at least because it 
 718     // causes crashes in ConvertToBitmap() if we don't catch it in time 
 719     wxImageRefData 
*data 
= M_IMGDATA
; 
 720     return data 
&& data
->m_ok 
&& data
->m_width 
&& data
->m_height
; 
 723 unsigned char *wxImage::GetData() const 
 725     wxCHECK_MSG( Ok(), (unsigned char *)NULL
, wxT("invalid image") ); 
 727     return M_IMGDATA
->m_data
; 
 730 void wxImage::SetData( unsigned char *data 
) 
 732     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 734     wxImageRefData 
*newRefData 
= new wxImageRefData(); 
 736     newRefData
->m_width 
= M_IMGDATA
->m_width
; 
 737     newRefData
->m_height 
= M_IMGDATA
->m_height
; 
 738     newRefData
->m_data 
= data
; 
 739     newRefData
->m_ok 
= TRUE
; 
 740     newRefData
->m_maskRed 
= M_IMGDATA
->m_maskRed
; 
 741     newRefData
->m_maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 742     newRefData
->m_maskBlue 
= M_IMGDATA
->m_maskBlue
; 
 743     newRefData
->m_hasMask 
= M_IMGDATA
->m_hasMask
; 
 747     m_refData 
= newRefData
; 
 750 void wxImage::SetData( unsigned char *data
, int new_width
, int new_height 
) 
 752     wxImageRefData 
*newRefData 
= new wxImageRefData(); 
 756         newRefData
->m_width 
= new_width
; 
 757         newRefData
->m_height 
= new_height
; 
 758         newRefData
->m_data 
= data
; 
 759         newRefData
->m_ok 
= TRUE
; 
 760         newRefData
->m_maskRed 
= M_IMGDATA
->m_maskRed
; 
 761         newRefData
->m_maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 762         newRefData
->m_maskBlue 
= M_IMGDATA
->m_maskBlue
; 
 763         newRefData
->m_hasMask 
= M_IMGDATA
->m_hasMask
; 
 767         newRefData
->m_width 
= new_width
; 
 768         newRefData
->m_height 
= new_height
; 
 769         newRefData
->m_data 
= data
; 
 770         newRefData
->m_ok 
= TRUE
; 
 775     m_refData 
= newRefData
; 
 778 // ---------------------------------------------------------------------------- 
 779 // alpha channel support 
 780 // ---------------------------------------------------------------------------- 
 782 void wxImage::SetAlpha(int x
, int y
, unsigned char alpha
) 
 784     wxCHECK_RET( Ok() && HasAlpha(), wxT("invalid image or no alpha channel") ); 
 786     int w 
= M_IMGDATA
->m_width
, 
 787         h 
= M_IMGDATA
->m_height
; 
 789     wxCHECK_RET( x 
>=0 && y 
>= 0 && x 
< w 
&& y 
< h
, wxT("invalid image index") ); 
 791     M_IMGDATA
->m_alpha
[y
*w 
+ x
] = alpha
; 
 794 unsigned char wxImage::GetAlpha(int x
, int y
) 
 796     wxCHECK_MSG( Ok() && HasAlpha(), 0, wxT("invalid image or no alpha channel") ); 
 798     int w 
= M_IMGDATA
->m_width
, 
 799         h 
= M_IMGDATA
->m_height
; 
 801     wxCHECK_MSG( x 
>=0 && y 
>= 0 && x 
< w 
&& y 
< h
, 0, wxT("invalid image index") ); 
 803     return M_IMGDATA
->m_alpha
[y
*w 
+ x
]; 
 806 void wxImage::SetAlpha( unsigned char *alpha 
) 
 808     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 812         alpha 
= (unsigned char *) 
 813                     malloc(M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3); 
 816     delete [] M_IMGDATA
->m_alpha
; 
 817     M_IMGDATA
->m_alpha 
= alpha
; 
 820 unsigned char *wxImage::GetAlpha() const 
 822     wxCHECK_MSG( Ok(), (unsigned char *)NULL
, wxT("invalid image") ); 
 824     return M_IMGDATA
->m_alpha
; 
 827 // ---------------------------------------------------------------------------- 
 829 // ---------------------------------------------------------------------------- 
 831 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b 
) 
 833     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 835     M_IMGDATA
->m_maskRed 
= r
; 
 836     M_IMGDATA
->m_maskGreen 
= g
; 
 837     M_IMGDATA
->m_maskBlue 
= b
; 
 838     M_IMGDATA
->m_hasMask 
= TRUE
; 
 841 unsigned char wxImage::GetMaskRed() const 
 843     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 845     return M_IMGDATA
->m_maskRed
; 
 848 unsigned char wxImage::GetMaskGreen() const 
 850     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 852     return M_IMGDATA
->m_maskGreen
; 
 855 unsigned char wxImage::GetMaskBlue() const 
 857     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 859     return M_IMGDATA
->m_maskBlue
; 
 862 void wxImage::SetMask( bool mask 
) 
 864     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 866     M_IMGDATA
->m_hasMask 
= mask
; 
 869 bool wxImage::HasMask() const 
 871     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
 873     return M_IMGDATA
->m_hasMask
; 
 876 int wxImage::GetWidth() const 
 878     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 880     return M_IMGDATA
->m_width
; 
 883 int wxImage::GetHeight() const 
 885     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 887     return M_IMGDATA
->m_height
; 
 890 bool wxImage::SetMaskFromImage(const wxImage
& mask
, 
 891                                unsigned char mr
, unsigned char mg
, unsigned char mb
) 
 893     // check that the images are the same size 
 894     if ( (M_IMGDATA
->m_height 
!= mask
.GetHeight() ) || (M_IMGDATA
->m_width 
!= mask
.GetWidth () ) ) 
 896         wxLogError( _("Image and Mask have different sizes") ); 
 900     // find unused colour 
 901     unsigned char r
,g
,b 
; 
 902     if (!FindFirstUnusedColour(&r
, &g
, &b
)) 
 904         wxLogError( _("No Unused Color in image being masked") ); 
 908     unsigned char *imgdata 
= GetData(); 
 909     unsigned char *maskdata 
= mask
.GetData(); 
 911     const int w 
= GetWidth(); 
 912     const int h 
= GetHeight(); 
 914     for (int j 
= 0; j 
< h
; j
++) 
 916         for (int i 
= 0; i 
< w
; i
++) 
 918             if ((maskdata
[0] == mr
) && (maskdata
[1]  == mg
) && (maskdata
[2] == mb
)) 
 929     SetMaskColour(r
, g
, b
); 
 939 bool wxImage::HasPalette() const 
 944     return M_IMGDATA
->m_palette
.Ok(); 
 947 const wxPalette
& wxImage::GetPalette() const 
 949     wxCHECK_MSG( Ok(), wxNullPalette
, wxT("invalid image") ); 
 951     return M_IMGDATA
->m_palette
; 
 954 void wxImage::SetPalette(const wxPalette
& palette
) 
 956     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 958     M_IMGDATA
->m_palette 
= palette
; 
 961 #endif // wxUSE_PALETTE 
 963 // Option functions (arbitrary name/value mapping) 
 964 void wxImage::SetOption(const wxString
& name
, const wxString
& value
) 
 966     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 968     int idx 
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
); 
 969     if (idx 
== wxNOT_FOUND
) 
 971         M_IMGDATA
->m_optionNames
.Add(name
); 
 972         M_IMGDATA
->m_optionValues
.Add(value
); 
 976         M_IMGDATA
->m_optionNames
[idx
] = name
; 
 977         M_IMGDATA
->m_optionValues
[idx
] = value
; 
 981 void wxImage::SetOption(const wxString
& name
, int value
) 
 984     valStr
.Printf(wxT("%d"), value
); 
 985     SetOption(name
, valStr
); 
 988 wxString 
wxImage::GetOption(const wxString
& name
) const 
 990     wxCHECK_MSG( Ok(), wxEmptyString
, wxT("invalid image") ); 
 992     int idx 
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
); 
 993     if (idx 
== wxNOT_FOUND
) 
 994         return wxEmptyString
; 
 996         return M_IMGDATA
->m_optionValues
[idx
]; 
 999 int wxImage::GetOptionInt(const wxString
& name
) const 
1001     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
1003     return wxAtoi(GetOption(name
)); 
1006 bool wxImage::HasOption(const wxString
& name
) const 
1008     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
1010     return (M_IMGDATA
->m_optionNames
.Index(name
, FALSE
) != wxNOT_FOUND
); 
1013 bool wxImage::LoadFile( const wxString
& filename
, long type
, int index 
) 
1016     if (wxFileExists(filename
)) 
1018         wxFileInputStream 
stream(filename
); 
1019         wxBufferedInputStream 
bstream( stream 
); 
1020         return LoadFile(bstream
, type
, index
); 
1024         wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() ); 
1028 #else // !wxUSE_STREAMS 
1030 #endif // wxUSE_STREAMS 
1033 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
, int index 
) 
1036     if (wxFileExists(filename
)) 
1038         wxFileInputStream 
stream(filename
); 
1039         wxBufferedInputStream 
bstream( stream 
); 
1040         return LoadFile(bstream
, mimetype
, index
); 
1044         wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() ); 
1048 #else // !wxUSE_STREAMS 
1050 #endif // wxUSE_STREAMS 
1055 bool wxImage::SaveFile( const wxString
& filename 
) const 
1057     wxString ext 
= filename
.AfterLast('.').Lower(); 
1059     wxImageHandler 
* pHandler 
= FindHandler(ext
, -1); 
1062         SaveFile(filename
, pHandler
->GetType()); 
1066     wxLogError(_("Can't save image to file '%s': unknown extension."), filename
.c_str()); 
1071 bool wxImage::SaveFile( const wxString
& filename
, int type 
) const 
1074     ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
); 
1076     wxFileOutputStream 
stream(filename
); 
1078     if ( stream
.IsOk() ) 
1080         wxBufferedOutputStream 
bstream( stream 
); 
1081         return SaveFile(bstream
, type
); 
1083 #endif // wxUSE_STREAMS 
1088 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype 
) const 
1091     ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
); 
1093     wxFileOutputStream 
stream(filename
); 
1095     if ( stream
.IsOk() ) 
1097         wxBufferedOutputStream 
bstream( stream 
); 
1098         return SaveFile(bstream
, mimetype
); 
1100 #endif // wxUSE_STREAMS 
1105 bool wxImage::CanRead( const wxString 
&name 
) 
1108   wxFileInputStream 
stream(name
); 
1109   return CanRead(stream
); 
1115 int wxImage::GetImageCount( const wxString 
&name
, long type 
) 
1118   wxFileInputStream 
stream(name
); 
1120       return GetImageCount(stream
, type
); 
1128 bool wxImage::CanRead( wxInputStream 
&stream 
) 
1130     const wxList
& list 
= GetHandlers(); 
1132     for ( wxList::Node 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
1134         wxImageHandler 
*handler
=(wxImageHandler
*)node
->GetData(); 
1135         if (handler
->CanRead( stream 
)) 
1142 int wxImage::GetImageCount( wxInputStream 
&stream
, long type 
) 
1144     wxImageHandler 
*handler
; 
1146     if ( type 
== wxBITMAP_TYPE_ANY 
) 
1148         wxList 
&list
=GetHandlers(); 
1150         for (wxList::Node 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext()) 
1152              handler
=(wxImageHandler
*)node
->GetData(); 
1153              if ( handler
->CanRead(stream
) ) 
1154                  return handler
->GetImageCount(stream
); 
1158         wxLogWarning(_("No handler found for image type.")); 
1162     handler 
= FindHandler(type
); 
1166         wxLogWarning(_("No image handler for type %d defined."), type
); 
1170     if ( handler
->CanRead(stream
) ) 
1172         return handler
->GetImageCount(stream
); 
1176         wxLogError(_("Image file is not of type %d."), type
); 
1181 bool wxImage::LoadFile( wxInputStream
& stream
, long type
, int index 
) 
1185     m_refData 
= new wxImageRefData
; 
1187     wxImageHandler 
*handler
; 
1189     if ( type 
== wxBITMAP_TYPE_ANY 
) 
1191         wxList 
&list
=GetHandlers(); 
1193         for ( wxList::Node 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
1195              handler
=(wxImageHandler
*)node
->GetData(); 
1196              if ( handler
->CanRead(stream
) ) 
1197                  return handler
->LoadFile(this, stream
, TRUE
/*verbose*/, index
); 
1201         wxLogWarning( _("No handler found for image type.") ); 
1205     handler 
= FindHandler(type
); 
1209         wxLogWarning( _("No image handler for type %d defined."), type 
); 
1214     return handler
->LoadFile(this, stream
, TRUE
/*verbose*/, index
); 
1217 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
, int index 
) 
1221     m_refData 
= new wxImageRefData
; 
1223     wxImageHandler 
*handler 
= FindHandlerMime(mimetype
); 
1227         wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() ); 
1232     return handler
->LoadFile( this, stream
, TRUE
/*verbose*/, index 
); 
1235 bool wxImage::SaveFile( wxOutputStream
& stream
, int type 
) const 
1237     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
1239     wxImageHandler 
*handler 
= FindHandler(type
); 
1243         wxLogWarning( _("No image handler for type %d defined."), type 
); 
1248     return handler
->SaveFile( (wxImage
*)this, stream 
); 
1251 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype 
) const 
1253     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
1255     wxImageHandler 
*handler 
= FindHandlerMime(mimetype
); 
1259         wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() ); 
1264     return handler
->SaveFile( (wxImage
*)this, stream 
); 
1266 #endif // wxUSE_STREAMS 
1268 void wxImage::AddHandler( wxImageHandler 
*handler 
) 
1270     // make sure that the memory will be freed at the program end 
1271     sm_handlers
.DeleteContents(TRUE
); 
1273     // Check for an existing handler of the type being added. 
1274     if (FindHandler( handler
->GetType() ) == 0) 
1276         sm_handlers
.Append( handler 
); 
1280         // This is not documented behaviour, merely the simplest 'fix' 
1281         // for preventing duplicate additions.  If someone ever has 
1282         // a good reason to add and remove duplicate handlers (and they 
1283         // may) we should probably refcount the duplicates. 
1284         //   also an issue in InsertHandler below. 
1286         wxLogDebug( _T("Adding duplicate image handler for '%s'"), 
1287                     handler
->GetName().c_str() ); 
1292 void wxImage::InsertHandler( wxImageHandler 
*handler 
) 
1294     // make sure that the memory will be freed at the program end 
1295     sm_handlers
.DeleteContents(TRUE
); 
1297     // Check for an existing handler of the type being added. 
1298     if (FindHandler( handler
->GetType() ) == 0) 
1300         sm_handlers
.Insert( handler 
); 
1304         // see AddHandler for additional comments. 
1305         wxLogDebug( _T("Inserting duplicate image handler for '%s'"), 
1306                     handler
->GetName().c_str() ); 
1311 bool wxImage::RemoveHandler( const wxString
& name 
) 
1313     wxImageHandler 
*handler 
= FindHandler(name
); 
1316         sm_handlers
.DeleteObject(handler
); 
1323 wxImageHandler 
*wxImage::FindHandler( const wxString
& name 
) 
1325     wxNode 
*node 
= sm_handlers
.GetFirst(); 
1328         wxImageHandler 
*handler 
= (wxImageHandler
*)node
->GetData(); 
1329         if (handler
->GetName().Cmp(name
) == 0) return handler
; 
1331         node 
= node
->GetNext(); 
1336 wxImageHandler 
*wxImage::FindHandler( const wxString
& extension
, long bitmapType 
) 
1338     wxNode 
*node 
= sm_handlers
.GetFirst(); 
1341         wxImageHandler 
*handler 
= (wxImageHandler
*)node
->GetData(); 
1342         if ( (handler
->GetExtension().Cmp(extension
) == 0) && 
1343             (bitmapType 
== -1 || handler
->GetType() == bitmapType
) ) 
1345         node 
= node
->GetNext(); 
1350 wxImageHandler 
*wxImage::FindHandler( long bitmapType 
) 
1352     wxNode 
*node 
= sm_handlers
.GetFirst(); 
1355         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->GetData(); 
1356         if (handler
->GetType() == bitmapType
) return handler
; 
1357         node 
= node
->GetNext(); 
1362 wxImageHandler 
*wxImage::FindHandlerMime( const wxString
& mimetype 
) 
1364     wxNode 
*node 
= sm_handlers
.GetFirst(); 
1367         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->GetData(); 
1368         if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
; 
1369         node 
= node
->GetNext(); 
1374 void wxImage::InitStandardHandlers() 
1377     AddHandler(new wxBMPHandler
); 
1378 #endif // wxUSE_STREAMS 
1381 void wxImage::CleanUpHandlers() 
1383     wxNode 
*node 
= sm_handlers
.GetFirst(); 
1386         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->GetData(); 
1387         wxNode 
*next 
= node
->GetNext(); 
1395 //----------------------------------------------------------------------------- 
1397 //----------------------------------------------------------------------------- 
1399 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
) 
1402 bool wxImageHandler::LoadFile( wxImage 
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) ) 
1407 bool wxImageHandler::SaveFile( wxImage 
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) ) 
1412 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) ) 
1417 bool wxImageHandler::CanRead( const wxString
& name 
) 
1419     if (wxFileExists(name
)) 
1421         wxFileInputStream 
stream(name
); 
1422         return CanRead(stream
); 
1425     wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() ); 
1430 bool wxImageHandler::CallDoCanRead(wxInputStream
& stream
) 
1432     off_t posOld 
= stream
.TellI(); 
1433     if ( posOld 
== wxInvalidOffset 
) 
1435         // can't test unseekable stream 
1439     bool ok 
= DoCanRead(stream
); 
1441     // restore the old position to be able to test other formats and so on 
1442     if ( stream
.SeekI(posOld
) == wxInvalidOffset 
) 
1444         wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!")); 
1446         // reading would fail anyhow as we're not at the right position 
1453 #endif // wxUSE_STREAMS 
1457 //----------------------------------------------------------------------------- 
1458 // Deprecated wxBitmap conversion routines 
1459 //----------------------------------------------------------------------------- 
1461 #if WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI 
1464 wxBitmap 
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue 
) const 
1466     wxImage mono 
= this->ConvertToMono( red
, green
, blue 
); 
1467     wxBitmap 
bitmap( mono
, 1 ); 
1472 wxBitmap 
wxImage::ConvertToBitmap() const 
1474     wxBitmap 
bitmap( *this ); 
1478 wxImage::wxImage( const wxBitmap 
&bitmap 
) 
1480     *this = bitmap
.ConvertToImage(); 
1483 #endif // WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI 
1486 // ---------------------------------------------------------------------------- 
1487 // image histogram stuff 
1488 // ---------------------------------------------------------------------------- 
1491 wxImageHistogram::FindFirstUnusedColour(unsigned char *r
, 
1496                                         unsigned char g2
) const 
1498     unsigned long key 
= MakeKey(r2
, g2
, b2
); 
1500     while ( find(key
) != end() ) 
1502         // color already used 
1514                     wxLogError(_("GetUnusedColour:: No Unused Color in image ") ); 
1520         key 
= MakeKey(r2
, g2
, b2
); 
1534 wxImage::FindFirstUnusedColour(unsigned char *r
, 
1539                                unsigned char g2
) const 
1541     wxImageHistogram histogram
; 
1543     ComputeHistogram(histogram
); 
1545     return histogram
.FindFirstUnusedColour(r
, g
, b
, r2
, g2
, b2
); 
1551 // Counts and returns the number of different colours. Optionally stops 
1552 // when it exceeds 'stopafter' different colours. This is useful, for 
1553 // example, to see if the image can be saved as 8-bit (256 colour or 
1554 // less, in this case it would be invoked as CountColours(256)). Default 
1555 // value for stopafter is -1 (don't care). 
1557 unsigned long wxImage::CountColours( unsigned long stopafter 
) const 
1561     unsigned char r
, g
, b
; 
1563     unsigned long size
, nentries
, key
; 
1566     size 
= GetWidth() * GetHeight(); 
1569     for (unsigned long j 
= 0; (j 
< size
) && (nentries 
<= stopafter
) ; j
++) 
1574         key 
= wxImageHistogram::MakeKey(r
, g
, b
); 
1576         if (h
.Get(key
) == NULL
) 
1587 unsigned long wxImage::ComputeHistogram( wxImageHistogram 
&h 
) const 
1589     unsigned char *p 
= GetData(); 
1590     unsigned long nentries 
= 0; 
1594     const unsigned long size 
= GetWidth() * GetHeight(); 
1596     unsigned char r
, g
, b
; 
1597     for ( unsigned long n 
= 0; n 
< size
; n
++ ) 
1603         wxImageHistogramEntry
& entry 
= h
[wxImageHistogram::MakeKey(r
, g
, b
)]; 
1605         if ( entry
.value
++ == 0 ) 
1606             entry
.index 
= nentries
++; 
1613  * Rotation code by Carlos Moreno 
1616 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which 
1617 //      does exactly the same thing. And I also got rid of wxRotationPixel 
1618 //      bacause of potential problems in architectures where alignment 
1619 //      is an issue, so I had to rewrite parts of the code. 
1621 static const double gs_Epsilon 
= 1e-10; 
1623 static inline int wxCint (double x
) 
1625     return (x 
> 0) ? (int) (x 
+ 0.5) : (int) (x 
- 0.5); 
1629 // Auxiliary function to rotate a point (x,y) with respect to point p0 
1630 // make it inline and use a straight return to facilitate optimization 
1631 // also, the function receives the sine and cosine of the angle to avoid 
1632 // repeating the time-consuming calls to these functions -- sin/cos can 
1633 // be computed and stored in the calling function. 
1635 inline wxRealPoint 
rotated_point (const wxRealPoint 
& p
, double cos_angle
, double sin_angle
, const wxRealPoint 
& p0
) 
1637     return wxRealPoint (p0
.x 
+ (p
.x 
- p0
.x
) * cos_angle 
- (p
.y 
- p0
.y
) * sin_angle
, 
1638                         p0
.y 
+ (p
.y 
- p0
.y
) * cos_angle 
+ (p
.x 
- p0
.x
) * sin_angle
); 
1641 inline wxRealPoint 
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint 
& p0
) 
1643     return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
); 
1646 wxImage 
wxImage::Rotate(double angle
, const wxPoint 
& centre_of_rotation
, bool interpolating
, wxPoint 
* offset_after_rotation
) const 
1649     angle 
= -angle
;     // screen coordinates are a mirror image of "real" coordinates 
1651     // Create pointer-based array to accelerate access to wxImage's data 
1652     unsigned char ** data 
= new unsigned char * [GetHeight()]; 
1654     data
[0] = GetData(); 
1656     for (i 
= 1; i 
< GetHeight(); i
++) 
1657         data
[i
] = data
[i 
- 1] + (3 * GetWidth()); 
1659     // precompute coefficients for rotation formula 
1660     // (sine and cosine of the angle) 
1661     const double cos_angle 
= cos(angle
); 
1662     const double sin_angle 
= sin(angle
); 
1664     // Create new Image to store the result 
1665     // First, find rectangle that covers the rotated image;  to do that, 
1666     // rotate the four corners 
1668     const wxRealPoint 
p0(centre_of_rotation
.x
, centre_of_rotation
.y
); 
1670     wxRealPoint p1 
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
); 
1671     wxRealPoint p2 
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
); 
1672     wxRealPoint p3 
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
); 
1673     wxRealPoint p4 
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
); 
1675     int x1 
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
))); 
1676     int y1 
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
))); 
1677     int x2 
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
))); 
1678     int y2 
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
))); 
1680     wxImage 
rotated (x2 
- x1 
+ 1, y2 
- y1 
+ 1, false); 
1682     if (offset_after_rotation 
!= NULL
) 
1684         *offset_after_rotation 
= wxPoint (x1
, y1
); 
1687     // GRG: The rotated (destination) image is always accessed 
1688     //      sequentially, so there is no need for a pointer-based 
1689     //      array here (and in fact it would be slower). 
1691     unsigned char * dst 
= rotated
.GetData(); 
1693     // GRG: if the original image has a mask, use its RGB values 
1694     //      as the blank pixel, else, fall back to default (black). 
1696     unsigned char blank_r 
= 0; 
1697     unsigned char blank_g 
= 0; 
1698     unsigned char blank_b 
= 0; 
1702         blank_r 
= GetMaskRed(); 
1703         blank_g 
= GetMaskGreen(); 
1704         blank_b 
= GetMaskBlue(); 
1705         rotated
.SetMaskColour( blank_r
, blank_g
, blank_b 
); 
1708     // Now, for each point of the rotated image, find where it came from, by 
1709     // performing an inverse rotation (a rotation of -angle) and getting the 
1710     // pixel at those coordinates 
1712     // GRG: I've taken the (interpolating) test out of the loops, so that 
1713     //      it is done only once, instead of repeating it for each pixel. 
1718         for (int y 
= 0; y 
< rotated
.GetHeight(); y
++) 
1720             for (x 
= 0; x 
< rotated
.GetWidth(); x
++) 
1722                 wxRealPoint src 
= rotated_point (x 
+ x1
, y 
+ y1
, cos_angle
, -sin_angle
, p0
); 
1724                 if (-0.25 < src
.x 
&& src
.x 
< GetWidth() - 0.75 && 
1725                     -0.25 < src
.y 
&& src
.y 
< GetHeight() - 0.75) 
1727                     // interpolate using the 4 enclosing grid-points.  Those 
1728                     // points can be obtained using floor and ceiling of the 
1729                     // exact coordinates of the point 
1730                         // C.M. 2000-02-17:  when the point is near the border, special care is required. 
1734                     if (0 < src
.x 
&& src
.x 
< GetWidth() - 1) 
1736                         x1 
= wxCint(floor(src
.x
)); 
1737                         x2 
= wxCint(ceil(src
.x
)); 
1739                     else    // else means that x is near one of the borders (0 or width-1) 
1741                         x1 
= x2 
= wxCint (src
.x
); 
1744                     if (0 < src
.y 
&& src
.y 
< GetHeight() - 1) 
1746                         y1 
= wxCint(floor(src
.y
)); 
1747                         y2 
= wxCint(ceil(src
.y
)); 
1751                         y1 
= y2 
= wxCint (src
.y
); 
1754                     // get four points and the distances (square of the distance, 
1755                     // for efficiency reasons) for the interpolation formula 
1757                     // GRG: Do not calculate the points until they are 
1758                     //      really needed -- this way we can calculate 
1759                     //      just one, instead of four, if d1, d2, d3 
1760                     //      or d4 are < gs_Epsilon 
1762                     const double d1 
= (src
.x 
- x1
) * (src
.x 
- x1
) + (src
.y 
- y1
) * (src
.y 
- y1
); 
1763                     const double d2 
= (src
.x 
- x2
) * (src
.x 
- x2
) + (src
.y 
- y1
) * (src
.y 
- y1
); 
1764                     const double d3 
= (src
.x 
- x2
) * (src
.x 
- x2
) + (src
.y 
- y2
) * (src
.y 
- y2
); 
1765                     const double d4 
= (src
.x 
- x1
) * (src
.x 
- x1
) + (src
.y 
- y2
) * (src
.y 
- y2
); 
1767                     // Now interpolate as a weighted average of the four surrounding 
1768                     // points, where the weights are the distances to each of those points 
1770                     // If the point is exactly at one point of the grid of the source 
1771                     // image, then don't interpolate -- just assign the pixel 
1773                     if (d1 
< gs_Epsilon
)        // d1,d2,d3,d4 are positive -- no need for abs() 
1775                         unsigned char *p 
= data
[y1
] + (3 * x1
); 
1780                     else if (d2 
< gs_Epsilon
) 
1782                         unsigned char *p 
= data
[y1
] + (3 * x2
); 
1787                     else if (d3 
< gs_Epsilon
) 
1789                         unsigned char *p 
= data
[y2
] + (3 * x2
); 
1794                     else if (d4 
< gs_Epsilon
) 
1796                         unsigned char *p 
= data
[y2
] + (3 * x1
); 
1803                         // weights for the weighted average are proportional to the inverse of the distance 
1804                         unsigned char *v1 
= data
[y1
] + (3 * x1
); 
1805                         unsigned char *v2 
= data
[y1
] + (3 * x2
); 
1806                         unsigned char *v3 
= data
[y2
] + (3 * x2
); 
1807                         unsigned char *v4 
= data
[y2
] + (3 * x1
); 
1809                         const double w1 
= 1/d1
, w2 
= 1/d2
, w3 
= 1/d3
, w4 
= 1/d4
; 
1813                         *(dst
++) = (unsigned char) 
1814                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1815                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1816                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1817                         *(dst
++) = (unsigned char) 
1818                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1819                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1820                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1821                         *(dst
++) = (unsigned char) 
1822                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1823                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1824                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1836     else    // not interpolating 
1838         for (int y 
= 0; y 
< rotated
.GetHeight(); y
++) 
1840             for (x 
= 0; x 
< rotated
.GetWidth(); x
++) 
1842                 wxRealPoint src 
= rotated_point (x 
+ x1
, y 
+ y1
, cos_angle
, -sin_angle
, p0
); 
1844                 const int xs 
= wxCint (src
.x
);      // wxCint rounds to the 
1845                 const int ys 
= wxCint (src
.y
);      // closest integer 
1847                 if (0 <= xs 
&& xs 
< GetWidth() && 
1848                     0 <= ys 
&& ys 
< GetHeight()) 
1850                     unsigned char *p 
= data
[ys
] + (3 * xs
); 
1874 // A module to allow wxImage initialization/cleanup 
1875 // without calling these functions from app.cpp or from 
1876 // the user's application. 
1878 class wxImageModule
: public wxModule
 
1880 DECLARE_DYNAMIC_CLASS(wxImageModule
) 
1883     bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; }; 
1884     void OnExit() { wxImage::CleanUpHandlers(); }; 
1887 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
) 
1890 #endif // wxUSE_IMAGE