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" 
  44 //----------------------------------------------------------------------------- 
  46 //----------------------------------------------------------------------------- 
  48 class wxImageRefData
: public wxObjectRefData
 
  56     unsigned char  *m_data
; 
  58     unsigned char   m_maskRed
,m_maskGreen
,m_maskBlue
; 
  63 #endif // wxUSE_PALETTE 
  64     wxArrayString   m_optionNames
; 
  65     wxArrayString   m_optionValues
; 
  68 wxImageRefData::wxImageRefData() 
  72     m_data 
= (unsigned char*) NULL
; 
  81 wxImageRefData::~wxImageRefData() 
  83     if (m_data 
&& !m_static
) 
  87 wxList 
wxImage::sm_handlers
; 
  91 //----------------------------------------------------------------------------- 
  93 #define M_IMGDATA ((wxImageRefData *)m_refData) 
  95 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
) 
 101 wxImage::wxImage( int width
, int height 
) 
 103     Create( width
, height 
); 
 106 wxImage::wxImage( int width
, int height
, unsigned char* data
, bool static_data 
) 
 108     Create( width
, height
, data
, static_data 
); 
 111 wxImage::wxImage( const wxString
& name
, long type
, int index 
) 
 113     LoadFile( name
, type
, index 
); 
 116 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
, int index 
) 
 118     LoadFile( name
, mimetype
, index 
); 
 122 wxImage::wxImage( wxInputStream
& stream
, long type
, int index 
) 
 124     LoadFile( stream
, type
, index 
); 
 127 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
, int index 
) 
 129     LoadFile( stream
, mimetype
, index 
); 
 131 #endif // wxUSE_STREAMS 
 133 wxImage::wxImage( const wxImage
& image 
) 
 138 wxImage::wxImage( const wxImage
* image 
) 
 140     if (image
) Ref(*image
); 
 143 void wxImage::Create( int width
, int height 
) 
 147     m_refData 
= new wxImageRefData(); 
 149     M_IMGDATA
->m_data 
= (unsigned char *) malloc( width
*height
*3 ); 
 150     if (M_IMGDATA
->m_data
) 
 152         for (int l 
= 0; l 
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0; 
 154         M_IMGDATA
->m_width 
= width
; 
 155         M_IMGDATA
->m_height 
= height
; 
 156         M_IMGDATA
->m_ok 
= TRUE
; 
 164 void wxImage::Create( int width
, int height
, unsigned char* data
, bool static_data 
) 
 168     m_refData 
= new wxImageRefData(); 
 170     M_IMGDATA
->m_data 
= data
; 
 171     if (M_IMGDATA
->m_data
) 
 173         M_IMGDATA
->m_width 
= width
; 
 174         M_IMGDATA
->m_height 
= height
; 
 175         M_IMGDATA
->m_ok 
= TRUE
; 
 176         M_IMGDATA
->m_static 
= static_data
; 
 184 void wxImage::Destroy() 
 189 wxImage 
wxImage::Copy() const 
 193     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 195     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height 
); 
 197     char unsigned *data 
= image
.GetData(); 
 199     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 201     if (M_IMGDATA
->m_hasMask
) 
 202         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 204     memcpy( data
, GetData(), M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3 ); 
 209 wxImage 
wxImage::Scale( int width
, int height 
) const 
 213     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 215     // can't scale to/from 0 size 
 216     wxCHECK_MSG( (width 
> 0) && (height 
> 0), image
, 
 217                  wxT("invalid new image size") ); 
 219     long old_height 
= M_IMGDATA
->m_height
, 
 220          old_width  
= M_IMGDATA
->m_width
; 
 221     wxCHECK_MSG( (old_height 
> 0) && (old_width 
> 0), image
, 
 222                  wxT("invalid old image size") ); 
 224     image
.Create( width
, height 
); 
 226     char unsigned *data 
= image
.GetData(); 
 228     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 230     if (M_IMGDATA
->m_hasMask
) 
 232         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, 
 233                              M_IMGDATA
->m_maskGreen
, 
 234                              M_IMGDATA
->m_maskBlue 
); 
 237     char unsigned *source_data 
= M_IMGDATA
->m_data
; 
 238     char unsigned *target_data 
= data
; 
 241     // This is nonsense, RR. 
 243     // We do (x, y) -> (x, y)*oldSize/newSize but the valid values of x and y 
 244     // are from 0 to size-1, hence all decrement the sizes 
 245     long old_old_width 
= old_width
; 
 250     for ( long j 
= 0; j 
<= height
; j
++ ) 
 252         // don't crash for images with height == 1 
 253         long y_offset 
= height 
? (j 
* old_height 
/ height
)* old_old_width 
: 0; 
 255         for ( long i 
= 0; i 
<= width
; i
++ ) 
 257             long x_offset 
= width 
? (i 
* old_width
) / width 
: 0; 
 259             memcpy( target_data
, source_data 
+ 3*(y_offset 
+ x_offset
), 3 ); 
 264     for (long j 
= 0; j 
< height
; j
++) 
 266         long y_offset 
= (j 
* old_height 
/ height
) * old_width
; 
 268         for (long i 
= 0; i 
< width
; i
++) 
 271                 source_data 
+ 3*(y_offset 
+ ((i 
* old_width 
)/ width
)), 
 278     // In case this is a cursor, make sure the hotspot is scalled accordingly: 
 279     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
) ) 
 280         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
, 
 281                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
)*width
)/old_width
); 
 282     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
) ) 
 283         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
, 
 284                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)*height
)/old_height
); 
 289 wxImage 
wxImage::Rotate90( bool clockwise 
) const 
 293     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 295     image
.Create( M_IMGDATA
->m_height
, M_IMGDATA
->m_width 
); 
 297     char unsigned *data 
= image
.GetData(); 
 299     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 301     if (M_IMGDATA
->m_hasMask
) 
 302         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 304     long height 
= M_IMGDATA
->m_height
; 
 305     long width  
= M_IMGDATA
->m_width
; 
 307     char unsigned *source_data 
= M_IMGDATA
->m_data
; 
 308     char unsigned *target_data
; 
 310     for (long j 
= 0; j 
< height
; j
++) 
 312         for (long i 
= 0; i 
< width
; i
++) 
 315                 target_data 
= data 
+ (((i
+1)*height
) - j 
- 1)*3; 
 317                 target_data 
= data 
+ ((height
*(width
-1)) + j 
- (i
*height
))*3; 
 318             memcpy( target_data
, source_data
, 3 ); 
 326 wxImage 
wxImage::Mirror( bool horizontally 
) const 
 330     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 332     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height 
); 
 334     char unsigned *data 
= image
.GetData(); 
 336     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 338     if (M_IMGDATA
->m_hasMask
) 
 339         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 341     long height 
= M_IMGDATA
->m_height
; 
 342     long width  
= M_IMGDATA
->m_width
; 
 344     char unsigned *source_data 
= M_IMGDATA
->m_data
; 
 345     char unsigned *target_data
; 
 349         for (long j 
= 0; j 
< height
; j
++) 
 352             target_data 
= data
-3; 
 353             for (long i 
= 0; i 
< width
; i
++) 
 355                 memcpy( target_data
, source_data
, 3 ); 
 363         for (long i 
= 0; i 
< height
; i
++) 
 365             target_data 
= data 
+ 3*width
*(height
-1-i
); 
 366             memcpy( target_data
, source_data
, (size_t)3*width 
); 
 367             source_data 
+= 3*width
; 
 374 wxImage 
wxImage::GetSubImage( const wxRect 
&rect 
) const 
 378     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 380     wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()), 
 381                  image
, wxT("invalid subimage size") ); 
 383     int subwidth
=rect
.GetWidth(); 
 384     const int subheight
=rect
.GetHeight(); 
 386     image
.Create( subwidth
, subheight 
); 
 388     char unsigned *subdata 
= image
.GetData(), *data
=GetData(); 
 390     wxCHECK_MSG( subdata
, image
, wxT("unable to create image") ); 
 392     if (M_IMGDATA
->m_hasMask
) 
 393         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 395     const int subleft
=3*rect
.GetLeft(); 
 396     const int width
=3*GetWidth(); 
 399     data
+=rect
.GetTop()*width
+subleft
; 
 401     for (long j 
= 0; j 
< subheight
; ++j
) 
 403         memcpy( subdata
, data
, subwidth
); 
 411 void wxImage::Paste( const wxImage 
&image
, int x
, int y 
) 
 413     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 414     wxCHECK_RET( image
.Ok(), wxT("invalid image") ); 
 418     int width 
= image
.GetWidth(); 
 419     int height 
= image
.GetHeight(); 
 432     if ((x
+xx
)+width 
> M_IMGDATA
->m_width
) 
 433         width 
= M_IMGDATA
->m_width 
- (x
+xx
); 
 434     if ((y
+yy
)+height 
> M_IMGDATA
->m_height
) 
 435         height 
= M_IMGDATA
->m_height 
- (y
+yy
); 
 437     if (width 
< 1) return; 
 438     if (height 
< 1) return; 
 440     if ((!HasMask() && !image
.HasMask()) || 
 441        ((HasMask() && image
.HasMask() && 
 442          (GetMaskRed()==image
.GetMaskRed()) && 
 443          (GetMaskGreen()==image
.GetMaskGreen()) && 
 444          (GetMaskBlue()==image
.GetMaskBlue())))) 
 447         unsigned char* source_data 
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth(); 
 448         int source_step 
= image
.GetWidth()*3; 
 450         unsigned char* target_data 
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
; 
 451         int target_step 
= M_IMGDATA
->m_width
*3; 
 452         for (int j 
= 0; j 
< height
; j
++) 
 454             memcpy( target_data
, source_data
, width 
); 
 455             source_data 
+= source_step
; 
 456             target_data 
+= target_step
; 
 461     if (!HasMask() && image
.HasMask()) 
 463         unsigned char r 
= image
.GetMaskRed(); 
 464         unsigned char g 
= image
.GetMaskGreen(); 
 465         unsigned char b 
= image
.GetMaskBlue(); 
 468         unsigned char* source_data 
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth(); 
 469         int source_step 
= image
.GetWidth()*3; 
 471         unsigned char* target_data 
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
; 
 472         int target_step 
= M_IMGDATA
->m_width
*3; 
 474         for (int j 
= 0; j 
< height
; j
++) 
 476             for (int i 
= 0; i 
< width
; i
+=3) 
 478                 if ((source_data
[i
]   != r
) && 
 479                     (source_data
[i
+1] != g
) && 
 480                     (source_data
[i
+2] != b
)) 
 482                     memcpy( target_data
+i
, source_data
+i
, 3 ); 
 485             source_data 
+= source_step
; 
 486             target_data 
+= target_step
; 
 491 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
, 
 492                        unsigned char r2
, unsigned char g2
, unsigned char b2 
) 
 494     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 496     char unsigned *data 
= GetData(); 
 498     const int w 
= GetWidth(); 
 499     const int h 
= GetHeight(); 
 501     for (int j 
= 0; j 
< h
; j
++) 
 502         for (int i 
= 0; i 
< w
; i
++) 
 504             if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
)) 
 514 wxImage 
wxImage::ConvertToMono( unsigned char r
, unsigned char g
, unsigned char b 
) const 
 518     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 520     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height 
); 
 522     char unsigned *data 
= image
.GetData(); 
 524     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 526     if (M_IMGDATA
->m_hasMask
) 
 528         if (M_IMGDATA
->m_maskRed 
== r 
&& M_IMGDATA
->m_maskGreen 
== g 
&& 
 529                                          M_IMGDATA
->m_maskBlue 
== b
) 
 530             image
.SetMaskColour( 255, 255, 255 ); 
 532             image
.SetMaskColour( 0, 0, 0 ); 
 535     long size 
= M_IMGDATA
->m_height 
* M_IMGDATA
->m_width
; 
 537     char unsigned *srcd 
= M_IMGDATA
->m_data
; 
 538     char unsigned *tard 
= image
.GetData(); 
 540     for ( long i 
= 0; i 
< size
; i
++, srcd 
+= 3, tard 
+= 3 ) 
 542         if (srcd
[0] == r 
&& srcd
[1] == g 
&& srcd
[2] == b
) 
 543             tard
[0] = tard
[1] = tard
[2] = 255; 
 545             tard
[0] = tard
[1] = tard
[2] = 0; 
 551 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b 
) 
 553     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 555     int w 
= M_IMGDATA
->m_width
; 
 556     int h 
= M_IMGDATA
->m_height
; 
 558     wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") ); 
 560     long pos 
= (y 
* w 
+ x
) * 3; 
 562     M_IMGDATA
->m_data
[ pos   
] = r
; 
 563     M_IMGDATA
->m_data
[ pos
+1 ] = g
; 
 564     M_IMGDATA
->m_data
[ pos
+2 ] = b
; 
 567 unsigned char wxImage::GetRed( int x
, int y 
) const 
 569     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 571     int w 
= M_IMGDATA
->m_width
; 
 572     int h 
= M_IMGDATA
->m_height
; 
 574     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 576     long pos 
= (y 
* w 
+ x
) * 3; 
 578     return M_IMGDATA
->m_data
[pos
]; 
 581 unsigned char wxImage::GetGreen( int x
, int y 
) const 
 583     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 585     int w 
= M_IMGDATA
->m_width
; 
 586     int h 
= M_IMGDATA
->m_height
; 
 588     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 590     long pos 
= (y 
* w 
+ x
) * 3; 
 592     return M_IMGDATA
->m_data
[pos
+1]; 
 595 unsigned char wxImage::GetBlue( int x
, int y 
) const 
 597     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 599     int w 
= M_IMGDATA
->m_width
; 
 600     int h 
= M_IMGDATA
->m_height
; 
 602     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 604     long pos 
= (y 
* w 
+ x
) * 3; 
 606     return M_IMGDATA
->m_data
[pos
+2]; 
 609 bool wxImage::Ok() const 
 611     // image of 0 width or height can't be considered ok - at least because it 
 612     // causes crashes in ConvertToBitmap() if we don't catch it in time 
 613     wxImageRefData 
*data 
= M_IMGDATA
; 
 614     return data 
&& data
->m_ok 
&& data
->m_width 
&& data
->m_height
; 
 617 char unsigned *wxImage::GetData() const 
 619     wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") ); 
 621     return M_IMGDATA
->m_data
; 
 624 void wxImage::SetData( char unsigned *data 
) 
 626     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 628     wxImageRefData 
*newRefData 
= new wxImageRefData(); 
 630     newRefData
->m_width 
= M_IMGDATA
->m_width
; 
 631     newRefData
->m_height 
= M_IMGDATA
->m_height
; 
 632     newRefData
->m_data 
= data
; 
 633     newRefData
->m_ok 
= TRUE
; 
 634     newRefData
->m_maskRed 
= M_IMGDATA
->m_maskRed
; 
 635     newRefData
->m_maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 636     newRefData
->m_maskBlue 
= M_IMGDATA
->m_maskBlue
; 
 637     newRefData
->m_hasMask 
= M_IMGDATA
->m_hasMask
; 
 641     m_refData 
= newRefData
; 
 644 void wxImage::SetData( char unsigned *data
, int new_width
, int new_height 
) 
 646     wxImageRefData 
*newRefData 
= new wxImageRefData(); 
 650         newRefData
->m_width 
= new_width
; 
 651         newRefData
->m_height 
= new_height
; 
 652         newRefData
->m_data 
= data
; 
 653         newRefData
->m_ok 
= TRUE
; 
 654         newRefData
->m_maskRed 
= M_IMGDATA
->m_maskRed
; 
 655         newRefData
->m_maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 656         newRefData
->m_maskBlue 
= M_IMGDATA
->m_maskBlue
; 
 657         newRefData
->m_hasMask 
= M_IMGDATA
->m_hasMask
; 
 661         newRefData
->m_width 
= new_width
; 
 662         newRefData
->m_height 
= new_height
; 
 663         newRefData
->m_data 
= data
; 
 664         newRefData
->m_ok 
= TRUE
; 
 669     m_refData 
= newRefData
; 
 672 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b 
) 
 674     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 676     M_IMGDATA
->m_maskRed 
= r
; 
 677     M_IMGDATA
->m_maskGreen 
= g
; 
 678     M_IMGDATA
->m_maskBlue 
= b
; 
 679     M_IMGDATA
->m_hasMask 
= TRUE
; 
 682 unsigned char wxImage::GetMaskRed() const 
 684     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 686     return M_IMGDATA
->m_maskRed
; 
 689 unsigned char wxImage::GetMaskGreen() const 
 691     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 693     return M_IMGDATA
->m_maskGreen
; 
 696 unsigned char wxImage::GetMaskBlue() const 
 698     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 700     return M_IMGDATA
->m_maskBlue
; 
 703 void wxImage::SetMask( bool mask 
) 
 705     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 707     M_IMGDATA
->m_hasMask 
= mask
; 
 710 bool wxImage::HasMask() const 
 712     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
 714     return M_IMGDATA
->m_hasMask
; 
 717 int wxImage::GetWidth() const 
 719     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 721     return M_IMGDATA
->m_width
; 
 724 int wxImage::GetHeight() const 
 726     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 728     return M_IMGDATA
->m_height
; 
 732 bool wxImage::FindFirstUnusedColour( 
 733             unsigned char *r
, unsigned char *g
, unsigned char *b
, 
 734             unsigned char startR
, unsigned char startG
, unsigned char startB
) const 
 736     wxImageHistogram histogram
; 
 739     ComputeHistogram(histogram
); 
 741     unsigned char r2 
= startR
; 
 742     unsigned char g2 
= startG
; 
 743     unsigned char b2 
= startB
; 
 745     key 
= (r2 
<< 16) | (g2 
<< 8) | b2
; 
 747     while ( histogram
.find(key
) != histogram
.end() ) 
 749         // color already used 
 761                     wxLogError( _("GetUnusedColour:: No Unused Color in image ") );             
 767         key 
= (r2 
<< 16) | (g2 
<< 8) | b2
; 
 778 bool wxImage::SetMaskFromImage(const wxImage
& mask
,  
 779                                unsigned char mr
, unsigned char mg
, unsigned char mb
) 
 781     // check that the images are the same size 
 782     if ( (M_IMGDATA
->m_height 
!= mask
.GetHeight() ) || (M_IMGDATA
->m_width 
!= mask
.GetWidth () ) ) 
 784         wxLogError( _("Image and Mask have different sizes") );             
 788     // find unused colour 
 789     unsigned char r
,g
,b 
; 
 790     if (!FindFirstUnusedColour(&r
, &g
, &b
)) 
 792         wxLogError( _("No Unused Color in image being masked") );             
 796     char unsigned *imgdata 
= GetData(); 
 797     char unsigned *maskdata 
= mask
.GetData(); 
 799     const int w 
= GetWidth(); 
 800     const int h 
= GetHeight(); 
 802     for (int j 
= 0; j 
< h
; j
++) 
 804         for (int i 
= 0; i 
< w
; i
++) 
 806             if ((maskdata
[0] == mr
) && (maskdata
[1]  == mg
) && (maskdata
[2] == mb
)) 
 817     SetMaskColour(r
, g
, b
); 
 827 bool wxImage::HasPalette() const 
 832     return M_IMGDATA
->m_palette
.Ok(); 
 835 const wxPalette
& wxImage::GetPalette() const 
 837     wxCHECK_MSG( Ok(), wxNullPalette
, wxT("invalid image") ); 
 839     return M_IMGDATA
->m_palette
; 
 842 void wxImage::SetPalette(const wxPalette
& palette
) 
 844     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 846     M_IMGDATA
->m_palette 
= palette
; 
 849 #endif // wxUSE_PALETTE 
 851 // Option functions (arbitrary name/value mapping) 
 852 void wxImage::SetOption(const wxString
& name
, const wxString
& value
) 
 854     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 856     int idx 
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
); 
 857     if (idx 
== wxNOT_FOUND
) 
 859         M_IMGDATA
->m_optionNames
.Add(name
); 
 860         M_IMGDATA
->m_optionValues
.Add(value
); 
 864         M_IMGDATA
->m_optionNames
[idx
] = name
; 
 865         M_IMGDATA
->m_optionValues
[idx
] = value
; 
 869 void wxImage::SetOption(const wxString
& name
, int value
) 
 872     valStr
.Printf(wxT("%d"), value
); 
 873     SetOption(name
, valStr
); 
 876 wxString 
wxImage::GetOption(const wxString
& name
) const 
 878     wxCHECK_MSG( Ok(), wxEmptyString
, wxT("invalid image") ); 
 880     int idx 
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
); 
 881     if (idx 
== wxNOT_FOUND
) 
 882         return wxEmptyString
; 
 884         return M_IMGDATA
->m_optionValues
[idx
]; 
 887 int wxImage::GetOptionInt(const wxString
& name
) const 
 889     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 891     return wxAtoi(GetOption(name
)); 
 894 bool wxImage::HasOption(const wxString
& name
) const 
 896     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
 898     return (M_IMGDATA
->m_optionNames
.Index(name
, FALSE
) != wxNOT_FOUND
); 
 901 bool wxImage::LoadFile( const wxString
& filename
, long type
, int index 
) 
 904     if (wxFileExists(filename
)) 
 906         wxFileInputStream 
stream(filename
); 
 907         wxBufferedInputStream 
bstream( stream 
); 
 908         return LoadFile(bstream
, type
, index
); 
 912         wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() ); 
 916 #else // !wxUSE_STREAMS 
 918 #endif // wxUSE_STREAMS 
 921 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
, int index 
) 
 924     if (wxFileExists(filename
)) 
 926         wxFileInputStream 
stream(filename
); 
 927         wxBufferedInputStream 
bstream( stream 
); 
 928         return LoadFile(bstream
, mimetype
, index
); 
 932         wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() ); 
 936 #else // !wxUSE_STREAMS 
 938 #endif // wxUSE_STREAMS 
 941 bool wxImage::SaveFile( const wxString
& filename
, int type 
) const 
 944     ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
); 
 946     wxFileOutputStream 
stream(filename
); 
 948     if ( stream
.LastError() == wxStream_NOERROR 
) 
 950         wxBufferedOutputStream 
bstream( stream 
); 
 951         return SaveFile(bstream
, type
); 
 953 #endif // wxUSE_STREAMS 
 958 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype 
) const 
 961     ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
); 
 963     wxFileOutputStream 
stream(filename
); 
 965     if ( stream
.LastError() == wxStream_NOERROR 
) 
 967         wxBufferedOutputStream 
bstream( stream 
); 
 968         return SaveFile(bstream
, mimetype
); 
 970 #endif // wxUSE_STREAMS 
 975 bool wxImage::CanRead( const wxString 
&name 
) 
 978   wxFileInputStream 
stream(name
); 
 979   return CanRead(stream
); 
 985 int wxImage::GetImageCount( const wxString 
&name
, long type 
) 
 988   wxFileInputStream 
stream(name
); 
 989   return GetImageCount(stream
, type
); 
 997 bool wxImage::CanRead( wxInputStream 
&stream 
) 
 999     wxList 
&list
=GetHandlers(); 
1001     for ( wxList::Node 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
1003         wxImageHandler 
*handler
=(wxImageHandler
*)node
->GetData(); 
1004         if (handler
->CanRead( stream 
)) 
1011 int wxImage::GetImageCount( wxInputStream 
&stream
, long type 
) 
1013     wxImageHandler 
*handler
; 
1015     if ( type 
== wxBITMAP_TYPE_ANY 
) 
1017         wxList 
&list
=GetHandlers(); 
1019         for (wxList::Node 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext()) 
1021              handler
=(wxImageHandler
*)node
->GetData(); 
1022              if ( handler
->CanRead(stream
) ) 
1023                  return handler
->GetImageCount(stream
); 
1027         wxLogWarning(_("No handler found for image type.")); 
1031     handler 
= FindHandler(type
); 
1035         wxLogWarning(_("No image handler for type %d defined."), type
); 
1039     if ( handler
->CanRead(stream
) ) 
1041         return handler
->GetImageCount(stream
); 
1045         wxLogError(_("Image file is not of type %d."), type
); 
1050 bool wxImage::LoadFile( wxInputStream
& stream
, long type
, int index 
) 
1054     m_refData 
= new wxImageRefData
; 
1056     wxImageHandler 
*handler
; 
1058     if ( type 
== wxBITMAP_TYPE_ANY 
) 
1060         wxList 
&list
=GetHandlers(); 
1062         for ( wxList::Node 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
1064              handler
=(wxImageHandler
*)node
->GetData(); 
1065              if ( handler
->CanRead(stream
) ) 
1066                  return handler
->LoadFile(this, stream
, TRUE
/*verbose*/, index
); 
1070         wxLogWarning( _("No handler found for image type.") ); 
1074     handler 
= FindHandler(type
); 
1076     if (handler 
== NULL
) 
1078         wxLogWarning( _("No image handler for type %d defined."), type 
); 
1083     return handler
->LoadFile(this, stream
, TRUE
/*verbose*/, index
); 
1086 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
, int index 
) 
1090     m_refData 
= new wxImageRefData
; 
1092     wxImageHandler 
*handler 
= FindHandlerMime(mimetype
); 
1094     if (handler 
== NULL
) 
1096         wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() ); 
1101     return handler
->LoadFile( this, stream
, TRUE
/*verbose*/, index 
); 
1104 bool wxImage::SaveFile( wxOutputStream
& stream
, int type 
) const 
1106     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
1108     wxImageHandler 
*handler 
= FindHandler(type
); 
1110     if (handler 
== NULL
) 
1112         wxLogWarning( _("No image handler for type %d defined."), type 
); 
1117     return handler
->SaveFile( (wxImage
*)this, stream 
); 
1120 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype 
) const 
1122     wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") ); 
1124     wxImageHandler 
*handler 
= FindHandlerMime(mimetype
); 
1126     if (handler 
== NULL
) 
1128         wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() ); 
1133     return handler
->SaveFile( (wxImage
*)this, stream 
); 
1135 #endif // wxUSE_STREAMS 
1137 void wxImage::AddHandler( wxImageHandler 
*handler 
) 
1139     // make sure that the memory will be freed at the program end 
1140     sm_handlers
.DeleteContents(TRUE
); 
1142     sm_handlers
.Append( handler 
); 
1145 void wxImage::InsertHandler( wxImageHandler 
*handler 
) 
1147     // make sure that the memory will be freed at the program end 
1148     sm_handlers
.DeleteContents(TRUE
); 
1150     sm_handlers
.Insert( handler 
); 
1153 bool wxImage::RemoveHandler( const wxString
& name 
) 
1155     wxImageHandler 
*handler 
= FindHandler(name
); 
1158         sm_handlers
.DeleteObject(handler
); 
1165 wxImageHandler 
*wxImage::FindHandler( const wxString
& name 
) 
1167     wxNode 
*node 
= sm_handlers
.First(); 
1170         wxImageHandler 
*handler 
= (wxImageHandler
*)node
->Data(); 
1171         if (handler
->GetName().Cmp(name
) == 0) return handler
; 
1173         node 
= node
->Next(); 
1175     return (wxImageHandler 
*)NULL
; 
1178 wxImageHandler 
*wxImage::FindHandler( const wxString
& extension
, long bitmapType 
) 
1180     wxNode 
*node 
= sm_handlers
.First(); 
1183         wxImageHandler 
*handler 
= (wxImageHandler
*)node
->Data(); 
1184         if ( (handler
->GetExtension().Cmp(extension
) == 0) && 
1185             (bitmapType 
== -1 || handler
->GetType() == bitmapType
) ) 
1187         node 
= node
->Next(); 
1189     return (wxImageHandler
*)NULL
; 
1192 wxImageHandler 
*wxImage::FindHandler( long bitmapType 
) 
1194     wxNode 
*node 
= sm_handlers
.First(); 
1197         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->Data(); 
1198         if (handler
->GetType() == bitmapType
) return handler
; 
1199         node 
= node
->Next(); 
1204 wxImageHandler 
*wxImage::FindHandlerMime( const wxString
& mimetype 
) 
1206     wxNode 
*node 
= sm_handlers
.First(); 
1209         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->Data(); 
1210         if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
; 
1211         node 
= node
->Next(); 
1216 void wxImage::InitStandardHandlers() 
1219     AddHandler(new wxBMPHandler
); 
1220 #endif // wxUSE_STREAMS 
1222 #if wxUSE_XPM && !defined(__WXGTK__) && !defined(__WXMOTIF__) 
1223     AddHandler(new wxXPMHandler
); 
1227 void wxImage::CleanUpHandlers() 
1229     wxNode 
*node 
= sm_handlers
.First(); 
1232         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->Data(); 
1233         wxNode 
*next 
= node
->Next(); 
1240 //----------------------------------------------------------------------------- 
1242 //----------------------------------------------------------------------------- 
1244 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
) 
1247 bool wxImageHandler::LoadFile( wxImage 
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) ) 
1252 bool wxImageHandler::SaveFile( wxImage 
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) ) 
1257 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) ) 
1262 bool wxImageHandler::CanRead( const wxString
& name 
) 
1264     if (wxFileExists(name
)) 
1266         wxFileInputStream 
stream(name
); 
1267         return CanRead(stream
); 
1271         wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() ); 
1278 #endif // wxUSE_STREAMS 
1282 //----------------------------------------------------------------------------- 
1283 // wxBitmap convertion routines 
1284 //----------------------------------------------------------------------------- 
1289 wxBitmap 
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue 
) const 
1291     wxImage mono 
= this->ConvertToMono( red
, green
, blue 
); 
1292     wxBitmap 
bitmap( mono
, 1 ); 
1297 wxBitmap 
wxImage::ConvertToBitmap() const 
1299     wxBitmap 
bitmap( *this ); 
1303 wxImage::wxImage( const wxBitmap 
&bitmap 
) 
1305     *this = bitmap
.ConvertToImage(); 
1312 // A module to allow wxImage initialization/cleanup 
1313 // without calling these functions from app.cpp or from 
1314 // the user's application. 
1316 class wxImageModule
: public wxModule
 
1318 DECLARE_DYNAMIC_CLASS(wxImageModule
) 
1321     bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; }; 
1322     void OnExit() { wxImage::CleanUpHandlers(); }; 
1325 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
) 
1328 //----------------------------------------------------------------------------- 
1331 // Counts and returns the number of different colours. Optionally stops 
1332 // when it exceeds 'stopafter' different colours. This is useful, for 
1333 // example, to see if the image can be saved as 8-bit (256 colour or 
1334 // less, in this case it would be invoked as CountColours(256)). Default 
1335 // value for stopafter is -1 (don't care). 
1337 unsigned long wxImage::CountColours( unsigned long stopafter 
) const 
1341     unsigned char r
, g
, b
; 
1343     unsigned long size
, nentries
, key
; 
1346     size 
= GetWidth() * GetHeight(); 
1349     for (unsigned long j 
= 0; (j 
< size
) && (nentries 
<= stopafter
) ; j
++) 
1354         key 
= (r 
<< 16) | (g 
<< 8) | b
; 
1356         if (h
.Get(key
) == NULL
) 
1367 unsigned long wxImage::ComputeHistogram( wxImageHistogram 
&h 
) const 
1369     unsigned char r
, g
, b
; 
1371     unsigned long size
, nentries
, key
; 
1376     size 
= GetWidth() * GetHeight(); 
1379     for (unsigned long j 
= 0; j 
< size
; j
++) 
1384         key 
= (r 
<< 16) | (g 
<< 8) | b
; 
1386         wxImageHistogramEntry
& entry 
= h
[key
]; 
1387         if ( entry
.value
++ == 0 ) 
1388             entry
.index 
= nentries
++; 
1395  * Rotation code by Carlos Moreno 
1398 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which 
1399 //      does exactly the same thing. And I also got rid of wxRotationPixel 
1400 //      bacause of potential problems in architectures where alignment 
1401 //      is an issue, so I had to rewrite parts of the code. 
1403 static const double gs_Epsilon 
= 1e-10; 
1405 static inline int wxCint (double x
) 
1407     return (x 
> 0) ? (int) (x 
+ 0.5) : (int) (x 
- 0.5); 
1411 // Auxiliary function to rotate a point (x,y) with respect to point p0 
1412 // make it inline and use a straight return to facilitate optimization 
1413 // also, the function receives the sine and cosine of the angle to avoid 
1414 // repeating the time-consuming calls to these functions -- sin/cos can 
1415 // be computed and stored in the calling function. 
1417 inline wxRealPoint 
rotated_point (const wxRealPoint 
& p
, double cos_angle
, double sin_angle
, const wxRealPoint 
& p0
) 
1419     return wxRealPoint (p0
.x 
+ (p
.x 
- p0
.x
) * cos_angle 
- (p
.y 
- p0
.y
) * sin_angle
, 
1420                         p0
.y 
+ (p
.y 
- p0
.y
) * cos_angle 
+ (p
.x 
- p0
.x
) * sin_angle
); 
1423 inline wxRealPoint 
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint 
& p0
) 
1425     return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
); 
1428 wxImage 
wxImage::Rotate(double angle
, const wxPoint 
& centre_of_rotation
, bool interpolating
, wxPoint 
* offset_after_rotation
) const 
1431     angle 
= -angle
;     // screen coordinates are a mirror image of "real" coordinates 
1433     // Create pointer-based array to accelerate access to wxImage's data 
1434     unsigned char ** data 
= new unsigned char * [GetHeight()]; 
1436     data
[0] = GetData(); 
1438     for (i 
= 1; i 
< GetHeight(); i
++) 
1439         data
[i
] = data
[i 
- 1] + (3 * GetWidth()); 
1441     // precompute coefficients for rotation formula 
1442     // (sine and cosine of the angle) 
1443     const double cos_angle 
= cos(angle
); 
1444     const double sin_angle 
= sin(angle
); 
1446     // Create new Image to store the result 
1447     // First, find rectangle that covers the rotated image;  to do that, 
1448     // rotate the four corners 
1450     const wxRealPoint 
p0(centre_of_rotation
.x
, centre_of_rotation
.y
); 
1452     wxRealPoint p1 
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
); 
1453     wxRealPoint p2 
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
); 
1454     wxRealPoint p3 
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
); 
1455     wxRealPoint p4 
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
); 
1457     int x1 
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
))); 
1458     int y1 
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
))); 
1459     int x2 
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
))); 
1460     int y2 
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
))); 
1462     wxImage 
rotated (x2 
- x1 
+ 1, y2 
- y1 
+ 1); 
1464     if (offset_after_rotation 
!= NULL
) 
1466         *offset_after_rotation 
= wxPoint (x1
, y1
); 
1469     // GRG: The rotated (destination) image is always accessed 
1470     //      sequentially, so there is no need for a pointer-based 
1471     //      array here (and in fact it would be slower). 
1473     unsigned char * dst 
= rotated
.GetData(); 
1475     // GRG: if the original image has a mask, use its RGB values 
1476     //      as the blank pixel, else, fall back to default (black). 
1478     unsigned char blank_r 
= 0; 
1479     unsigned char blank_g 
= 0; 
1480     unsigned char blank_b 
= 0; 
1484         blank_r 
= GetMaskRed(); 
1485         blank_g 
= GetMaskGreen(); 
1486         blank_b 
= GetMaskBlue(); 
1487         rotated
.SetMaskColour( blank_r
, blank_g
, blank_b 
); 
1490     // Now, for each point of the rotated image, find where it came from, by 
1491     // performing an inverse rotation (a rotation of -angle) and getting the 
1492     // pixel at those coordinates 
1494     // GRG: I've taken the (interpolating) test out of the loops, so that 
1495     //      it is done only once, instead of repeating it for each pixel. 
1500         for (int y 
= 0; y 
< rotated
.GetHeight(); y
++) 
1502             for (x 
= 0; x 
< rotated
.GetWidth(); x
++) 
1504                 wxRealPoint src 
= rotated_point (x 
+ x1
, y 
+ y1
, cos_angle
, -sin_angle
, p0
); 
1506                 if (-0.25 < src
.x 
&& src
.x 
< GetWidth() - 0.75 && 
1507                     -0.25 < src
.y 
&& src
.y 
< GetHeight() - 0.75) 
1509                     // interpolate using the 4 enclosing grid-points.  Those 
1510                     // points can be obtained using floor and ceiling of the 
1511                     // exact coordinates of the point 
1512                         // C.M. 2000-02-17:  when the point is near the border, special care is required. 
1516                     if (0 < src
.x 
&& src
.x 
< GetWidth() - 1) 
1518                         x1 
= wxCint(floor(src
.x
)); 
1519                         x2 
= wxCint(ceil(src
.x
)); 
1521                     else    // else means that x is near one of the borders (0 or width-1) 
1523                         x1 
= x2 
= wxCint (src
.x
); 
1526                     if (0 < src
.y 
&& src
.y 
< GetHeight() - 1) 
1528                         y1 
= wxCint(floor(src
.y
)); 
1529                         y2 
= wxCint(ceil(src
.y
)); 
1533                         y1 
= y2 
= wxCint (src
.y
); 
1536                     // get four points and the distances (square of the distance, 
1537                     // for efficiency reasons) for the interpolation formula 
1539                     // GRG: Do not calculate the points until they are 
1540                     //      really needed -- this way we can calculate 
1541                     //      just one, instead of four, if d1, d2, d3 
1542                     //      or d4 are < gs_Epsilon 
1544                     const double d1 
= (src
.x 
- x1
) * (src
.x 
- x1
) + (src
.y 
- y1
) * (src
.y 
- y1
); 
1545                     const double d2 
= (src
.x 
- x2
) * (src
.x 
- x2
) + (src
.y 
- y1
) * (src
.y 
- y1
); 
1546                     const double d3 
= (src
.x 
- x2
) * (src
.x 
- x2
) + (src
.y 
- y2
) * (src
.y 
- y2
); 
1547                     const double d4 
= (src
.x 
- x1
) * (src
.x 
- x1
) + (src
.y 
- y2
) * (src
.y 
- y2
); 
1549                     // Now interpolate as a weighted average of the four surrounding 
1550                     // points, where the weights are the distances to each of those points 
1552                     // If the point is exactly at one point of the grid of the source 
1553                     // image, then don't interpolate -- just assign the pixel 
1555                     if (d1 
< gs_Epsilon
)        // d1,d2,d3,d4 are positive -- no need for abs() 
1557                         unsigned char *p 
= data
[y1
] + (3 * x1
); 
1562                     else if (d2 
< gs_Epsilon
) 
1564                         unsigned char *p 
= data
[y1
] + (3 * x2
); 
1569                     else if (d3 
< gs_Epsilon
) 
1571                         unsigned char *p 
= data
[y2
] + (3 * x2
); 
1576                     else if (d4 
< gs_Epsilon
) 
1578                         unsigned char *p 
= data
[y2
] + (3 * x1
); 
1585                         // weights for the weighted average are proportional to the inverse of the distance 
1586                         unsigned char *v1 
= data
[y1
] + (3 * x1
); 
1587                         unsigned char *v2 
= data
[y1
] + (3 * x2
); 
1588                         unsigned char *v3 
= data
[y2
] + (3 * x2
); 
1589                         unsigned char *v4 
= data
[y2
] + (3 * x1
); 
1591                         const double w1 
= 1/d1
, w2 
= 1/d2
, w3 
= 1/d3
, w4 
= 1/d4
; 
1595                         *(dst
++) = (unsigned char) 
1596                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1597                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1598                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1599                         *(dst
++) = (unsigned char) 
1600                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1601                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1602                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1603                         *(dst
++) = (unsigned char) 
1604                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1605                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1606                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1618     else    // not interpolating 
1620         for (int y 
= 0; y 
< rotated
.GetHeight(); y
++) 
1622             for (x 
= 0; x 
< rotated
.GetWidth(); x
++) 
1624                 wxRealPoint src 
= rotated_point (x 
+ x1
, y 
+ y1
, cos_angle
, -sin_angle
, p0
); 
1626                 const int xs 
= wxCint (src
.x
);      // wxCint rounds to the 
1627                 const int ys 
= wxCint (src
.y
);      // closest integer 
1629                 if (0 <= xs 
&& xs 
< GetWidth() && 
1630                     0 <= ys 
&& ys 
< GetHeight()) 
1632                     unsigned char *p 
= data
[ys
] + (3 * xs
); 
1652 #endif // wxUSE_IMAGE