1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  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" 
  46 //----------------------------------------------------------------------------- 
  48 //----------------------------------------------------------------------------- 
  50 class wxImageRefData
: public wxObjectRefData
 
  54     virtual ~wxImageRefData(); 
  58     unsigned char  *m_data
; 
  61     unsigned char   m_maskRed
,m_maskGreen
,m_maskBlue
; 
  63     // alpha channel data, may be NULL for the formats without alpha support 
  64     unsigned char  *m_alpha
; 
  71 #endif // wxUSE_PALETTE 
  73     wxArrayString   m_optionNames
; 
  74     wxArrayString   m_optionValues
; 
  76     DECLARE_NO_COPY_CLASS(wxImageRefData
) 
  79 wxImageRefData::wxImageRefData() 
  84     m_alpha 
= (unsigned char *) NULL
; 
  95 wxImageRefData::~wxImageRefData() 
 104 wxList 
wxImage::sm_handlers
; 
 108 //----------------------------------------------------------------------------- 
 110 #define M_IMGDATA ((wxImageRefData *)m_refData) 
 112 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
) 
 114 wxImage::wxImage( int width
, int height
, bool clear 
) 
 116     Create( width
, height
, clear 
); 
 119 wxImage::wxImage( int width
, int height
, unsigned char* data
, bool static_data 
) 
 121     Create( width
, height
, data
, static_data 
); 
 124 wxImage::wxImage( int width
, int height
, unsigned char* data
, unsigned char* alpha
, bool static_data 
) 
 126     Create( width
, height
, data
, alpha
, static_data 
); 
 129 wxImage::wxImage( const wxString
& name
, long type
, int index 
) 
 131     LoadFile( name
, type
, index 
); 
 134 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
, int index 
) 
 136     LoadFile( name
, mimetype
, index 
); 
 140 wxImage::wxImage( wxInputStream
& stream
, long type
, int index 
) 
 142     LoadFile( stream
, type
, index 
); 
 145 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
, int index 
) 
 147     LoadFile( stream
, mimetype
, index 
); 
 149 #endif // wxUSE_STREAMS 
 151 wxImage::wxImage( const wxImage
& image 
) 
 157 wxImage::wxImage( const wxImage
* image 
) 
 159     if (image
) Ref(*image
); 
 162 bool wxImage::Create( int width
, int height
, bool clear 
) 
 166     m_refData 
= new wxImageRefData(); 
 168     M_IMGDATA
->m_data 
= (unsigned char *) malloc( width
*height
*3 ); 
 169     if (!M_IMGDATA
->m_data
) 
 176         memset(M_IMGDATA
->m_data
, 0, width
*height
*3); 
 178     M_IMGDATA
->m_width 
= width
; 
 179     M_IMGDATA
->m_height 
= height
; 
 180     M_IMGDATA
->m_ok 
= true; 
 185 bool wxImage::Create( int width
, int height
, unsigned char* data
, bool static_data 
) 
 189     wxCHECK_MSG( data
, false, _T("NULL data in wxImage::Create") ); 
 191     m_refData 
= new wxImageRefData(); 
 193     M_IMGDATA
->m_data 
= data
; 
 194     M_IMGDATA
->m_width 
= width
; 
 195     M_IMGDATA
->m_height 
= height
; 
 196     M_IMGDATA
->m_ok 
= true; 
 197     M_IMGDATA
->m_static 
= static_data
; 
 202 bool wxImage::Create( int width
, int height
, unsigned char* data
, unsigned char* alpha
, bool static_data 
) 
 206     wxCHECK_MSG( data
, false, _T("NULL data in wxImage::Create") ); 
 208     m_refData 
= new wxImageRefData(); 
 210     M_IMGDATA
->m_data 
= data
; 
 211     M_IMGDATA
->m_alpha 
= alpha
; 
 212     M_IMGDATA
->m_width 
= width
; 
 213     M_IMGDATA
->m_height 
= height
; 
 214     M_IMGDATA
->m_ok 
= true; 
 215     M_IMGDATA
->m_static 
= static_data
; 
 220 void wxImage::Destroy() 
 225 wxImage 
wxImage::Copy() const 
 229     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 231     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
, false ); 
 233     unsigned char *data 
= image
.GetData(); 
 235     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 237     image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 238     image
.SetMask( M_IMGDATA
->m_hasMask 
); 
 240     memcpy( data
, GetData(), M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3 ); 
 242     // also copy the image options 
 243     wxImageRefData 
*imgData 
= (wxImageRefData 
*)image
.m_refData
; 
 244     imgData
->m_optionNames 
= M_IMGDATA
->m_optionNames
; 
 245     imgData
->m_optionValues 
= M_IMGDATA
->m_optionValues
; 
 250 wxImage 
wxImage::ShrinkBy( int xFactor 
, int yFactor 
) const 
 252     if( xFactor 
== 1 && yFactor 
== 1 ) 
 257     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 259     // can't scale to/from 0 size 
 260     wxCHECK_MSG( (xFactor 
> 0) && (yFactor 
> 0), image
, 
 261                  wxT("invalid new image size") ); 
 263     long old_height 
= M_IMGDATA
->m_height
, 
 264          old_width  
= M_IMGDATA
->m_width
; 
 266     wxCHECK_MSG( (old_height 
> 0) && (old_width 
> 0), image
, 
 267                  wxT("invalid old image size") ); 
 269     long width 
= old_width 
/ xFactor 
; 
 270     long height 
= old_height 
/ yFactor 
; 
 272     image
.Create( width
, height
, false ); 
 274     char unsigned *data 
= image
.GetData(); 
 276     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 278     bool hasMask 
= false ; 
 279     unsigned char maskRed 
= 0; 
 280     unsigned char maskGreen 
= 0; 
 281     unsigned char maskBlue 
=0 ; 
 283     unsigned char *source_data 
= M_IMGDATA
->m_data
; 
 284     unsigned char *target_data 
= data
; 
 285     unsigned char *source_alpha 
= 0 ; 
 286     unsigned char *target_alpha 
= 0 ; 
 287     if (M_IMGDATA
->m_hasMask
) 
 290         maskRed 
= M_IMGDATA
->m_maskRed
; 
 291         maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 292         maskBlue 
=M_IMGDATA
->m_maskBlue 
; 
 294         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, 
 295                              M_IMGDATA
->m_maskGreen
, 
 296                              M_IMGDATA
->m_maskBlue 
); 
 300         source_alpha 
= M_IMGDATA
->m_alpha 
; 
 304             target_alpha 
= image
.GetAlpha() ; 
 308     for (long y 
= 0; y 
< height
; y
++) 
 310         for (long x 
= 0; x 
< width
; x
++) 
 312             unsigned long avgRed 
= 0 ; 
 313             unsigned long avgGreen 
= 0; 
 314             unsigned long avgBlue 
= 0; 
 315             unsigned long avgAlpha 
= 0 ; 
 316             unsigned long counter 
= 0 ; 
 318             for ( int y1 
= 0 ; y1 
< yFactor 
; ++y1 
) 
 320                 long y_offset 
= (y 
* yFactor 
+ y1
) * old_width
; 
 321                 for ( int x1 
= 0 ; x1 
< xFactor 
; ++x1 
) 
 323                     unsigned char *pixel 
= source_data 
+ 3 * ( y_offset 
+ x 
* xFactor 
+ x1 
) ; 
 324                     unsigned char red 
= pixel
[0] ; 
 325                     unsigned char green 
= pixel
[1] ; 
 326                     unsigned char blue 
= pixel
[2] ; 
 327                     unsigned char alpha 
= 255  ; 
 329                         alpha 
= *(source_alpha 
+ y_offset 
+ x 
* xFactor 
+ x1
) ; 
 330                     if ( !hasMask 
|| red 
!= maskRed 
|| green 
!= maskGreen 
|| blue 
!= maskBlue 
) 
 345                 *(target_data
++) = M_IMGDATA
->m_maskRed 
; 
 346                 *(target_data
++) = M_IMGDATA
->m_maskGreen 
; 
 347                 *(target_data
++) = M_IMGDATA
->m_maskBlue 
; 
 352                     *(target_alpha
++) = (unsigned char)(avgAlpha 
/ counter 
) ; 
 353                 *(target_data
++) = (unsigned char)(avgRed 
/ counter
); 
 354                 *(target_data
++) = (unsigned char)(avgGreen 
/ counter
); 
 355                 *(target_data
++) = (unsigned char)(avgBlue 
/ counter
); 
 360     // In case this is a cursor, make sure the hotspot is scalled accordingly: 
 361     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
) ) 
 362         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
, 
 363                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
))/xFactor
); 
 364     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
) ) 
 365         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
, 
 366                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))/yFactor
); 
 371 wxImage 
wxImage::Scale( int width
, int height 
) const 
 375     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 377     // can't scale to/from 0 size 
 378     wxCHECK_MSG( (width 
> 0) && (height 
> 0), image
, 
 379                  wxT("invalid new image size") ); 
 381     long old_height 
= M_IMGDATA
->m_height
, 
 382          old_width  
= M_IMGDATA
->m_width
; 
 383     wxCHECK_MSG( (old_height 
> 0) && (old_width 
> 0), image
, 
 384                  wxT("invalid old image size") ); 
 386     if ( old_width 
% width 
== 0 && old_width 
>= width 
&& 
 387         old_height 
% height 
== 0 && old_height 
>= height 
) 
 389         return ShrinkBy( old_width 
/ width 
, old_height 
/ height 
) ; 
 391     image
.Create( width
, height
, false ); 
 393     unsigned char *data 
= image
.GetData(); 
 395     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 397     unsigned char *source_data 
= M_IMGDATA
->m_data
; 
 398     unsigned char *target_data 
= data
; 
 399     unsigned char *source_alpha 
= 0 ; 
 400     unsigned char *target_alpha 
= 0 ; 
 402     if (M_IMGDATA
->m_hasMask
) 
 404         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, 
 405                              M_IMGDATA
->m_maskGreen
, 
 406                              M_IMGDATA
->m_maskBlue 
); 
 410         source_alpha 
= M_IMGDATA
->m_alpha 
; 
 414             target_alpha 
= image
.GetAlpha() ; 
 418     long x_delta 
= (old_width
<<16) / width
; 
 419     long y_delta 
= (old_height
<<16) / height
; 
 421     unsigned char* dest_pixel 
= target_data
; 
 424     for ( long j 
= 0; j 
< height
; j
++ ) 
 426         unsigned char* src_line 
= &source_data
[(y
>>16)*old_width
*3]; 
 427         unsigned char* src_alpha_line 
= source_alpha 
? &source_alpha
[(y
>>16)*old_width
] : 0 ; 
 430         for ( long i 
= 0; i 
< width
; i
++ ) 
 432              unsigned char* src_pixel 
= &src_line
[(x
>>16)*3]; 
 433              unsigned char* src_alpha_pixel 
= source_alpha 
? &src_alpha_line
[(x
>>16)] : 0 ; 
 434              dest_pixel
[0] = src_pixel
[0]; 
 435              dest_pixel
[1] = src_pixel
[1]; 
 436              dest_pixel
[2] = src_pixel
[2]; 
 439                 *(target_alpha
++) = *src_alpha_pixel 
; 
 446     // In case this is a cursor, make sure the hotspot is scalled accordingly: 
 447     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
) ) 
 448         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
, 
 449                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
)*width
)/old_width
); 
 450     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
) ) 
 451         image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
, 
 452                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)*height
)/old_height
); 
 457 wxImage 
wxImage::Rotate90( bool clockwise 
) const 
 461     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 463     image
.Create( M_IMGDATA
->m_height
, M_IMGDATA
->m_width
, false ); 
 465     unsigned char *data 
= image
.GetData(); 
 467     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 469     if (M_IMGDATA
->m_hasMask
) 
 470         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 472     long height 
= M_IMGDATA
->m_height
; 
 473     long width  
= M_IMGDATA
->m_width
; 
 475     unsigned char *source_data 
= M_IMGDATA
->m_data
; 
 476     unsigned char *target_data
; 
 478     for (long j 
= 0; j 
< height
; j
++) 
 480         for (long i 
= 0; i 
< width
; i
++) 
 483                 target_data 
= data 
+ (((i
+1)*height
) - j 
- 1)*3; 
 485                 target_data 
= data 
+ ((height
*(width
-1)) + j 
- (i
*height
))*3; 
 486             memcpy( target_data
, source_data
, 3 ); 
 494 wxImage 
wxImage::Mirror( bool horizontally 
) const 
 498     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 500     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
, false ); 
 502     unsigned char *data 
= image
.GetData(); 
 504     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 506     if (M_IMGDATA
->m_hasMask
) 
 507         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 509     long height 
= M_IMGDATA
->m_height
; 
 510     long width  
= M_IMGDATA
->m_width
; 
 512     unsigned char *source_data 
= M_IMGDATA
->m_data
; 
 513     unsigned char *target_data
; 
 517         for (long j 
= 0; j 
< height
; j
++) 
 520             target_data 
= data
-3; 
 521             for (long i 
= 0; i 
< width
; i
++) 
 523                 memcpy( target_data
, source_data
, 3 ); 
 531         for (long i 
= 0; i 
< height
; i
++) 
 533             target_data 
= data 
+ 3*width
*(height
-1-i
); 
 534             memcpy( target_data
, source_data
, (size_t)3*width 
); 
 535             source_data 
+= 3*width
; 
 542 wxImage 
wxImage::GetSubImage( const wxRect 
&rect 
) const 
 546     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 548     wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()), 
 549                  image
, wxT("invalid subimage size") ); 
 551     int subwidth
=rect
.GetWidth(); 
 552     const int subheight
=rect
.GetHeight(); 
 554     image
.Create( subwidth
, subheight
, false ); 
 556     unsigned char *subdata 
= image
.GetData(), *data
=GetData(); 
 558     wxCHECK_MSG( subdata
, image
, wxT("unable to create image") ); 
 560     if (M_IMGDATA
->m_hasMask
) 
 561         image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue 
); 
 563     const int subleft
=3*rect
.GetLeft(); 
 564     const int width
=3*GetWidth(); 
 567     data
+=rect
.GetTop()*width
+subleft
; 
 569     for (long j 
= 0; j 
< subheight
; ++j
) 
 571         memcpy( subdata
, data
, subwidth
); 
 579 void wxImage::Paste( const wxImage 
&image
, int x
, int y 
) 
 581     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 582     wxCHECK_RET( image
.Ok(), wxT("invalid image") ); 
 586     int width 
= image
.GetWidth(); 
 587     int height 
= image
.GetHeight(); 
 600     if ((x
+xx
)+width 
> M_IMGDATA
->m_width
) 
 601         width 
= M_IMGDATA
->m_width 
- (x
+xx
); 
 602     if ((y
+yy
)+height 
> M_IMGDATA
->m_height
) 
 603         height 
= M_IMGDATA
->m_height 
- (y
+yy
); 
 605     if (width 
< 1) return; 
 606     if (height 
< 1) return; 
 608     if ((!HasMask() && !image
.HasMask()) || 
 609        ((HasMask() && image
.HasMask() && 
 610          (GetMaskRed()==image
.GetMaskRed()) && 
 611          (GetMaskGreen()==image
.GetMaskGreen()) && 
 612          (GetMaskBlue()==image
.GetMaskBlue())))) 
 615         unsigned char* source_data 
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth(); 
 616         int source_step 
= image
.GetWidth()*3; 
 618         unsigned char* target_data 
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
; 
 619         int target_step 
= M_IMGDATA
->m_width
*3; 
 620         for (int j 
= 0; j 
< height
; j
++) 
 622             memcpy( target_data
, source_data
, width 
); 
 623             source_data 
+= source_step
; 
 624             target_data 
+= target_step
; 
 629     if (!HasMask() && image
.HasMask()) 
 631         unsigned char r 
= image
.GetMaskRed(); 
 632         unsigned char g 
= image
.GetMaskGreen(); 
 633         unsigned char b 
= image
.GetMaskBlue(); 
 636         unsigned char* source_data 
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth(); 
 637         int source_step 
= image
.GetWidth()*3; 
 639         unsigned char* target_data 
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
; 
 640         int target_step 
= M_IMGDATA
->m_width
*3; 
 642         for (int j 
= 0; j 
< height
; j
++) 
 644             for (int i 
= 0; i 
< width
; i
+=3) 
 646                 if ((source_data
[i
]   != r
) && 
 647                     (source_data
[i
+1] != g
) && 
 648                     (source_data
[i
+2] != b
)) 
 650                     memcpy( target_data
+i
, source_data
+i
, 3 ); 
 653             source_data 
+= source_step
; 
 654             target_data 
+= target_step
; 
 659 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
, 
 660                        unsigned char r2
, unsigned char g2
, unsigned char b2 
) 
 662     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 664     unsigned char *data 
= GetData(); 
 666     const int w 
= GetWidth(); 
 667     const int h 
= GetHeight(); 
 669     for (int j 
= 0; j 
< h
; j
++) 
 670         for (int i 
= 0; i 
< w
; i
++) 
 672             if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
)) 
 682 wxImage 
wxImage::ConvertToMono( unsigned char r
, unsigned char g
, unsigned char b 
) const 
 686     wxCHECK_MSG( Ok(), image
, wxT("invalid image") ); 
 688     image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
, false ); 
 690     unsigned char *data 
= image
.GetData(); 
 692     wxCHECK_MSG( data
, image
, wxT("unable to create image") ); 
 694     if (M_IMGDATA
->m_hasMask
) 
 696         if (M_IMGDATA
->m_maskRed 
== r 
&& M_IMGDATA
->m_maskGreen 
== g 
&& 
 697                                          M_IMGDATA
->m_maskBlue 
== b
) 
 698             image
.SetMaskColour( 255, 255, 255 ); 
 700             image
.SetMaskColour( 0, 0, 0 ); 
 703     long size 
= M_IMGDATA
->m_height 
* M_IMGDATA
->m_width
; 
 705     unsigned char *srcd 
= M_IMGDATA
->m_data
; 
 706     unsigned char *tard 
= image
.GetData(); 
 708     for ( long i 
= 0; i 
< size
; i
++, srcd 
+= 3, tard 
+= 3 ) 
 710         if (srcd
[0] == r 
&& srcd
[1] == g 
&& srcd
[2] == b
) 
 711             tard
[0] = tard
[1] = tard
[2] = 255; 
 713             tard
[0] = tard
[1] = tard
[2] = 0; 
 719 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b 
) 
 721     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 723     int w 
= M_IMGDATA
->m_width
; 
 724     int h 
= M_IMGDATA
->m_height
; 
 726     wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") ); 
 728     long pos 
= (y 
* w 
+ x
) * 3; 
 730     M_IMGDATA
->m_data
[ pos   
] = r
; 
 731     M_IMGDATA
->m_data
[ pos
+1 ] = g
; 
 732     M_IMGDATA
->m_data
[ pos
+2 ] = b
; 
 735 unsigned char wxImage::GetRed( int x
, int y 
) const 
 737     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 739     int w 
= M_IMGDATA
->m_width
; 
 740     int h 
= M_IMGDATA
->m_height
; 
 742     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 744     long pos 
= (y 
* w 
+ x
) * 3; 
 746     return M_IMGDATA
->m_data
[pos
]; 
 749 unsigned char wxImage::GetGreen( int x
, int y 
) const 
 751     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 753     int w 
= M_IMGDATA
->m_width
; 
 754     int h 
= M_IMGDATA
->m_height
; 
 756     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 758     long pos 
= (y 
* w 
+ x
) * 3; 
 760     return M_IMGDATA
->m_data
[pos
+1]; 
 763 unsigned char wxImage::GetBlue( int x
, int y 
) const 
 765     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 767     int w 
= M_IMGDATA
->m_width
; 
 768     int h 
= M_IMGDATA
->m_height
; 
 770     wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") ); 
 772     long pos 
= (y 
* w 
+ x
) * 3; 
 774     return M_IMGDATA
->m_data
[pos
+2]; 
 777 bool wxImage::Ok() const 
 779     // image of 0 width or height can't be considered ok - at least because it 
 780     // causes crashes in ConvertToBitmap() if we don't catch it in time 
 781     wxImageRefData 
*data 
= M_IMGDATA
; 
 782     return data 
&& data
->m_ok 
&& data
->m_width 
&& data
->m_height
; 
 785 unsigned char *wxImage::GetData() const 
 787     wxCHECK_MSG( Ok(), (unsigned char *)NULL
, wxT("invalid image") ); 
 789     return M_IMGDATA
->m_data
; 
 792 void wxImage::SetData( unsigned char *data 
) 
 794     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 796     wxImageRefData 
*newRefData 
= new wxImageRefData(); 
 798     newRefData
->m_width 
= M_IMGDATA
->m_width
; 
 799     newRefData
->m_height 
= M_IMGDATA
->m_height
; 
 800     newRefData
->m_data 
= data
; 
 801     newRefData
->m_ok 
= true; 
 802     newRefData
->m_maskRed 
= M_IMGDATA
->m_maskRed
; 
 803     newRefData
->m_maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 804     newRefData
->m_maskBlue 
= M_IMGDATA
->m_maskBlue
; 
 805     newRefData
->m_hasMask 
= M_IMGDATA
->m_hasMask
; 
 809     m_refData 
= newRefData
; 
 812 void wxImage::SetData( unsigned char *data
, int new_width
, int new_height 
) 
 814     wxImageRefData 
*newRefData 
= new wxImageRefData(); 
 818         newRefData
->m_width 
= new_width
; 
 819         newRefData
->m_height 
= new_height
; 
 820         newRefData
->m_data 
= data
; 
 821         newRefData
->m_ok 
= true; 
 822         newRefData
->m_maskRed 
= M_IMGDATA
->m_maskRed
; 
 823         newRefData
->m_maskGreen 
= M_IMGDATA
->m_maskGreen
; 
 824         newRefData
->m_maskBlue 
= M_IMGDATA
->m_maskBlue
; 
 825         newRefData
->m_hasMask 
= M_IMGDATA
->m_hasMask
; 
 829         newRefData
->m_width 
= new_width
; 
 830         newRefData
->m_height 
= new_height
; 
 831         newRefData
->m_data 
= data
; 
 832         newRefData
->m_ok 
= true; 
 837     m_refData 
= newRefData
; 
 840 // ---------------------------------------------------------------------------- 
 841 // alpha channel support 
 842 // ---------------------------------------------------------------------------- 
 844 void wxImage::SetAlpha(int x
, int y
, unsigned char alpha
) 
 846     wxCHECK_RET( Ok() && HasAlpha(), wxT("invalid image or no alpha channel") ); 
 848     int w 
= M_IMGDATA
->m_width
, 
 849         h 
= M_IMGDATA
->m_height
; 
 851     wxCHECK_RET( x 
>=0 && y 
>= 0 && x 
< w 
&& y 
< h
, wxT("invalid image index") ); 
 853     M_IMGDATA
->m_alpha
[y
*w 
+ x
] = alpha
; 
 856 unsigned char wxImage::GetAlpha(int x
, int y
) const 
 858     wxCHECK_MSG( Ok() && HasAlpha(), 0, wxT("invalid image or no alpha channel") ); 
 860     int w 
= M_IMGDATA
->m_width
, 
 861         h 
= M_IMGDATA
->m_height
; 
 863     wxCHECK_MSG( x 
>=0 && y 
>= 0 && x 
< w 
&& y 
< h
, 0, wxT("invalid image index") ); 
 865     return M_IMGDATA
->m_alpha
[y
*w 
+ x
]; 
 868 bool wxImage::ConvertColourToAlpha( unsigned char r
, unsigned char g
, unsigned char b 
) 
 872     int w 
= M_IMGDATA
->m_width
, 
 873         h 
= M_IMGDATA
->m_height
; 
 875     unsigned char *alpha 
= GetAlpha(); 
 876     unsigned char *data 
= GetData(); 
 879     for (y 
= 0; y 
< h
; y
++) 
 880         for (x 
= 0; x 
< w
; x
++) 
 895 void wxImage::SetAlpha( unsigned char *alpha 
) 
 897     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 901         alpha 
= (unsigned char *)malloc(M_IMGDATA
->m_width
*M_IMGDATA
->m_height
); 
 904     free(M_IMGDATA
->m_alpha
); 
 905     M_IMGDATA
->m_alpha 
= alpha
; 
 908 unsigned char *wxImage::GetAlpha() const 
 910     wxCHECK_MSG( Ok(), (unsigned char *)NULL
, wxT("invalid image") ); 
 912     return M_IMGDATA
->m_alpha
; 
 915 // ---------------------------------------------------------------------------- 
 917 // ---------------------------------------------------------------------------- 
 919 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b 
) 
 921     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 923     M_IMGDATA
->m_maskRed 
= r
; 
 924     M_IMGDATA
->m_maskGreen 
= g
; 
 925     M_IMGDATA
->m_maskBlue 
= b
; 
 926     M_IMGDATA
->m_hasMask 
= true; 
 929 unsigned char wxImage::GetMaskRed() const 
 931     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 933     return M_IMGDATA
->m_maskRed
; 
 936 unsigned char wxImage::GetMaskGreen() const 
 938     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 940     return M_IMGDATA
->m_maskGreen
; 
 943 unsigned char wxImage::GetMaskBlue() const 
 945     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 947     return M_IMGDATA
->m_maskBlue
; 
 950 void wxImage::SetMask( bool mask 
) 
 952     wxCHECK_RET( Ok(), wxT("invalid image") ); 
 954     M_IMGDATA
->m_hasMask 
= mask
; 
 957 bool wxImage::HasMask() const 
 959     wxCHECK_MSG( Ok(), false, wxT("invalid image") ); 
 961     return M_IMGDATA
->m_hasMask
; 
 964 int wxImage::GetWidth() const 
 966     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 968     return M_IMGDATA
->m_width
; 
 971 int wxImage::GetHeight() const 
 973     wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); 
 975     return M_IMGDATA
->m_height
; 
 978 bool wxImage::SetMaskFromImage(const wxImage
& mask
, 
 979                                unsigned char mr
, unsigned char mg
, unsigned char mb
) 
 981     // check that the images are the same size 
 982     if ( (M_IMGDATA
->m_height 
!= mask
.GetHeight() ) || (M_IMGDATA
->m_width 
!= mask
.GetWidth () ) ) 
 984         wxLogError( _("Image and mask have different sizes.") ); 
 988     // find unused colour 
 989     unsigned char r
,g
,b 
; 
 990     if (!FindFirstUnusedColour(&r
, &g
, &b
)) 
 992         wxLogError( _("No unused colour in image being masked.") ); 
 996     unsigned char *imgdata 
= GetData(); 
 997     unsigned char *maskdata 
= mask
.GetData(); 
 999     const int w 
= GetWidth(); 
1000     const int h 
= GetHeight(); 
1002     for (int j 
= 0; j 
< h
; j
++) 
1004         for (int i 
= 0; i 
< w
; i
++) 
1006             if ((maskdata
[0] == mr
) && (maskdata
[1]  == mg
) && (maskdata
[2] == mb
)) 
1017     SetMaskColour(r
, g
, b
); 
1023 bool wxImage::ConvertAlphaToMask(unsigned char threshold
) 
1028     unsigned char mr
, mg
, mb
; 
1029     if (!FindFirstUnusedColour(&mr
, &mg
, &mb
)) 
1031         wxLogError( _("No unused colour in image being masked.") ); 
1036     SetMaskColour(mr
, mg
, mb
); 
1038     unsigned char *imgdata 
= GetData(); 
1039     unsigned char *alphadata 
= GetAlpha(); 
1042     int h 
= GetHeight(); 
1044     for (int y 
= 0; y 
< h
; y
++) 
1046         for (int x 
= 0; x 
< w
; x
++, imgdata 
+= 3, alphadata
++) 
1048             if (*alphadata 
< threshold
) 
1057     free(M_IMGDATA
->m_alpha
); 
1058     M_IMGDATA
->m_alpha 
= NULL
; 
1065 // Palette functions 
1067 bool wxImage::HasPalette() const 
1072     return M_IMGDATA
->m_palette
.Ok(); 
1075 const wxPalette
& wxImage::GetPalette() const 
1077     wxCHECK_MSG( Ok(), wxNullPalette
, wxT("invalid image") ); 
1079     return M_IMGDATA
->m_palette
; 
1082 void wxImage::SetPalette(const wxPalette
& palette
) 
1084     wxCHECK_RET( Ok(), wxT("invalid image") ); 
1086     M_IMGDATA
->m_palette 
= palette
; 
1089 #endif // wxUSE_PALETTE 
1091 // Option functions (arbitrary name/value mapping) 
1092 void wxImage::SetOption(const wxString
& name
, const wxString
& value
) 
1094     wxCHECK_RET( Ok(), wxT("invalid image") ); 
1096     int idx 
= M_IMGDATA
->m_optionNames
.Index(name
, false); 
1097     if (idx 
== wxNOT_FOUND
) 
1099         M_IMGDATA
->m_optionNames
.Add(name
); 
1100         M_IMGDATA
->m_optionValues
.Add(value
); 
1104         M_IMGDATA
->m_optionNames
[idx
] = name
; 
1105         M_IMGDATA
->m_optionValues
[idx
] = value
; 
1109 void wxImage::SetOption(const wxString
& name
, int value
) 
1112     valStr
.Printf(wxT("%d"), value
); 
1113     SetOption(name
, valStr
); 
1116 wxString 
wxImage::GetOption(const wxString
& name
) const 
1118     wxCHECK_MSG( Ok(), wxEmptyString
, wxT("invalid image") ); 
1120     int idx 
= M_IMGDATA
->m_optionNames
.Index(name
, false); 
1121     if (idx 
== wxNOT_FOUND
) 
1122         return wxEmptyString
; 
1124         return M_IMGDATA
->m_optionValues
[idx
]; 
1127 int wxImage::GetOptionInt(const wxString
& name
) const 
1129     return wxAtoi(GetOption(name
)); 
1132 bool wxImage::HasOption(const wxString
& name
) const 
1134     wxCHECK_MSG( Ok(), false, wxT("invalid image") ); 
1136     return (M_IMGDATA
->m_optionNames
.Index(name
, false) != wxNOT_FOUND
); 
1139 bool wxImage::LoadFile( const wxString
& filename
, long type
, int index 
) 
1142     if (wxFileExists(filename
)) 
1144         wxFileInputStream 
stream(filename
); 
1145         wxBufferedInputStream 
bstream( stream 
); 
1146         return LoadFile(bstream
, type
, index
); 
1150         wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() ); 
1154 #else // !wxUSE_STREAMS 
1156 #endif // wxUSE_STREAMS 
1159 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
, int index 
) 
1162     if (wxFileExists(filename
)) 
1164         wxFileInputStream 
stream(filename
); 
1165         wxBufferedInputStream 
bstream( stream 
); 
1166         return LoadFile(bstream
, mimetype
, index
); 
1170         wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() ); 
1174 #else // !wxUSE_STREAMS 
1176 #endif // wxUSE_STREAMS 
1181 bool wxImage::SaveFile( const wxString
& filename 
) const 
1183     wxString ext 
= filename
.AfterLast('.').Lower(); 
1185     wxImageHandler 
* pHandler 
= FindHandler(ext
, -1); 
1188         SaveFile(filename
, pHandler
->GetType()); 
1192     wxLogError(_("Can't save image to file '%s': unknown extension."), filename
.c_str()); 
1197 bool wxImage::SaveFile( const wxString
& filename
, int type 
) const 
1200     ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
); 
1202     wxFileOutputStream 
stream(filename
); 
1204     if ( stream
.IsOk() ) 
1206         wxBufferedOutputStream 
bstream( stream 
); 
1207         return SaveFile(bstream
, type
); 
1209 #endif // wxUSE_STREAMS 
1214 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype 
) const 
1217     ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
); 
1219     wxFileOutputStream 
stream(filename
); 
1221     if ( stream
.IsOk() ) 
1223         wxBufferedOutputStream 
bstream( stream 
); 
1224         return SaveFile(bstream
, mimetype
); 
1226 #endif // wxUSE_STREAMS 
1231 bool wxImage::CanRead( const wxString 
&name 
) 
1234   wxFileInputStream 
stream(name
); 
1235   return CanRead(stream
); 
1241 int wxImage::GetImageCount( const wxString 
&name
, long type 
) 
1244   wxFileInputStream 
stream(name
); 
1246       return GetImageCount(stream
, type
); 
1254 bool wxImage::CanRead( wxInputStream 
&stream 
) 
1256     const wxList
& list 
= GetHandlers(); 
1258     for ( wxList::compatibility_iterator node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
1260         wxImageHandler 
*handler
=(wxImageHandler
*)node
->GetData(); 
1261         if (handler
->CanRead( stream 
)) 
1268 int wxImage::GetImageCount( wxInputStream 
&stream
, long type 
) 
1270     wxImageHandler 
*handler
; 
1272     if ( type 
== wxBITMAP_TYPE_ANY 
) 
1274         wxList 
&list
=GetHandlers(); 
1276         for (wxList::compatibility_iterator node 
= list
.GetFirst(); node
; node 
= node
->GetNext()) 
1278              handler
=(wxImageHandler
*)node
->GetData(); 
1279              if ( handler
->CanRead(stream
) ) 
1280                  return handler
->GetImageCount(stream
); 
1284         wxLogWarning(_("No handler found for image type.")); 
1288     handler 
= FindHandler(type
); 
1292         wxLogWarning(_("No image handler for type %d defined."), type
); 
1296     if ( handler
->CanRead(stream
) ) 
1298         return handler
->GetImageCount(stream
); 
1302         wxLogError(_("Image file is not of type %d."), type
); 
1307 bool wxImage::LoadFile( wxInputStream
& stream
, long type
, int index 
) 
1311     m_refData 
= new wxImageRefData
; 
1313     wxImageHandler 
*handler
; 
1315     if ( type 
== wxBITMAP_TYPE_ANY 
) 
1317         wxList 
&list
=GetHandlers(); 
1319         for ( wxList::compatibility_iterator node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
1321              handler
=(wxImageHandler
*)node
->GetData(); 
1322              if ( handler
->CanRead(stream
) ) 
1323                  return handler
->LoadFile(this, stream
, true/*verbose*/, index
); 
1327         wxLogWarning( _("No handler found for image type.") ); 
1331     handler 
= FindHandler(type
); 
1335         wxLogWarning( _("No image handler for type %d defined."), type 
); 
1340     return handler
->LoadFile(this, stream
, true/*verbose*/, index
); 
1343 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
, int index 
) 
1347     m_refData 
= new wxImageRefData
; 
1349     wxImageHandler 
*handler 
= FindHandlerMime(mimetype
); 
1353         wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() ); 
1358     return handler
->LoadFile( this, stream
, true/*verbose*/, index 
); 
1361 bool wxImage::SaveFile( wxOutputStream
& stream
, int type 
) const 
1363     wxCHECK_MSG( Ok(), false, wxT("invalid image") ); 
1365     wxImageHandler 
*handler 
= FindHandler(type
); 
1369         wxLogWarning( _("No image handler for type %d defined."), type 
); 
1374     return handler
->SaveFile( (wxImage
*)this, stream 
); 
1377 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype 
) const 
1379     wxCHECK_MSG( Ok(), false, wxT("invalid image") ); 
1381     wxImageHandler 
*handler 
= FindHandlerMime(mimetype
); 
1385         wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() ); 
1390     return handler
->SaveFile( (wxImage
*)this, stream 
); 
1392 #endif // wxUSE_STREAMS 
1394 void wxImage::AddHandler( wxImageHandler 
*handler 
) 
1396     // Check for an existing handler of the type being added. 
1397     if (FindHandler( handler
->GetType() ) == 0) 
1399         sm_handlers
.Append( handler 
); 
1403         // This is not documented behaviour, merely the simplest 'fix' 
1404         // for preventing duplicate additions.  If someone ever has 
1405         // a good reason to add and remove duplicate handlers (and they 
1406         // may) we should probably refcount the duplicates. 
1407         //   also an issue in InsertHandler below. 
1409         wxLogDebug( _T("Adding duplicate image handler for '%s'"), 
1410                     handler
->GetName().c_str() ); 
1415 void wxImage::InsertHandler( wxImageHandler 
*handler 
) 
1417     // Check for an existing handler of the type being added. 
1418     if (FindHandler( handler
->GetType() ) == 0) 
1420         sm_handlers
.Insert( handler 
); 
1424         // see AddHandler for additional comments. 
1425         wxLogDebug( _T("Inserting duplicate image handler for '%s'"), 
1426                     handler
->GetName().c_str() ); 
1431 bool wxImage::RemoveHandler( const wxString
& name 
) 
1433     wxImageHandler 
*handler 
= FindHandler(name
); 
1436         sm_handlers
.DeleteObject(handler
); 
1444 wxImageHandler 
*wxImage::FindHandler( const wxString
& name 
) 
1446     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
1449         wxImageHandler 
*handler 
= (wxImageHandler
*)node
->GetData(); 
1450         if (handler
->GetName().Cmp(name
) == 0) return handler
; 
1452         node 
= node
->GetNext(); 
1457 wxImageHandler 
*wxImage::FindHandler( const wxString
& extension
, long bitmapType 
) 
1459     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
1462         wxImageHandler 
*handler 
= (wxImageHandler
*)node
->GetData(); 
1463         if ( (handler
->GetExtension().Cmp(extension
) == 0) && 
1464             (bitmapType 
== -1 || handler
->GetType() == bitmapType
) ) 
1466         node 
= node
->GetNext(); 
1471 wxImageHandler 
*wxImage::FindHandler( long bitmapType 
) 
1473     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
1476         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->GetData(); 
1477         if (handler
->GetType() == bitmapType
) return handler
; 
1478         node 
= node
->GetNext(); 
1483 wxImageHandler 
*wxImage::FindHandlerMime( const wxString
& mimetype 
) 
1485     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
1488         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->GetData(); 
1489         if (handler
->GetMimeType().IsSameAs(mimetype
, false)) return handler
; 
1490         node 
= node
->GetNext(); 
1495 void wxImage::InitStandardHandlers() 
1498     AddHandler(new wxBMPHandler
); 
1499 #endif // wxUSE_STREAMS 
1502 void wxImage::CleanUpHandlers() 
1504     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
1507         wxImageHandler 
*handler 
= (wxImageHandler 
*)node
->GetData(); 
1508         wxList::compatibility_iterator next 
= node
->GetNext(); 
1513     sm_handlers
.Clear(); 
1516 wxString 
wxImage::GetImageExtWildcard() 
1520     wxList
& Handlers 
= wxImage::GetHandlers(); 
1521     wxList::compatibility_iterator Node 
= Handlers
.GetFirst(); 
1524         wxImageHandler
* Handler 
= (wxImageHandler
*)Node
->GetData(); 
1525         fmts 
+= wxT("*.") + Handler
->GetExtension(); 
1526         Node 
= Node
->GetNext(); 
1527         if ( Node 
) fmts 
+= wxT(";"); 
1530     return wxT("(") + fmts 
+ wxT(")|") + fmts
; 
1533 //----------------------------------------------------------------------------- 
1535 //----------------------------------------------------------------------------- 
1537 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
) 
1540 bool wxImageHandler::LoadFile( wxImage 
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) ) 
1545 bool wxImageHandler::SaveFile( wxImage 
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) ) 
1550 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) ) 
1555 bool wxImageHandler::CanRead( const wxString
& name 
) 
1557     if (wxFileExists(name
)) 
1559         wxFileInputStream 
stream(name
); 
1560         return CanRead(stream
); 
1563     wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() ); 
1568 bool wxImageHandler::CallDoCanRead(wxInputStream
& stream
) 
1570     wxFileOffset posOld 
= stream
.TellI(); 
1571     if ( posOld 
== wxInvalidOffset 
) 
1573         // can't test unseekable stream 
1577     bool ok 
= DoCanRead(stream
); 
1579     // restore the old position to be able to test other formats and so on 
1580     if ( stream
.SeekI(posOld
) == wxInvalidOffset 
) 
1582         wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!")); 
1584         // reading would fail anyhow as we're not at the right position 
1591 #endif // wxUSE_STREAMS 
1593 // ---------------------------------------------------------------------------- 
1594 // image histogram stuff 
1595 // ---------------------------------------------------------------------------- 
1598 wxImageHistogram::FindFirstUnusedColour(unsigned char *r
, 
1603                                         unsigned char g2
) const 
1605     unsigned long key 
= MakeKey(r2
, g2
, b2
); 
1607     while ( find(key
) != end() ) 
1609         // color already used 
1621                     wxLogError(_("No unused colour in image.") ); 
1627         key 
= MakeKey(r2
, g2
, b2
); 
1641 wxImage::FindFirstUnusedColour(unsigned char *r
, 
1646                                unsigned char g2
) const 
1648     wxImageHistogram histogram
; 
1650     ComputeHistogram(histogram
); 
1652     return histogram
.FindFirstUnusedColour(r
, g
, b
, r2
, g2
, b2
); 
1658 // Counts and returns the number of different colours. Optionally stops 
1659 // when it exceeds 'stopafter' different colours. This is useful, for 
1660 // example, to see if the image can be saved as 8-bit (256 colour or 
1661 // less, in this case it would be invoked as CountColours(256)). Default 
1662 // value for stopafter is -1 (don't care). 
1664 unsigned long wxImage::CountColours( unsigned long stopafter 
) const 
1668     unsigned char r
, g
, b
; 
1670     unsigned long size
, nentries
, key
; 
1673     size 
= GetWidth() * GetHeight(); 
1676     for (unsigned long j 
= 0; (j 
< size
) && (nentries 
<= stopafter
) ; j
++) 
1681         key 
= wxImageHistogram::MakeKey(r
, g
, b
); 
1683         if (h
.Get(key
) == NULL
) 
1694 unsigned long wxImage::ComputeHistogram( wxImageHistogram 
&h 
) const 
1696     unsigned char *p 
= GetData(); 
1697     unsigned long nentries 
= 0; 
1701     const unsigned long size 
= GetWidth() * GetHeight(); 
1703     unsigned char r
, g
, b
; 
1704     for ( unsigned long n 
= 0; n 
< size
; n
++ ) 
1710         wxImageHistogramEntry
& entry 
= h
[wxImageHistogram::MakeKey(r
, g
, b
)]; 
1712         if ( entry
.value
++ == 0 ) 
1713             entry
.index 
= nentries
++; 
1720  * Rotation code by Carlos Moreno 
1723 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which 
1724 //      does exactly the same thing. And I also got rid of wxRotationPixel 
1725 //      bacause of potential problems in architectures where alignment 
1726 //      is an issue, so I had to rewrite parts of the code. 
1728 static const double gs_Epsilon 
= 1e-10; 
1730 static inline int wxCint (double x
) 
1732     return (x 
> 0) ? (int) (x 
+ 0.5) : (int) (x 
- 0.5); 
1736 // Auxiliary function to rotate a point (x,y) with respect to point p0 
1737 // make it inline and use a straight return to facilitate optimization 
1738 // also, the function receives the sine and cosine of the angle to avoid 
1739 // repeating the time-consuming calls to these functions -- sin/cos can 
1740 // be computed and stored in the calling function. 
1742 inline wxRealPoint 
rotated_point (const wxRealPoint 
& p
, double cos_angle
, double sin_angle
, const wxRealPoint 
& p0
) 
1744     return wxRealPoint (p0
.x 
+ (p
.x 
- p0
.x
) * cos_angle 
- (p
.y 
- p0
.y
) * sin_angle
, 
1745                         p0
.y 
+ (p
.y 
- p0
.y
) * cos_angle 
+ (p
.x 
- p0
.x
) * sin_angle
); 
1748 inline wxRealPoint 
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint 
& p0
) 
1750     return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
); 
1753 wxImage 
wxImage::Rotate(double angle
, const wxPoint 
& centre_of_rotation
, bool interpolating
, wxPoint 
* offset_after_rotation
) const 
1756     angle 
= -angle
;     // screen coordinates are a mirror image of "real" coordinates 
1758     bool has_alpha 
= HasAlpha(); 
1760     // Create pointer-based array to accelerate access to wxImage's data 
1761     unsigned char ** data 
= new unsigned char * [GetHeight()]; 
1762     data
[0] = GetData(); 
1763     for (i 
= 1; i 
< GetHeight(); i
++) 
1764         data
[i
] = data
[i 
- 1] + (3 * GetWidth()); 
1766     // Same for alpha channel 
1767     unsigned char ** alpha 
= NULL
; 
1770         alpha 
= new unsigned char * [GetHeight()]; 
1771         alpha
[0] = GetAlpha(); 
1772         for (i 
= 1; i 
< GetHeight(); i
++) 
1773             alpha
[i
] = alpha
[i 
- 1] + GetWidth(); 
1776     // precompute coefficients for rotation formula 
1777     // (sine and cosine of the angle) 
1778     const double cos_angle 
= cos(angle
); 
1779     const double sin_angle 
= sin(angle
); 
1781     // Create new Image to store the result 
1782     // First, find rectangle that covers the rotated image;  to do that, 
1783     // rotate the four corners 
1785     const wxRealPoint 
p0(centre_of_rotation
.x
, centre_of_rotation
.y
); 
1787     wxRealPoint p1 
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
); 
1788     wxRealPoint p2 
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
); 
1789     wxRealPoint p3 
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
); 
1790     wxRealPoint p4 
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
); 
1792     int x1 
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
))); 
1793     int y1 
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
))); 
1794     int x2 
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
))); 
1795     int y2 
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
))); 
1797     // Create rotated image 
1798     wxImage 
rotated (x2 
- x1 
+ 1, y2 
- y1 
+ 1, false); 
1799     // With alpha channel 
1803     if (offset_after_rotation 
!= NULL
) 
1805         *offset_after_rotation 
= wxPoint (x1
, y1
); 
1808     // GRG: The rotated (destination) image is always accessed 
1809     //      sequentially, so there is no need for a pointer-based 
1810     //      array here (and in fact it would be slower). 
1812     unsigned char * dst 
= rotated
.GetData(); 
1814     unsigned char * alpha_dst 
= NULL
; 
1816         alpha_dst 
= rotated
.GetAlpha(); 
1818     // GRG: if the original image has a mask, use its RGB values 
1819     //      as the blank pixel, else, fall back to default (black). 
1821     unsigned char blank_r 
= 0; 
1822     unsigned char blank_g 
= 0; 
1823     unsigned char blank_b 
= 0; 
1827         blank_r 
= GetMaskRed(); 
1828         blank_g 
= GetMaskGreen(); 
1829         blank_b 
= GetMaskBlue(); 
1830         rotated
.SetMaskColour( blank_r
, blank_g
, blank_b 
); 
1833     // Now, for each point of the rotated image, find where it came from, by 
1834     // performing an inverse rotation (a rotation of -angle) and getting the 
1835     // pixel at those coordinates 
1837     // GRG: I've taken the (interpolating) test out of the loops, so that 
1838     //      it is done only once, instead of repeating it for each pixel. 
1843         for (int y 
= 0; y 
< rotated
.GetHeight(); y
++) 
1845             for (x 
= 0; x 
< rotated
.GetWidth(); x
++) 
1847                 wxRealPoint src 
= rotated_point (x 
+ x1
, y 
+ y1
, cos_angle
, -sin_angle
, p0
); 
1849                 if (-0.25 < src
.x 
&& src
.x 
< GetWidth() - 0.75 && 
1850                     -0.25 < src
.y 
&& src
.y 
< GetHeight() - 0.75) 
1852                     // interpolate using the 4 enclosing grid-points.  Those 
1853                     // points can be obtained using floor and ceiling of the 
1854                     // exact coordinates of the point 
1855                         // C.M. 2000-02-17:  when the point is near the border, special care is required. 
1859                     if (0 < src
.x 
&& src
.x 
< GetWidth() - 1) 
1861                         x1 
= wxCint(floor(src
.x
)); 
1862                         x2 
= wxCint(ceil(src
.x
)); 
1864                     else    // else means that x is near one of the borders (0 or width-1) 
1866                         x1 
= x2 
= wxCint (src
.x
); 
1869                     if (0 < src
.y 
&& src
.y 
< GetHeight() - 1) 
1871                         y1 
= wxCint(floor(src
.y
)); 
1872                         y2 
= wxCint(ceil(src
.y
)); 
1876                         y1 
= y2 
= wxCint (src
.y
); 
1879                     // get four points and the distances (square of the distance, 
1880                     // for efficiency reasons) for the interpolation formula 
1882                     // GRG: Do not calculate the points until they are 
1883                     //      really needed -- this way we can calculate 
1884                     //      just one, instead of four, if d1, d2, d3 
1885                     //      or d4 are < gs_Epsilon 
1887                     const double d1 
= (src
.x 
- x1
) * (src
.x 
- x1
) + (src
.y 
- y1
) * (src
.y 
- y1
); 
1888                     const double d2 
= (src
.x 
- x2
) * (src
.x 
- x2
) + (src
.y 
- y1
) * (src
.y 
- y1
); 
1889                     const double d3 
= (src
.x 
- x2
) * (src
.x 
- x2
) + (src
.y 
- y2
) * (src
.y 
- y2
); 
1890                     const double d4 
= (src
.x 
- x1
) * (src
.x 
- x1
) + (src
.y 
- y2
) * (src
.y 
- y2
); 
1892                     // Now interpolate as a weighted average of the four surrounding 
1893                     // points, where the weights are the distances to each of those points 
1895                     // If the point is exactly at one point of the grid of the source 
1896                     // image, then don't interpolate -- just assign the pixel 
1898                     if (d1 
< gs_Epsilon
)        // d1,d2,d3,d4 are positive -- no need for abs() 
1900                         unsigned char *p 
= data
[y1
] + (3 * x1
); 
1907                             unsigned char *p 
= alpha
[y1
] + x1
; 
1908                             *(alpha_dst
++) = *p
; 
1911                     else if (d2 
< gs_Epsilon
) 
1913                         unsigned char *p 
= data
[y1
] + (3 * x2
); 
1920                             unsigned char *p 
= alpha
[y1
] + x2
; 
1921                             *(alpha_dst
++) = *p
; 
1924                     else if (d3 
< gs_Epsilon
) 
1926                         unsigned char *p 
= data
[y2
] + (3 * x2
); 
1933                             unsigned char *p 
= alpha
[y2
] + x2
; 
1934                             *(alpha_dst
++) = *p
; 
1937                     else if (d4 
< gs_Epsilon
) 
1939                         unsigned char *p 
= data
[y2
] + (3 * x1
); 
1946                             unsigned char *p 
= alpha
[y2
] + x1
; 
1947                             *(alpha_dst
++) = *p
; 
1952                         // weights for the weighted average are proportional to the inverse of the distance 
1953                         unsigned char *v1 
= data
[y1
] + (3 * x1
); 
1954                         unsigned char *v2 
= data
[y1
] + (3 * x2
); 
1955                         unsigned char *v3 
= data
[y2
] + (3 * x2
); 
1956                         unsigned char *v4 
= data
[y2
] + (3 * x1
); 
1958                         const double w1 
= 1/d1
, w2 
= 1/d2
, w3 
= 1/d3
, w4 
= 1/d4
; 
1962                         *(dst
++) = (unsigned char) 
1963                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1964                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1965                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1966                         *(dst
++) = (unsigned char) 
1967                             ( (w1 
* *(v1
++) + w2 
* *(v2
++) + 
1968                                w3 
* *(v3
++) + w4 
* *(v4
++)) / 
1969                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1970                         *(dst
++) = (unsigned char) 
1971                             ( (w1 
* *v1 
+ w2 
* *v2 
+ 
1972                                w3 
* *v3 
+ w4 
* *v4
) / 
1973                               (w1 
+ w2 
+ w3 
+ w4
) ); 
1977                             unsigned char *v1 
= alpha
[y1
] + (x1
); 
1978                             unsigned char *v2 
= alpha
[y1
] + (x2
); 
1979                             unsigned char *v3 
= alpha
[y2
] + (x2
); 
1980                             unsigned char *v4 
= alpha
[y2
] + (x1
); 
1982                             *(alpha_dst
++) = (unsigned char) 
1983                                 ( (w1 
* *v1 
+ w2 
* *v2 
+ 
1984                                    w3 
* *v3 
+ w4 
* *v4
) / 
1985                                   (w1 
+ w2 
+ w3 
+ w4
) ); 
2001     else    // not interpolating 
2003         for (int y 
= 0; y 
< rotated
.GetHeight(); y
++) 
2005             for (x 
= 0; x 
< rotated
.GetWidth(); x
++) 
2007                 wxRealPoint src 
= rotated_point (x 
+ x1
, y 
+ y1
, cos_angle
, -sin_angle
, p0
); 
2009                 const int xs 
= wxCint (src
.x
);      // wxCint rounds to the 
2010                 const int ys 
= wxCint (src
.y
);      // closest integer 
2012                 if (0 <= xs 
&& xs 
< GetWidth() && 
2013                     0 <= ys 
&& ys 
< GetHeight()) 
2015                     unsigned char *p 
= data
[ys
] + (3 * xs
); 
2022                         unsigned char *p 
= alpha
[ys
] + (xs
); 
2023                         *(alpha_dst
++) = *p
; 
2033                         *(alpha_dst
++) = 255; 
2051 // A module to allow wxImage initialization/cleanup 
2052 // without calling these functions from app.cpp or from 
2053 // the user's application. 
2055 class wxImageModule
: public wxModule
 
2057 DECLARE_DYNAMIC_CLASS(wxImageModule
) 
2060     bool OnInit() { wxImage::InitStandardHandlers(); return true; }; 
2061     void OnExit() { wxImage::CleanUpHandlers(); }; 
2064 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
) 
2067 #endif // wxUSE_IMAGE