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 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
1131 return wxAtoi(GetOption(name
));
1134 bool wxImage
::HasOption(const wxString
& name
) const
1136 wxCHECK_MSG( Ok(), false, wxT("invalid image") );
1138 return (M_IMGDATA
->m_optionNames
.Index(name
, false) != wxNOT_FOUND
);
1141 bool wxImage
::LoadFile( const wxString
& filename
, long type
, int index
)
1144 if (wxFileExists(filename
))
1146 wxFileInputStream
stream(filename
);
1147 wxBufferedInputStream
bstream( stream
);
1148 return LoadFile(bstream
, type
, index
);
1152 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
1156 #else // !wxUSE_STREAMS
1158 #endif // wxUSE_STREAMS
1161 bool wxImage
::LoadFile( const wxString
& filename
, const wxString
& mimetype
, int index
)
1164 if (wxFileExists(filename
))
1166 wxFileInputStream
stream(filename
);
1167 wxBufferedInputStream
bstream( stream
);
1168 return LoadFile(bstream
, mimetype
, index
);
1172 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
1176 #else // !wxUSE_STREAMS
1178 #endif // wxUSE_STREAMS
1183 bool wxImage
::SaveFile( const wxString
& filename
) const
1185 wxString ext
= filename
.AfterLast('.').Lower();
1187 wxImageHandler
* pHandler
= FindHandler(ext
, -1);
1190 SaveFile(filename
, pHandler
->GetType());
1194 wxLogError(_("Can't save image to file '%s': unknown extension."), filename
.c_str());
1199 bool wxImage
::SaveFile( const wxString
& filename
, int type
) const
1202 ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
);
1204 wxFileOutputStream
stream(filename
);
1206 if ( stream
.IsOk() )
1208 wxBufferedOutputStream
bstream( stream
);
1209 return SaveFile(bstream
, type
);
1211 #endif // wxUSE_STREAMS
1216 bool wxImage
::SaveFile( const wxString
& filename
, const wxString
& mimetype
) const
1219 ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
);
1221 wxFileOutputStream
stream(filename
);
1223 if ( stream
.IsOk() )
1225 wxBufferedOutputStream
bstream( stream
);
1226 return SaveFile(bstream
, mimetype
);
1228 #endif // wxUSE_STREAMS
1233 bool wxImage
::CanRead( const wxString
&name
)
1236 wxFileInputStream
stream(name
);
1237 return CanRead(stream
);
1243 int wxImage
::GetImageCount( const wxString
&name
, long type
)
1246 wxFileInputStream
stream(name
);
1248 return GetImageCount(stream
, type
);
1256 bool wxImage
::CanRead( wxInputStream
&stream
)
1258 const wxList
& list
= GetHandlers();
1260 for ( wxList
::compatibility_iterator node
= list
.GetFirst(); node
; node
= node
->GetNext() )
1262 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
1263 if (handler
->CanRead( stream
))
1270 int wxImage
::GetImageCount( wxInputStream
&stream
, long type
)
1272 wxImageHandler
*handler
;
1274 if ( type
== wxBITMAP_TYPE_ANY
)
1276 wxList
&list
=GetHandlers();
1278 for (wxList
::compatibility_iterator node
= list
.GetFirst(); node
; node
= node
->GetNext())
1280 handler
=(wxImageHandler
*)node
->GetData();
1281 if ( handler
->CanRead(stream
) )
1282 return handler
->GetImageCount(stream
);
1286 wxLogWarning(_("No handler found for image type."));
1290 handler
= FindHandler(type
);
1294 wxLogWarning(_("No image handler for type %d defined."), type
);
1298 if ( handler
->CanRead(stream
) )
1300 return handler
->GetImageCount(stream
);
1304 wxLogError(_("Image file is not of type %d."), type
);
1309 bool wxImage
::LoadFile( wxInputStream
& stream
, long type
, int index
)
1313 m_refData
= new wxImageRefData
;
1315 wxImageHandler
*handler
;
1317 if ( type
== wxBITMAP_TYPE_ANY
)
1319 wxList
&list
=GetHandlers();
1321 for ( wxList
::compatibility_iterator node
= list
.GetFirst(); node
; node
= node
->GetNext() )
1323 handler
=(wxImageHandler
*)node
->GetData();
1324 if ( handler
->CanRead(stream
) )
1325 return handler
->LoadFile(this, stream
, true/*verbose*/, index
);
1329 wxLogWarning( _("No handler found for image type.") );
1333 handler
= FindHandler(type
);
1337 wxLogWarning( _("No image handler for type %d defined."), type
);
1342 return handler
->LoadFile(this, stream
, true/*verbose*/, index
);
1345 bool wxImage
::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
, int index
)
1349 m_refData
= new wxImageRefData
;
1351 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
1355 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
1360 return handler
->LoadFile( this, stream
, true/*verbose*/, index
);
1363 bool wxImage
::SaveFile( wxOutputStream
& stream
, int type
) const
1365 wxCHECK_MSG( Ok(), false, wxT("invalid image") );
1367 wxImageHandler
*handler
= FindHandler(type
);
1371 wxLogWarning( _("No image handler for type %d defined."), type
);
1376 return handler
->SaveFile( (wxImage
*)this, stream
);
1379 bool wxImage
::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
) const
1381 wxCHECK_MSG( Ok(), false, wxT("invalid image") );
1383 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
1387 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
1392 return handler
->SaveFile( (wxImage
*)this, stream
);
1394 #endif // wxUSE_STREAMS
1396 void wxImage
::AddHandler( wxImageHandler
*handler
)
1398 // Check for an existing handler of the type being added.
1399 if (FindHandler( handler
->GetType() ) == 0)
1401 sm_handlers
.Append( handler
);
1405 // This is not documented behaviour, merely the simplest 'fix'
1406 // for preventing duplicate additions. If someone ever has
1407 // a good reason to add and remove duplicate handlers (and they
1408 // may) we should probably refcount the duplicates.
1409 // also an issue in InsertHandler below.
1411 wxLogDebug( _T("Adding duplicate image handler for '%s'"),
1412 handler
->GetName().c_str() );
1417 void wxImage
::InsertHandler( wxImageHandler
*handler
)
1419 // Check for an existing handler of the type being added.
1420 if (FindHandler( handler
->GetType() ) == 0)
1422 sm_handlers
.Insert( handler
);
1426 // see AddHandler for additional comments.
1427 wxLogDebug( _T("Inserting duplicate image handler for '%s'"),
1428 handler
->GetName().c_str() );
1433 bool wxImage
::RemoveHandler( const wxString
& name
)
1435 wxImageHandler
*handler
= FindHandler(name
);
1438 sm_handlers
.DeleteObject(handler
);
1446 wxImageHandler
*wxImage
::FindHandler( const wxString
& name
)
1448 wxList
::compatibility_iterator node
= sm_handlers
.GetFirst();
1451 wxImageHandler
*handler
= (wxImageHandler
*)node
->GetData();
1452 if (handler
->GetName().Cmp(name
) == 0) return handler
;
1454 node
= node
->GetNext();
1459 wxImageHandler
*wxImage
::FindHandler( const wxString
& extension
, long bitmapType
)
1461 wxList
::compatibility_iterator node
= sm_handlers
.GetFirst();
1464 wxImageHandler
*handler
= (wxImageHandler
*)node
->GetData();
1465 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
1466 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
1468 node
= node
->GetNext();
1473 wxImageHandler
*wxImage
::FindHandler( long bitmapType
)
1475 wxList
::compatibility_iterator node
= sm_handlers
.GetFirst();
1478 wxImageHandler
*handler
= (wxImageHandler
*)node
->GetData();
1479 if (handler
->GetType() == bitmapType
) return handler
;
1480 node
= node
->GetNext();
1485 wxImageHandler
*wxImage
::FindHandlerMime( const wxString
& mimetype
)
1487 wxList
::compatibility_iterator node
= sm_handlers
.GetFirst();
1490 wxImageHandler
*handler
= (wxImageHandler
*)node
->GetData();
1491 if (handler
->GetMimeType().IsSameAs(mimetype
, false)) return handler
;
1492 node
= node
->GetNext();
1497 void wxImage
::InitStandardHandlers()
1500 AddHandler(new wxBMPHandler
);
1501 #endif // wxUSE_STREAMS
1504 void wxImage
::CleanUpHandlers()
1506 wxList
::compatibility_iterator node
= sm_handlers
.GetFirst();
1509 wxImageHandler
*handler
= (wxImageHandler
*)node
->GetData();
1510 wxList
::compatibility_iterator next
= node
->GetNext();
1515 sm_handlers
.Clear();
1518 wxString wxImage
::GetImageExtWildcard()
1522 wxList
& Handlers
= wxImage
::GetHandlers();
1523 wxList
::compatibility_iterator Node
= Handlers
.GetFirst();
1526 wxImageHandler
* Handler
= (wxImageHandler
*)Node
->GetData();
1527 fmts
+= wxT("*.") + Handler
->GetExtension();
1528 Node
= Node
->GetNext();
1529 if ( Node
) fmts
+= wxT(";");
1532 return wxT("(") + fmts
+ wxT(")|") + fmts
;
1535 //-----------------------------------------------------------------------------
1537 //-----------------------------------------------------------------------------
1539 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
1542 bool wxImageHandler
::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
1547 bool wxImageHandler
::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
1552 int wxImageHandler
::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
1557 bool wxImageHandler
::CanRead( const wxString
& name
)
1559 if (wxFileExists(name
))
1561 wxFileInputStream
stream(name
);
1562 return CanRead(stream
);
1565 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
1570 bool wxImageHandler
::CallDoCanRead(wxInputStream
& stream
)
1572 wxFileOffset posOld
= stream
.TellI();
1573 if ( posOld
== wxInvalidOffset
)
1575 // can't test unseekable stream
1579 bool ok
= DoCanRead(stream
);
1581 // restore the old position to be able to test other formats and so on
1582 if ( stream
.SeekI(posOld
) == wxInvalidOffset
)
1584 wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!"));
1586 // reading would fail anyhow as we're not at the right position
1593 #endif // wxUSE_STREAMS
1595 // ----------------------------------------------------------------------------
1596 // image histogram stuff
1597 // ----------------------------------------------------------------------------
1600 wxImageHistogram
::FindFirstUnusedColour(unsigned char *r
,
1605 unsigned char g2
) const
1607 unsigned long key
= MakeKey(r2
, g2
, b2
);
1609 while ( find(key
) != end() )
1611 // color already used
1623 wxLogError(_("No unused colour in image.") );
1629 key
= MakeKey(r2
, g2
, b2
);
1643 wxImage
::FindFirstUnusedColour(unsigned char *r
,
1648 unsigned char g2
) const
1650 wxImageHistogram histogram
;
1652 ComputeHistogram(histogram
);
1654 return histogram
.FindFirstUnusedColour(r
, g
, b
, r2
, g2
, b2
);
1660 // Counts and returns the number of different colours. Optionally stops
1661 // when it exceeds 'stopafter' different colours. This is useful, for
1662 // example, to see if the image can be saved as 8-bit (256 colour or
1663 // less, in this case it would be invoked as CountColours(256)). Default
1664 // value for stopafter is -1 (don't care).
1666 unsigned long wxImage
::CountColours( unsigned long stopafter
) const
1670 unsigned char r
, g
, b
;
1672 unsigned long size
, nentries
, key
;
1675 size
= GetWidth() * GetHeight();
1678 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
1683 key
= wxImageHistogram
::MakeKey(r
, g
, b
);
1685 if (h
.Get(key
) == NULL
)
1696 unsigned long wxImage
::ComputeHistogram( wxImageHistogram
&h
) const
1698 unsigned char *p
= GetData();
1699 unsigned long nentries
= 0;
1703 const unsigned long size
= GetWidth() * GetHeight();
1705 unsigned char r
, g
, b
;
1706 for ( unsigned long n
= 0; n
< size
; n
++ )
1712 wxImageHistogramEntry
& entry
= h
[wxImageHistogram
::MakeKey(r
, g
, b
)];
1714 if ( entry
.value
++ == 0 )
1715 entry
.index
= nentries
++;
1722 * Rotation code by Carlos Moreno
1725 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
1726 // does exactly the same thing. And I also got rid of wxRotationPixel
1727 // bacause of potential problems in architectures where alignment
1728 // is an issue, so I had to rewrite parts of the code.
1730 static const double gs_Epsilon
= 1e-10;
1732 static inline int wxCint (double x
)
1734 return (x
> 0) ?
(int) (x
+ 0.5) : (int) (x
- 0.5);
1738 // Auxiliary function to rotate a point (x,y) with respect to point p0
1739 // make it inline and use a straight return to facilitate optimization
1740 // also, the function receives the sine and cosine of the angle to avoid
1741 // repeating the time-consuming calls to these functions -- sin/cos can
1742 // be computed and stored in the calling function.
1744 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
1746 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
1747 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
1750 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
1752 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
1755 wxImage wxImage
::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
1758 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
1760 bool has_alpha
= HasAlpha();
1762 // Create pointer-based array to accelerate access to wxImage's data
1763 unsigned char ** data
= new unsigned char * [GetHeight()];
1764 data
[0] = GetData();
1765 for (i
= 1; i
< GetHeight(); i
++)
1766 data
[i
] = data
[i
- 1] + (3 * GetWidth());
1768 // Same for alpha channel
1769 unsigned char ** alpha
= NULL
;
1772 alpha
= new unsigned char * [GetHeight()];
1773 alpha
[0] = GetAlpha();
1774 for (i
= 1; i
< GetHeight(); i
++)
1775 alpha
[i
] = alpha
[i
- 1] + GetWidth();
1778 // precompute coefficients for rotation formula
1779 // (sine and cosine of the angle)
1780 const double cos_angle
= cos(angle
);
1781 const double sin_angle
= sin(angle
);
1783 // Create new Image to store the result
1784 // First, find rectangle that covers the rotated image; to do that,
1785 // rotate the four corners
1787 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
1789 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
1790 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
1791 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
1792 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
1794 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
1795 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
1796 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
1797 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
1799 // Create rotated image
1800 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1, false);
1801 // With alpha channel
1805 if (offset_after_rotation
!= NULL
)
1807 *offset_after_rotation
= wxPoint (x1
, y1
);
1810 // GRG: The rotated (destination) image is always accessed
1811 // sequentially, so there is no need for a pointer-based
1812 // array here (and in fact it would be slower).
1814 unsigned char * dst
= rotated
.GetData();
1816 unsigned char * alpha_dst
= NULL
;
1818 alpha_dst
= rotated
.GetAlpha();
1820 // GRG: if the original image has a mask, use its RGB values
1821 // as the blank pixel, else, fall back to default (black).
1823 unsigned char blank_r
= 0;
1824 unsigned char blank_g
= 0;
1825 unsigned char blank_b
= 0;
1829 blank_r
= GetMaskRed();
1830 blank_g
= GetMaskGreen();
1831 blank_b
= GetMaskBlue();
1832 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
1835 // Now, for each point of the rotated image, find where it came from, by
1836 // performing an inverse rotation (a rotation of -angle) and getting the
1837 // pixel at those coordinates
1839 // GRG: I've taken the (interpolating) test out of the loops, so that
1840 // it is done only once, instead of repeating it for each pixel.
1845 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
1847 for (x
= 0; x
< rotated
.GetWidth(); x
++)
1849 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
1851 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
1852 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
1854 // interpolate using the 4 enclosing grid-points. Those
1855 // points can be obtained using floor and ceiling of the
1856 // exact coordinates of the point
1857 // C.M. 2000-02-17: when the point is near the border, special care is required.
1861 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
1863 x1
= wxCint(floor(src
.x
));
1864 x2
= wxCint(ceil(src
.x
));
1866 else // else means that x is near one of the borders (0 or width-1)
1868 x1
= x2
= wxCint (src
.x
);
1871 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
1873 y1
= wxCint(floor(src
.y
));
1874 y2
= wxCint(ceil(src
.y
));
1878 y1
= y2
= wxCint (src
.y
);
1881 // get four points and the distances (square of the distance,
1882 // for efficiency reasons) for the interpolation formula
1884 // GRG: Do not calculate the points until they are
1885 // really needed -- this way we can calculate
1886 // just one, instead of four, if d1, d2, d3
1887 // or d4 are < gs_Epsilon
1889 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
1890 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
1891 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
1892 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
1894 // Now interpolate as a weighted average of the four surrounding
1895 // points, where the weights are the distances to each of those points
1897 // If the point is exactly at one point of the grid of the source
1898 // image, then don't interpolate -- just assign the pixel
1900 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
1902 unsigned char *p
= data
[y1
] + (3 * x1
);
1909 unsigned char *p
= alpha
[y1
] + x1
;
1910 *(alpha_dst
++) = *p
;
1913 else if (d2
< gs_Epsilon
)
1915 unsigned char *p
= data
[y1
] + (3 * x2
);
1922 unsigned char *p
= alpha
[y1
] + x2
;
1923 *(alpha_dst
++) = *p
;
1926 else if (d3
< gs_Epsilon
)
1928 unsigned char *p
= data
[y2
] + (3 * x2
);
1935 unsigned char *p
= alpha
[y2
] + x2
;
1936 *(alpha_dst
++) = *p
;
1939 else if (d4
< gs_Epsilon
)
1941 unsigned char *p
= data
[y2
] + (3 * x1
);
1948 unsigned char *p
= alpha
[y2
] + x1
;
1949 *(alpha_dst
++) = *p
;
1954 // weights for the weighted average are proportional to the inverse of the distance
1955 unsigned char *v1
= data
[y1
] + (3 * x1
);
1956 unsigned char *v2
= data
[y1
] + (3 * x2
);
1957 unsigned char *v3
= data
[y2
] + (3 * x2
);
1958 unsigned char *v4
= data
[y2
] + (3 * x1
);
1960 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
1964 *(dst
++) = (unsigned char)
1965 ( (w1
* *(v1
++) + w2
* *(v2
++) +
1966 w3
* *(v3
++) + w4
* *(v4
++)) /
1967 (w1
+ w2
+ w3
+ w4
) );
1968 *(dst
++) = (unsigned char)
1969 ( (w1
* *(v1
++) + w2
* *(v2
++) +
1970 w3
* *(v3
++) + w4
* *(v4
++)) /
1971 (w1
+ w2
+ w3
+ w4
) );
1972 *(dst
++) = (unsigned char)
1973 ( (w1
* *v1
+ w2
* *v2
+
1974 w3
* *v3
+ w4
* *v4
) /
1975 (w1
+ w2
+ w3
+ w4
) );
1979 unsigned char *v1
= alpha
[y1
] + (x1
);
1980 unsigned char *v2
= alpha
[y1
] + (x2
);
1981 unsigned char *v3
= alpha
[y2
] + (x2
);
1982 unsigned char *v4
= alpha
[y2
] + (x1
);
1984 *(alpha_dst
++) = (unsigned char)
1985 ( (w1
* *v1
+ w2
* *v2
+
1986 w3
* *v3
+ w4
* *v4
) /
1987 (w1
+ w2
+ w3
+ w4
) );
2003 else // not interpolating
2005 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
2007 for (x
= 0; x
< rotated
.GetWidth(); x
++)
2009 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
2011 const int xs
= wxCint (src
.x
); // wxCint rounds to the
2012 const int ys
= wxCint (src
.y
); // closest integer
2014 if (0 <= xs
&& xs
< GetWidth() &&
2015 0 <= ys
&& ys
< GetHeight())
2017 unsigned char *p
= data
[ys
] + (3 * xs
);
2024 unsigned char *p
= alpha
[ys
] + (xs
);
2025 *(alpha_dst
++) = *p
;
2035 *(alpha_dst
++) = 255;
2053 // A module to allow wxImage initialization/cleanup
2054 // without calling these functions from app.cpp or from
2055 // the user's application.
2057 class wxImageModule
: public wxModule
2059 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2062 bool OnInit() { wxImage
::InitStandardHandlers(); return true; };
2063 void OnExit() { wxImage
::CleanUpHandlers(); };
2066 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2069 #endif // wxUSE_IMAGE