1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "image.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
26 #include "wx/bitmap.h"
30 #include "wx/filefn.h"
31 #include "wx/wfstream.h"
33 #include "wx/module.h"
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 class wxImageRefData
: public wxObjectRefData
56 unsigned char *m_data
;
58 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
63 #endif // wxUSE_PALETTE
64 wxArrayString m_optionNames
;
65 wxArrayString m_optionValues
;
68 wxImageRefData::wxImageRefData()
72 m_data
= (unsigned char*) NULL
;
81 wxImageRefData::~wxImageRefData()
83 if (m_data
&& !m_static
)
87 wxList
wxImage::sm_handlers
;
91 //-----------------------------------------------------------------------------
93 #define M_IMGDATA ((wxImageRefData *)m_refData)
95 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
101 wxImage::wxImage( int width
, int height
)
103 Create( width
, height
);
106 wxImage::wxImage( int width
, int height
, unsigned char* data
, bool static_data
)
108 Create( width
, height
, data
, static_data
);
111 wxImage::wxImage( const wxString
& name
, long type
, int index
)
113 LoadFile( name
, type
, index
);
116 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
, int index
)
118 LoadFile( name
, mimetype
, index
);
122 wxImage::wxImage( wxInputStream
& stream
, long type
, int index
)
124 LoadFile( stream
, type
, index
);
127 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
, int index
)
129 LoadFile( stream
, mimetype
, index
);
131 #endif // wxUSE_STREAMS
133 wxImage::wxImage( const wxImage
& image
)
138 wxImage::wxImage( const wxImage
* image
)
140 if (image
) Ref(*image
);
143 void wxImage::Create( int width
, int height
)
147 m_refData
= new wxImageRefData();
149 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
150 if (M_IMGDATA
->m_data
)
152 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
154 M_IMGDATA
->m_width
= width
;
155 M_IMGDATA
->m_height
= height
;
156 M_IMGDATA
->m_ok
= TRUE
;
164 void wxImage::Create( int width
, int height
, unsigned char* data
, bool static_data
)
168 m_refData
= new wxImageRefData();
170 M_IMGDATA
->m_data
= data
;
171 if (M_IMGDATA
->m_data
)
173 M_IMGDATA
->m_width
= width
;
174 M_IMGDATA
->m_height
= height
;
175 M_IMGDATA
->m_ok
= TRUE
;
176 M_IMGDATA
->m_static
= static_data
;
184 void wxImage::Destroy()
189 wxImage
wxImage::Copy() const
193 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
195 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
197 char unsigned *data
= image
.GetData();
199 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
201 if (M_IMGDATA
->m_hasMask
)
202 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
204 memcpy( data
, GetData(), M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3 );
209 wxImage
wxImage::Scale( int width
, int height
) const
213 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
215 // can't scale to/from 0 size
216 wxCHECK_MSG( (width
> 0) && (height
> 0), image
,
217 wxT("invalid new image size") );
219 long old_height
= M_IMGDATA
->m_height
,
220 old_width
= M_IMGDATA
->m_width
;
221 wxCHECK_MSG( (old_height
> 0) && (old_width
> 0), image
,
222 wxT("invalid old image size") );
224 image
.Create( width
, height
);
226 char unsigned *data
= image
.GetData();
228 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
230 if (M_IMGDATA
->m_hasMask
)
232 image
.SetMaskColour( M_IMGDATA
->m_maskRed
,
233 M_IMGDATA
->m_maskGreen
,
234 M_IMGDATA
->m_maskBlue
);
237 char unsigned *source_data
= M_IMGDATA
->m_data
;
238 char unsigned *target_data
= data
;
241 // This is nonsense, RR.
243 // We do (x, y) -> (x, y)*oldSize/newSize but the valid values of x and y
244 // are from 0 to size-1, hence all decrement the sizes
245 long old_old_width
= old_width
;
250 for ( long j
= 0; j
<= height
; j
++ )
252 // don't crash for images with height == 1
253 long y_offset
= height
? (j
* old_height
/ height
)* old_old_width
: 0;
255 for ( long i
= 0; i
<= width
; i
++ )
257 long x_offset
= width
? (i
* old_width
) / width
: 0;
259 memcpy( target_data
, source_data
+ 3*(y_offset
+ x_offset
), 3 );
264 for (long j
= 0; j
< height
; j
++)
266 long y_offset
= (j
* old_height
/ height
) * old_width
;
268 for (long i
= 0; i
< width
; i
++)
271 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
278 // In case this is a cursor, make sure the hotspot is scalled accordingly:
279 if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
) )
280 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
,
281 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
)*width
)/old_width
);
282 if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
) )
283 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
,
284 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)*height
)/old_height
);
289 wxImage
wxImage::Rotate90( bool clockwise
) const
293 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
295 image
.Create( M_IMGDATA
->m_height
, M_IMGDATA
->m_width
);
297 char unsigned *data
= image
.GetData();
299 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
301 if (M_IMGDATA
->m_hasMask
)
302 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
304 long height
= M_IMGDATA
->m_height
;
305 long width
= M_IMGDATA
->m_width
;
307 char unsigned *source_data
= M_IMGDATA
->m_data
;
308 char unsigned *target_data
;
310 for (long j
= 0; j
< height
; j
++)
312 for (long i
= 0; i
< width
; i
++)
315 target_data
= data
+ (((i
+1)*height
) - j
- 1)*3;
317 target_data
= data
+ ((height
*(width
-1)) + j
- (i
*height
))*3;
318 memcpy( target_data
, source_data
, 3 );
326 wxImage
wxImage::Mirror( bool horizontally
) const
330 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
332 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
334 char unsigned *data
= image
.GetData();
336 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
338 if (M_IMGDATA
->m_hasMask
)
339 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
341 long height
= M_IMGDATA
->m_height
;
342 long width
= M_IMGDATA
->m_width
;
344 char unsigned *source_data
= M_IMGDATA
->m_data
;
345 char unsigned *target_data
;
349 for (long j
= 0; j
< height
; j
++)
352 target_data
= data
-3;
353 for (long i
= 0; i
< width
; i
++)
355 memcpy( target_data
, source_data
, 3 );
363 for (long i
= 0; i
< height
; i
++)
365 target_data
= data
+ 3*width
*(height
-1-i
);
366 memcpy( target_data
, source_data
, (size_t)3*width
);
367 source_data
+= 3*width
;
374 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
378 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
380 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()),
381 image
, wxT("invalid subimage size") );
383 int subwidth
=rect
.GetWidth();
384 const int subheight
=rect
.GetHeight();
386 image
.Create( subwidth
, subheight
);
388 char unsigned *subdata
= image
.GetData(), *data
=GetData();
390 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
392 if (M_IMGDATA
->m_hasMask
)
393 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
395 const int subleft
=3*rect
.GetLeft();
396 const int width
=3*GetWidth();
399 data
+=rect
.GetTop()*width
+subleft
;
401 for (long j
= 0; j
< subheight
; ++j
)
403 memcpy( subdata
, data
, subwidth
);
411 void wxImage::Paste( const wxImage
&image
, int x
, int y
)
413 wxCHECK_RET( Ok(), wxT("invalid image") );
414 wxCHECK_RET( image
.Ok(), wxT("invalid image") );
418 int width
= image
.GetWidth();
419 int height
= image
.GetHeight();
432 if ((x
+xx
)+width
> M_IMGDATA
->m_width
)
433 width
= M_IMGDATA
->m_width
- (x
+xx
);
434 if ((y
+yy
)+height
> M_IMGDATA
->m_height
)
435 height
= M_IMGDATA
->m_height
- (y
+yy
);
437 if (width
< 1) return;
438 if (height
< 1) return;
440 if ((!HasMask() && !image
.HasMask()) ||
441 ((HasMask() && image
.HasMask() &&
442 (GetMaskRed()==image
.GetMaskRed()) &&
443 (GetMaskGreen()==image
.GetMaskGreen()) &&
444 (GetMaskBlue()==image
.GetMaskBlue()))))
447 unsigned char* source_data
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth();
448 int source_step
= image
.GetWidth()*3;
450 unsigned char* target_data
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
;
451 int target_step
= M_IMGDATA
->m_width
*3;
452 for (int j
= 0; j
< height
; j
++)
454 memcpy( target_data
, source_data
, width
);
455 source_data
+= source_step
;
456 target_data
+= target_step
;
461 if (!HasMask() && image
.HasMask())
463 unsigned char r
= image
.GetMaskRed();
464 unsigned char g
= image
.GetMaskGreen();
465 unsigned char b
= image
.GetMaskBlue();
468 unsigned char* source_data
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth();
469 int source_step
= image
.GetWidth()*3;
471 unsigned char* target_data
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
;
472 int target_step
= M_IMGDATA
->m_width
*3;
474 for (int j
= 0; j
< height
; j
++)
476 for (int i
= 0; i
< width
; i
+=3)
478 if ((source_data
[i
] != r
) &&
479 (source_data
[i
+1] != g
) &&
480 (source_data
[i
+2] != b
))
482 memcpy( target_data
+i
, source_data
+i
, 3 );
485 source_data
+= source_step
;
486 target_data
+= target_step
;
491 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
492 unsigned char r2
, unsigned char g2
, unsigned char b2
)
494 wxCHECK_RET( Ok(), wxT("invalid image") );
496 char unsigned *data
= GetData();
498 const int w
= GetWidth();
499 const int h
= GetHeight();
501 for (int j
= 0; j
< h
; j
++)
502 for (int i
= 0; i
< w
; i
++)
504 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
514 wxImage
wxImage::ConvertToMono( unsigned char r
, unsigned char g
, unsigned char b
) const
518 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
520 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
522 char unsigned *data
= image
.GetData();
524 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
526 if (M_IMGDATA
->m_hasMask
)
528 if (M_IMGDATA
->m_maskRed
== r
&& M_IMGDATA
->m_maskGreen
== g
&&
529 M_IMGDATA
->m_maskBlue
== b
)
530 image
.SetMaskColour( 255, 255, 255 );
532 image
.SetMaskColour( 0, 0, 0 );
535 long size
= M_IMGDATA
->m_height
* M_IMGDATA
->m_width
;
537 char unsigned *srcd
= M_IMGDATA
->m_data
;
538 char unsigned *tard
= image
.GetData();
540 for ( long i
= 0; i
< size
; i
++, srcd
+= 3, tard
+= 3 )
542 if (srcd
[0] == r
&& srcd
[1] == g
&& srcd
[2] == b
)
543 tard
[0] = tard
[1] = tard
[2] = 255;
545 tard
[0] = tard
[1] = tard
[2] = 0;
551 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
553 wxCHECK_RET( Ok(), wxT("invalid image") );
555 int w
= M_IMGDATA
->m_width
;
556 int h
= M_IMGDATA
->m_height
;
558 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
560 long pos
= (y
* w
+ x
) * 3;
562 M_IMGDATA
->m_data
[ pos
] = r
;
563 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
564 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
567 unsigned char wxImage::GetRed( int x
, int y
) const
569 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
571 int w
= M_IMGDATA
->m_width
;
572 int h
= M_IMGDATA
->m_height
;
574 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
576 long pos
= (y
* w
+ x
) * 3;
578 return M_IMGDATA
->m_data
[pos
];
581 unsigned char wxImage::GetGreen( int x
, int y
) const
583 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
585 int w
= M_IMGDATA
->m_width
;
586 int h
= M_IMGDATA
->m_height
;
588 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
590 long pos
= (y
* w
+ x
) * 3;
592 return M_IMGDATA
->m_data
[pos
+1];
595 unsigned char wxImage::GetBlue( int x
, int y
) const
597 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
599 int w
= M_IMGDATA
->m_width
;
600 int h
= M_IMGDATA
->m_height
;
602 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
604 long pos
= (y
* w
+ x
) * 3;
606 return M_IMGDATA
->m_data
[pos
+2];
609 bool wxImage::Ok() const
611 // image of 0 width or height can't be considered ok - at least because it
612 // causes crashes in ConvertToBitmap() if we don't catch it in time
613 wxImageRefData
*data
= M_IMGDATA
;
614 return data
&& data
->m_ok
&& data
->m_width
&& data
->m_height
;
617 char unsigned *wxImage::GetData() const
619 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
621 return M_IMGDATA
->m_data
;
624 void wxImage::SetData( char unsigned *data
)
626 wxCHECK_RET( Ok(), wxT("invalid image") );
628 wxImageRefData
*newRefData
= new wxImageRefData();
630 newRefData
->m_width
= M_IMGDATA
->m_width
;
631 newRefData
->m_height
= M_IMGDATA
->m_height
;
632 newRefData
->m_data
= data
;
633 newRefData
->m_ok
= TRUE
;
634 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
635 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
636 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
637 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
641 m_refData
= newRefData
;
644 void wxImage::SetData( char unsigned *data
, int new_width
, int new_height
)
646 wxImageRefData
*newRefData
= new wxImageRefData();
650 newRefData
->m_width
= new_width
;
651 newRefData
->m_height
= new_height
;
652 newRefData
->m_data
= data
;
653 newRefData
->m_ok
= TRUE
;
654 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
655 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
656 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
657 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
661 newRefData
->m_width
= new_width
;
662 newRefData
->m_height
= new_height
;
663 newRefData
->m_data
= data
;
664 newRefData
->m_ok
= TRUE
;
669 m_refData
= newRefData
;
672 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
674 wxCHECK_RET( Ok(), wxT("invalid image") );
676 M_IMGDATA
->m_maskRed
= r
;
677 M_IMGDATA
->m_maskGreen
= g
;
678 M_IMGDATA
->m_maskBlue
= b
;
679 M_IMGDATA
->m_hasMask
= TRUE
;
682 unsigned char wxImage::GetMaskRed() const
684 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
686 return M_IMGDATA
->m_maskRed
;
689 unsigned char wxImage::GetMaskGreen() const
691 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
693 return M_IMGDATA
->m_maskGreen
;
696 unsigned char wxImage::GetMaskBlue() const
698 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
700 return M_IMGDATA
->m_maskBlue
;
703 void wxImage::SetMask( bool mask
)
705 wxCHECK_RET( Ok(), wxT("invalid image") );
707 M_IMGDATA
->m_hasMask
= mask
;
710 bool wxImage::HasMask() const
712 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
714 return M_IMGDATA
->m_hasMask
;
717 int wxImage::GetWidth() const
719 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
721 return M_IMGDATA
->m_width
;
724 int wxImage::GetHeight() const
726 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
728 return M_IMGDATA
->m_height
;
732 bool wxImage::FindFirstUnusedColour(
733 unsigned char *r
, unsigned char *g
, unsigned char *b
,
734 unsigned char startR
, unsigned char startG
, unsigned char startB
) const
736 wxImageHistogram histogram
;
739 ComputeHistogram(histogram
);
741 unsigned char r2
= startR
;
742 unsigned char g2
= startG
;
743 unsigned char b2
= startB
;
745 key
= (r2
<< 16) | (g2
<< 8) | b2
;
747 while ( histogram
.find(key
) != histogram
.end() )
749 // color already used
761 wxLogError( _("GetUnusedColour:: No Unused Color in image ") );
767 key
= (r2
<< 16) | (g2
<< 8) | b2
;
778 bool wxImage::SetMaskFromImage(const wxImage
& mask
,
779 unsigned char mr
, unsigned char mg
, unsigned char mb
)
781 // check that the images are the same size
782 if ( (M_IMGDATA
->m_height
!= mask
.GetHeight() ) || (M_IMGDATA
->m_width
!= mask
.GetWidth () ) )
784 wxLogError( _("Image and Mask have different sizes") );
788 // find unused colour
789 unsigned char r
,g
,b
;
790 if (!FindFirstUnusedColour(&r
, &g
, &b
))
792 wxLogError( _("No Unused Color in image being masked") );
796 char unsigned *imgdata
= GetData();
797 char unsigned *maskdata
= mask
.GetData();
799 const int w
= GetWidth();
800 const int h
= GetHeight();
802 for (int j
= 0; j
< h
; j
++)
804 for (int i
= 0; i
< w
; i
++)
806 if ((maskdata
[0] == mr
) && (maskdata
[1] == mg
) && (maskdata
[2] == mb
))
817 SetMaskColour(r
, g
, b
);
825 // Fills with the colour extracted from fillBrush, starting at x,y until either
826 // a color different from the start pixel is reached (wxFLOOD_SURFACE)
827 // or fill color is reached (wxFLOOD_BORDER)
829 bool wxImage::MatchPixel(int x
, int y
, int w
, int h
, const wxColour
& c
)
831 if ((x
<0)||(x
>=w
)||(y
<0)||(y
>=h
)) return false;
833 unsigned char r
= GetRed(x
,y
);
834 unsigned char g
= GetGreen(x
,y
);
835 unsigned char b
= GetBlue(x
,y
);
836 return c
.Red() == r
&& c
.Green() == g
&& c
.Blue() == b
;
839 bool wxImage::MatchBoundaryPixel(int x
, int y
, int w
, int h
, const wxColour
& fill
, const wxColour
& bound
)
841 if ((x
<0)||(x
>=w
)||(y
<0)||(y
>=h
)) return TRUE
;
843 unsigned char r
= GetRed(x
,y
);
844 unsigned char g
= GetGreen(x
,y
);
845 unsigned char b
= GetBlue(x
,y
);
846 if ( fill
.Red() == r
&& fill
.Green() == g
&& fill
.Blue() == b
) return TRUE
;
847 if ( bound
.Red() == r
&& bound
.Green() == g
&& bound
.Blue() == b
) return TRUE
;
852 void wxImage::DoFloodFill (wxCoord x
, wxCoord y
, const wxBrush
& fillBrush
,
853 const wxColour
& testColour
, int style
/*=wxFLOOD_SURFACE */,
854 int LogicalFunction
/*= wxCOPY, currently unused */)
856 /* A diamond flood-fill using a circular queue system.
857 Each pixel surrounding the current pixel is added to
858 the queue if it meets the criteria, then is retrieved in
859 its turn. Code originally based on http://www.drawit.co.nz/Developers.htm */
861 int width
= GetWidth();
862 int height
= GetHeight();
864 //Draw using a pen made from the current brush colour
865 //Potentially allows us to use patterned flood fills in future code
866 wxColour fillColour
= fillBrush
.GetColour();
867 unsigned char r
= fillColour
.Red();
868 unsigned char g
= fillColour
.Green();
869 unsigned char b
= fillColour
.Blue();
872 if (style
== wxFLOOD_SURFACE
)
874 //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything
875 if ( GetRed(x
,y
) != r
876 || GetGreen(x
,y
) != g
877 || GetBlue (x
,y
) != b
)
879 //prepare memory for queue
880 //queue save, start, read
881 size_t *qs
, *qst
, *qr
;
883 //queue size (physical)
884 long qSz
= height
* width
* 2;
885 qst
= new size_t [qSz
];
887 //temporary x and y locations
890 for (int i
=0; i
< qSz
; i
++)
905 //Add new members to queue
906 //Above current pixel
907 if(MatchPixel(xt
,yt
-1,width
,height
,testColour
))
913 SetRGB(xt
,yt
-1,r
,g
,b
);
915 //Loop back to beginning of queue
916 if(qs
>=(qst
+qSz
)) qs
=qst
;
919 //Below current pixel
920 if(MatchPixel(xt
,yt
+1,width
,height
,testColour
))
926 SetRGB(xt
,yt
+1,r
,g
,b
);
927 if(qs
>=(qst
+qSz
)) qs
=qst
;
930 //Left of current pixel
931 if(MatchPixel(xt
-1,yt
,width
,height
,testColour
))
937 SetRGB(xt
-1,yt
,r
,g
,b
);
938 if(qs
>=(qst
+qSz
)) qs
=qst
;
941 //Right of current pixel
942 if(MatchPixel(xt
+1,yt
,width
,height
,testColour
))
948 SetRGB(xt
+1,yt
,r
,g
,b
);
949 if(qs
>=(qst
+qSz
)) qs
=qst
;
952 //Retrieve current queue member
955 //Loop back to the beginning
956 if(qr
>=(qst
+qSz
)) qr
=qst
;
960 //Go Back to beginning of loop
968 //style is wxFLOOD_BORDER
969 // fill up to testColor border - if already testColour don't do anything
970 if ( GetRed(x
,y
) != testColour
.Red()
971 || GetGreen(x
,y
) != testColour
.Green()
972 || GetBlue(x
,y
) != testColour
.Blue() )
974 //prepare memory for queue
975 //queue save, start, read
976 size_t *qs
, *qst
, *qr
;
978 //queue size (physical)
979 long qSz
= height
* width
* 2;
980 qst
= new size_t [qSz
];
982 //temporary x and y locations
985 for (int i
=0; i
< qSz
; i
++)
1000 //Add new members to queue
1001 //Above current pixel
1002 if(!MatchBoundaryPixel(xt
,yt
-1,width
,height
,fillColour
,testColour
))
1008 SetRGB(xt
,yt
-1,r
,g
,b
);
1010 //Loop back to beginning of queue
1011 if(qs
>=(qst
+qSz
)) qs
=qst
;
1014 //Below current pixel
1015 if(!MatchBoundaryPixel(xt
,yt
+1,width
,height
,fillColour
,testColour
))
1021 SetRGB(xt
,yt
+1,r
,g
,b
);
1022 if(qs
>=(qst
+qSz
)) qs
=qst
;
1025 //Left of current pixel
1026 if(!MatchBoundaryPixel(xt
-1,yt
,width
,height
,fillColour
,testColour
))
1032 SetRGB(xt
-1,yt
,r
,g
,b
);
1033 if(qs
>=(qst
+qSz
)) qs
=qst
;
1036 //Right of current pixel
1037 if(!MatchBoundaryPixel(xt
+1,yt
,width
,height
,fillColour
,testColour
))
1043 SetRGB(xt
+1,yt
,r
,g
,b
);
1044 if(qs
>=(qst
+qSz
)) qs
=qst
;
1047 //Retrieve current queue member
1050 //Loop back to the beginning
1051 if(qr
>=(qst
+qSz
)) qr
=qst
;
1055 //Go Back to beginning of loop
1067 // Palette functions
1069 bool wxImage::HasPalette() const
1074 return M_IMGDATA
->m_palette
.Ok();
1077 const wxPalette
& wxImage::GetPalette() const
1079 wxCHECK_MSG( Ok(), wxNullPalette
, wxT("invalid image") );
1081 return M_IMGDATA
->m_palette
;
1084 void wxImage::SetPalette(const wxPalette
& palette
)
1086 wxCHECK_RET( Ok(), wxT("invalid image") );
1088 M_IMGDATA
->m_palette
= palette
;
1091 #endif // wxUSE_PALETTE
1093 // Option functions (arbitrary name/value mapping)
1094 void wxImage::SetOption(const wxString
& name
, const wxString
& value
)
1096 wxCHECK_RET( Ok(), wxT("invalid image") );
1098 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
1099 if (idx
== wxNOT_FOUND
)
1101 M_IMGDATA
->m_optionNames
.Add(name
);
1102 M_IMGDATA
->m_optionValues
.Add(value
);
1106 M_IMGDATA
->m_optionNames
[idx
] = name
;
1107 M_IMGDATA
->m_optionValues
[idx
] = value
;
1111 void wxImage::SetOption(const wxString
& name
, int value
)
1114 valStr
.Printf(wxT("%d"), value
);
1115 SetOption(name
, valStr
);
1118 wxString
wxImage::GetOption(const wxString
& name
) const
1120 wxCHECK_MSG( Ok(), wxEmptyString
, wxT("invalid image") );
1122 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
1123 if (idx
== wxNOT_FOUND
)
1124 return wxEmptyString
;
1126 return M_IMGDATA
->m_optionValues
[idx
];
1129 int wxImage::GetOptionInt(const wxString
& name
) const
1131 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
1133 return wxAtoi(GetOption(name
));
1136 bool wxImage::HasOption(const wxString
& name
) const
1138 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
1140 return (M_IMGDATA
->m_optionNames
.Index(name
, FALSE
) != wxNOT_FOUND
);
1143 bool wxImage::LoadFile( const wxString
& filename
, long type
, int index
)
1146 if (wxFileExists(filename
))
1148 wxFileInputStream
stream(filename
);
1149 wxBufferedInputStream
bstream( stream
);
1150 return LoadFile(bstream
, type
, index
);
1154 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
1158 #else // !wxUSE_STREAMS
1160 #endif // wxUSE_STREAMS
1163 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
, int index
)
1166 if (wxFileExists(filename
))
1168 wxFileInputStream
stream(filename
);
1169 wxBufferedInputStream
bstream( stream
);
1170 return LoadFile(bstream
, mimetype
, index
);
1174 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
1178 #else // !wxUSE_STREAMS
1180 #endif // wxUSE_STREAMS
1185 bool wxImage::SaveFile( const wxString
& filename
) const
1187 wxString ext
= filename
.AfterLast('.').Lower();
1189 wxImageHandler
* pHandler
= FindHandler(ext
, -1);
1192 SaveFile(filename
, pHandler
->GetType());
1196 wxLogError(_("Can't save image to file '%s': unknown extension."), filename
.c_str());
1201 bool wxImage::SaveFile( const wxString
& filename
, int type
) const
1204 ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
);
1206 wxFileOutputStream
stream(filename
);
1208 if ( stream
.LastError() == wxStream_NOERROR
)
1210 wxBufferedOutputStream
bstream( stream
);
1211 return SaveFile(bstream
, type
);
1213 #endif // wxUSE_STREAMS
1218 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
) const
1221 ((wxImage
*)this)->SetOption(wxIMAGE_OPTION_FILENAME
, filename
);
1223 wxFileOutputStream
stream(filename
);
1225 if ( stream
.LastError() == wxStream_NOERROR
)
1227 wxBufferedOutputStream
bstream( stream
);
1228 return SaveFile(bstream
, mimetype
);
1230 #endif // wxUSE_STREAMS
1235 bool wxImage::CanRead( const wxString
&name
)
1238 wxFileInputStream
stream(name
);
1239 return CanRead(stream
);
1245 int wxImage::GetImageCount( const wxString
&name
, long type
)
1248 wxFileInputStream
stream(name
);
1249 return GetImageCount(stream
, type
);
1257 bool wxImage::CanRead( wxInputStream
&stream
)
1259 wxList
&list
=GetHandlers();
1261 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
1263 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
1264 if (handler
->CanRead( stream
))
1271 int wxImage::GetImageCount( wxInputStream
&stream
, long type
)
1273 wxImageHandler
*handler
;
1275 if ( type
== wxBITMAP_TYPE_ANY
)
1277 wxList
&list
=GetHandlers();
1279 for (wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext())
1281 handler
=(wxImageHandler
*)node
->GetData();
1282 if ( handler
->CanRead(stream
) )
1283 return handler
->GetImageCount(stream
);
1287 wxLogWarning(_("No handler found for image type."));
1291 handler
= FindHandler(type
);
1295 wxLogWarning(_("No image handler for type %d defined."), type
);
1299 if ( handler
->CanRead(stream
) )
1301 return handler
->GetImageCount(stream
);
1305 wxLogError(_("Image file is not of type %d."), type
);
1310 bool wxImage::LoadFile( wxInputStream
& stream
, long type
, int index
)
1314 m_refData
= new wxImageRefData
;
1316 wxImageHandler
*handler
;
1318 if ( type
== wxBITMAP_TYPE_ANY
)
1320 wxList
&list
=GetHandlers();
1322 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
1324 handler
=(wxImageHandler
*)node
->GetData();
1325 if ( handler
->CanRead(stream
) )
1326 return handler
->LoadFile(this, stream
, TRUE
/*verbose*/, index
);
1330 wxLogWarning( _("No handler found for image type.") );
1334 handler
= FindHandler(type
);
1336 if (handler
== NULL
)
1338 wxLogWarning( _("No image handler for type %d defined."), type
);
1343 return handler
->LoadFile(this, stream
, TRUE
/*verbose*/, index
);
1346 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
, int index
)
1350 m_refData
= new wxImageRefData
;
1352 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
1354 if (handler
== NULL
)
1356 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
1361 return handler
->LoadFile( this, stream
, TRUE
/*verbose*/, index
);
1364 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
) const
1366 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
1368 wxImageHandler
*handler
= FindHandler(type
);
1370 if (handler
== NULL
)
1372 wxLogWarning( _("No image handler for type %d defined."), type
);
1377 return handler
->SaveFile( (wxImage
*)this, stream
);
1380 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
) const
1382 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
1384 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
1386 if (handler
== NULL
)
1388 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
1393 return handler
->SaveFile( (wxImage
*)this, stream
);
1395 #endif // wxUSE_STREAMS
1397 void wxImage::AddHandler( wxImageHandler
*handler
)
1399 // make sure that the memory will be freed at the program end
1400 sm_handlers
.DeleteContents(TRUE
);
1402 sm_handlers
.Append( handler
);
1405 void wxImage::InsertHandler( wxImageHandler
*handler
)
1407 // make sure that the memory will be freed at the program end
1408 sm_handlers
.DeleteContents(TRUE
);
1410 sm_handlers
.Insert( handler
);
1413 bool wxImage::RemoveHandler( const wxString
& name
)
1415 wxImageHandler
*handler
= FindHandler(name
);
1418 sm_handlers
.DeleteObject(handler
);
1425 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
1427 wxNode
*node
= sm_handlers
.First();
1430 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
1431 if (handler
->GetName().Cmp(name
) == 0) return handler
;
1433 node
= node
->Next();
1435 return (wxImageHandler
*)NULL
;
1438 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
1440 wxNode
*node
= sm_handlers
.First();
1443 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
1444 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
1445 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
1447 node
= node
->Next();
1449 return (wxImageHandler
*)NULL
;
1452 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
1454 wxNode
*node
= sm_handlers
.First();
1457 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
1458 if (handler
->GetType() == bitmapType
) return handler
;
1459 node
= node
->Next();
1464 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
1466 wxNode
*node
= sm_handlers
.First();
1469 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
1470 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
1471 node
= node
->Next();
1476 void wxImage::InitStandardHandlers()
1479 AddHandler(new wxBMPHandler
);
1480 #endif // wxUSE_STREAMS
1482 #if wxUSE_XPM && !defined(__WXGTK__) && !defined(__WXMOTIF__)
1483 AddHandler(new wxXPMHandler
);
1487 void wxImage::CleanUpHandlers()
1489 wxNode
*node
= sm_handlers
.First();
1492 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
1493 wxNode
*next
= node
->Next();
1500 //-----------------------------------------------------------------------------
1502 //-----------------------------------------------------------------------------
1504 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
1507 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
1512 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
1517 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
1522 bool wxImageHandler::CanRead( const wxString
& name
)
1524 if (wxFileExists(name
))
1526 wxFileInputStream
stream(name
);
1527 return CanRead(stream
);
1531 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
1538 #endif // wxUSE_STREAMS
1542 //-----------------------------------------------------------------------------
1543 // Deprecated wxBitmap convertion routines
1544 //-----------------------------------------------------------------------------
1546 #if WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI
1549 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
) const
1551 wxImage mono
= this->ConvertToMono( red
, green
, blue
);
1552 wxBitmap
bitmap( mono
, 1 );
1557 wxBitmap
wxImage::ConvertToBitmap() const
1559 wxBitmap
bitmap( *this );
1563 wxImage::wxImage( const wxBitmap
&bitmap
)
1565 *this = bitmap
.ConvertToImage();
1568 #endif // WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI
1571 //-----------------------------------------------------------------------------
1574 // Counts and returns the number of different colours. Optionally stops
1575 // when it exceeds 'stopafter' different colours. This is useful, for
1576 // example, to see if the image can be saved as 8-bit (256 colour or
1577 // less, in this case it would be invoked as CountColours(256)). Default
1578 // value for stopafter is -1 (don't care).
1580 unsigned long wxImage::CountColours( unsigned long stopafter
) const
1584 unsigned char r
, g
, b
;
1586 unsigned long size
, nentries
, key
;
1589 size
= GetWidth() * GetHeight();
1592 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
1597 key
= (r
<< 16) | (g
<< 8) | b
;
1599 if (h
.Get(key
) == NULL
)
1610 unsigned long wxImage::ComputeHistogram( wxImageHistogram
&h
) const
1612 unsigned char r
, g
, b
;
1614 unsigned long size
, nentries
, key
;
1619 size
= GetWidth() * GetHeight();
1622 for (unsigned long j
= 0; j
< size
; j
++)
1627 key
= (r
<< 16) | (g
<< 8) | b
;
1629 wxImageHistogramEntry
& entry
= h
[key
];
1630 if ( entry
.value
++ == 0 )
1631 entry
.index
= nentries
++;
1638 * Rotation code by Carlos Moreno
1641 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
1642 // does exactly the same thing. And I also got rid of wxRotationPixel
1643 // bacause of potential problems in architectures where alignment
1644 // is an issue, so I had to rewrite parts of the code.
1646 static const double gs_Epsilon
= 1e-10;
1648 static inline int wxCint (double x
)
1650 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
1654 // Auxiliary function to rotate a point (x,y) with respect to point p0
1655 // make it inline and use a straight return to facilitate optimization
1656 // also, the function receives the sine and cosine of the angle to avoid
1657 // repeating the time-consuming calls to these functions -- sin/cos can
1658 // be computed and stored in the calling function.
1660 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
1662 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
1663 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
1666 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
1668 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
1671 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
1674 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
1676 // Create pointer-based array to accelerate access to wxImage's data
1677 unsigned char ** data
= new unsigned char * [GetHeight()];
1679 data
[0] = GetData();
1681 for (i
= 1; i
< GetHeight(); i
++)
1682 data
[i
] = data
[i
- 1] + (3 * GetWidth());
1684 // precompute coefficients for rotation formula
1685 // (sine and cosine of the angle)
1686 const double cos_angle
= cos(angle
);
1687 const double sin_angle
= sin(angle
);
1689 // Create new Image to store the result
1690 // First, find rectangle that covers the rotated image; to do that,
1691 // rotate the four corners
1693 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
1695 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
1696 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
1697 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
1698 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
1700 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
1701 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
1702 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
1703 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
1705 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
1707 if (offset_after_rotation
!= NULL
)
1709 *offset_after_rotation
= wxPoint (x1
, y1
);
1712 // GRG: The rotated (destination) image is always accessed
1713 // sequentially, so there is no need for a pointer-based
1714 // array here (and in fact it would be slower).
1716 unsigned char * dst
= rotated
.GetData();
1718 // GRG: if the original image has a mask, use its RGB values
1719 // as the blank pixel, else, fall back to default (black).
1721 unsigned char blank_r
= 0;
1722 unsigned char blank_g
= 0;
1723 unsigned char blank_b
= 0;
1727 blank_r
= GetMaskRed();
1728 blank_g
= GetMaskGreen();
1729 blank_b
= GetMaskBlue();
1730 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
1733 // Now, for each point of the rotated image, find where it came from, by
1734 // performing an inverse rotation (a rotation of -angle) and getting the
1735 // pixel at those coordinates
1737 // GRG: I've taken the (interpolating) test out of the loops, so that
1738 // it is done only once, instead of repeating it for each pixel.
1743 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
1745 for (x
= 0; x
< rotated
.GetWidth(); x
++)
1747 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
1749 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
1750 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
1752 // interpolate using the 4 enclosing grid-points. Those
1753 // points can be obtained using floor and ceiling of the
1754 // exact coordinates of the point
1755 // C.M. 2000-02-17: when the point is near the border, special care is required.
1759 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
1761 x1
= wxCint(floor(src
.x
));
1762 x2
= wxCint(ceil(src
.x
));
1764 else // else means that x is near one of the borders (0 or width-1)
1766 x1
= x2
= wxCint (src
.x
);
1769 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
1771 y1
= wxCint(floor(src
.y
));
1772 y2
= wxCint(ceil(src
.y
));
1776 y1
= y2
= wxCint (src
.y
);
1779 // get four points and the distances (square of the distance,
1780 // for efficiency reasons) for the interpolation formula
1782 // GRG: Do not calculate the points until they are
1783 // really needed -- this way we can calculate
1784 // just one, instead of four, if d1, d2, d3
1785 // or d4 are < gs_Epsilon
1787 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
1788 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
1789 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
1790 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
1792 // Now interpolate as a weighted average of the four surrounding
1793 // points, where the weights are the distances to each of those points
1795 // If the point is exactly at one point of the grid of the source
1796 // image, then don't interpolate -- just assign the pixel
1798 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
1800 unsigned char *p
= data
[y1
] + (3 * x1
);
1805 else if (d2
< gs_Epsilon
)
1807 unsigned char *p
= data
[y1
] + (3 * x2
);
1812 else if (d3
< gs_Epsilon
)
1814 unsigned char *p
= data
[y2
] + (3 * x2
);
1819 else if (d4
< gs_Epsilon
)
1821 unsigned char *p
= data
[y2
] + (3 * x1
);
1828 // weights for the weighted average are proportional to the inverse of the distance
1829 unsigned char *v1
= data
[y1
] + (3 * x1
);
1830 unsigned char *v2
= data
[y1
] + (3 * x2
);
1831 unsigned char *v3
= data
[y2
] + (3 * x2
);
1832 unsigned char *v4
= data
[y2
] + (3 * x1
);
1834 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
1838 *(dst
++) = (unsigned char)
1839 ( (w1
* *(v1
++) + w2
* *(v2
++) +
1840 w3
* *(v3
++) + w4
* *(v4
++)) /
1841 (w1
+ w2
+ w3
+ w4
) );
1842 *(dst
++) = (unsigned char)
1843 ( (w1
* *(v1
++) + w2
* *(v2
++) +
1844 w3
* *(v3
++) + w4
* *(v4
++)) /
1845 (w1
+ w2
+ w3
+ w4
) );
1846 *(dst
++) = (unsigned char)
1847 ( (w1
* *(v1
++) + w2
* *(v2
++) +
1848 w3
* *(v3
++) + w4
* *(v4
++)) /
1849 (w1
+ w2
+ w3
+ w4
) );
1861 else // not interpolating
1863 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
1865 for (x
= 0; x
< rotated
.GetWidth(); x
++)
1867 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
1869 const int xs
= wxCint (src
.x
); // wxCint rounds to the
1870 const int ys
= wxCint (src
.y
); // closest integer
1872 if (0 <= xs
&& xs
< GetWidth() &&
1873 0 <= ys
&& ys
< GetHeight())
1875 unsigned char *p
= data
[ys
] + (3 * xs
);
1899 // A module to allow wxImage initialization/cleanup
1900 // without calling these functions from app.cpp or from
1901 // the user's application.
1903 class wxImageModule
: public wxModule
1905 DECLARE_DYNAMIC_CLASS(wxImageModule
)
1908 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
1909 void OnExit() { wxImage::CleanUpHandlers(); };
1912 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
1915 #endif // wxUSE_IMAGE