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"
22 #include "wx/bitmap.h"
26 #include "wx/filefn.h"
27 #include "wx/wfstream.h"
29 #include "wx/module.h"
40 #include "wx/msw/private.h"
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
47 class wxImageRefData
: public wxObjectRefData
55 unsigned char *m_data
;
57 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
61 wxArrayString m_optionNames
;
62 wxArrayString m_optionValues
;
65 wxImageRefData::wxImageRefData()
69 m_data
= (unsigned char*) NULL
;
78 wxImageRefData::~wxImageRefData()
80 if (m_data
&& !m_static
)
84 wxList
wxImage::sm_handlers
;
86 //-----------------------------------------------------------------------------
88 #define M_IMGDATA ((wxImageRefData *)m_refData)
90 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
96 wxImage::wxImage( int width
, int height
)
98 Create( width
, height
);
101 wxImage::wxImage( int width
, int height
, unsigned char* data
, bool static_data
)
103 Create( width
, height
, data
, static_data
);
106 wxImage::wxImage( const wxString
& name
, long type
)
108 LoadFile( name
, type
);
111 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
)
113 LoadFile( name
, mimetype
);
117 wxImage::wxImage( wxInputStream
& stream
, long type
)
119 LoadFile( stream
, type
);
122 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
)
124 LoadFile( stream
, mimetype
);
126 #endif // wxUSE_STREAMS
128 wxImage::wxImage( const wxImage
& image
)
133 wxImage::wxImage( const wxImage
* image
)
135 if (image
) Ref(*image
);
138 void wxImage::Create( int width
, int height
)
142 m_refData
= new wxImageRefData();
144 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
145 if (M_IMGDATA
->m_data
)
147 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
149 M_IMGDATA
->m_width
= width
;
150 M_IMGDATA
->m_height
= height
;
151 M_IMGDATA
->m_ok
= TRUE
;
159 void wxImage::Create( int width
, int height
, unsigned char* data
, bool static_data
)
163 m_refData
= new wxImageRefData();
165 M_IMGDATA
->m_data
= data
;
166 if (M_IMGDATA
->m_data
)
168 M_IMGDATA
->m_width
= width
;
169 M_IMGDATA
->m_height
= height
;
170 M_IMGDATA
->m_ok
= TRUE
;
171 M_IMGDATA
->m_static
= static_data
;
179 void wxImage::Destroy()
184 wxImage
wxImage::Copy() const
188 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
190 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
192 char unsigned *data
= image
.GetData();
194 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
196 if (M_IMGDATA
->m_hasMask
)
197 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
199 memcpy( data
, GetData(), M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3 );
204 wxImage
wxImage::Scale( int width
, int height
) const
208 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
210 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, wxT("invalid image size") );
212 image
.Create( width
, height
);
214 char unsigned *data
= image
.GetData();
216 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
218 if (M_IMGDATA
->m_hasMask
)
219 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
221 long old_height
= M_IMGDATA
->m_height
;
222 long old_width
= M_IMGDATA
->m_width
;
224 char unsigned *source_data
= M_IMGDATA
->m_data
;
225 char unsigned *target_data
= data
;
227 for (long j
= 0; j
< height
; j
++)
229 long y_offset
= (j
* old_height
/ height
) * old_width
;
231 for (long i
= 0; i
< width
; i
++)
234 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
243 wxImage
wxImage::Rotate90( bool clockwise
) const
247 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
249 image
.Create( M_IMGDATA
->m_height
, M_IMGDATA
->m_width
);
251 char unsigned *data
= image
.GetData();
253 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
255 if (M_IMGDATA
->m_hasMask
)
256 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
258 long height
= M_IMGDATA
->m_height
;
259 long width
= M_IMGDATA
->m_width
;
261 char unsigned *source_data
= M_IMGDATA
->m_data
;
262 char unsigned *target_data
;
264 for (long j
= 0; j
< height
; j
++)
266 for (long i
= 0; i
< width
; i
++)
269 target_data
= data
+ (((i
+1)*height
) - j
- 1)*3;
271 target_data
= data
+ ((height
*(width
-1)) + j
- (i
*height
))*3;
272 memcpy( target_data
, source_data
, 3 );
280 wxImage
wxImage::Mirror( bool horizontally
) const
284 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
286 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
288 char unsigned *data
= image
.GetData();
290 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
292 if (M_IMGDATA
->m_hasMask
)
293 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
295 long height
= M_IMGDATA
->m_height
;
296 long width
= M_IMGDATA
->m_width
;
298 char unsigned *source_data
= M_IMGDATA
->m_data
;
299 char unsigned *target_data
;
303 for (long j
= 0; j
< height
; j
++)
306 target_data
= data
-3;
307 for (long i
= 0; i
< width
; i
++)
309 memcpy( target_data
, source_data
, 3 );
317 for (long i
= 0; i
< height
; i
++)
319 target_data
= data
+ 3*width
*(height
-1-i
);
320 memcpy( target_data
, source_data
, (size_t)3*width
);
321 source_data
+= 3*width
;
328 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
332 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
334 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()),
335 image
, wxT("invalid subimage size") );
337 int subwidth
=rect
.GetWidth();
338 const int subheight
=rect
.GetHeight();
340 image
.Create( subwidth
, subheight
);
342 char unsigned *subdata
= image
.GetData(), *data
=GetData();
344 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
346 if (M_IMGDATA
->m_hasMask
)
347 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
349 const int subleft
=3*rect
.GetLeft();
350 const int width
=3*GetWidth();
353 data
+=rect
.GetTop()*width
+subleft
;
355 for (long j
= 0; j
< subheight
; ++j
)
357 memcpy( subdata
, data
, subwidth
);
365 void wxImage::Paste( const wxImage
&image
, int x
, int y
)
367 wxCHECK_RET( Ok(), wxT("invalid image") );
368 wxCHECK_RET( image
.Ok(), wxT("invalid image") );
372 int width
= image
.GetWidth();
373 int height
= image
.GetHeight();
386 if ((x
+xx
)+width
> M_IMGDATA
->m_width
)
387 width
= M_IMGDATA
->m_width
- (x
+xx
);
388 if ((y
+yy
)+height
> M_IMGDATA
->m_height
)
389 height
= M_IMGDATA
->m_height
- (y
+yy
);
391 if (width
< 1) return;
392 if (height
< 1) return;
394 if ((!HasMask() && !image
.HasMask()) ||
395 ((HasMask() && image
.HasMask() &&
396 (GetMaskRed()==image
.GetMaskRed()) &&
397 (GetMaskGreen()==image
.GetMaskGreen()) &&
398 (GetMaskBlue()==image
.GetMaskBlue()))))
401 unsigned char* source_data
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth();
402 int source_step
= image
.GetWidth()*3;
404 unsigned char* target_data
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
;
405 int target_step
= M_IMGDATA
->m_width
*3;
406 for (int j
= 0; j
< height
; j
++)
408 memcpy( target_data
, source_data
, width
);
409 source_data
+= source_step
;
410 target_data
+= target_step
;
415 if (!HasMask() && image
.HasMask())
417 unsigned char r
= image
.GetMaskRed();
418 unsigned char g
= image
.GetMaskGreen();
419 unsigned char b
= image
.GetMaskBlue();
422 unsigned char* source_data
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth();
423 int source_step
= image
.GetWidth()*3;
425 unsigned char* target_data
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
;
426 int target_step
= M_IMGDATA
->m_width
*3;
428 for (int j
= 0; j
< height
; j
++)
430 for (int i
= 0; i
< width
; i
+=3)
432 if ((source_data
[i
] != r
) &&
433 (source_data
[i
+1] != g
) &&
434 (source_data
[i
+2] != b
))
436 memcpy( target_data
+i
, source_data
+i
, 3 );
439 source_data
+= source_step
;
440 target_data
+= target_step
;
445 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
446 unsigned char r2
, unsigned char g2
, unsigned char b2
)
448 wxCHECK_RET( Ok(), wxT("invalid image") );
450 char unsigned *data
= GetData();
452 const int w
= GetWidth();
453 const int h
= GetHeight();
455 for (int j
= 0; j
< h
; j
++)
456 for (int i
= 0; i
< w
; i
++)
458 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
468 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
470 wxCHECK_RET( Ok(), wxT("invalid image") );
472 int w
= M_IMGDATA
->m_width
;
473 int h
= M_IMGDATA
->m_height
;
475 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
477 long pos
= (y
* w
+ x
) * 3;
479 M_IMGDATA
->m_data
[ pos
] = r
;
480 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
481 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
484 unsigned char wxImage::GetRed( int x
, int y
) const
486 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
488 int w
= M_IMGDATA
->m_width
;
489 int h
= M_IMGDATA
->m_height
;
491 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
493 long pos
= (y
* w
+ x
) * 3;
495 return M_IMGDATA
->m_data
[pos
];
498 unsigned char wxImage::GetGreen( int x
, int y
) const
500 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
502 int w
= M_IMGDATA
->m_width
;
503 int h
= M_IMGDATA
->m_height
;
505 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
507 long pos
= (y
* w
+ x
) * 3;
509 return M_IMGDATA
->m_data
[pos
+1];
512 unsigned char wxImage::GetBlue( int x
, int y
) const
514 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
516 int w
= M_IMGDATA
->m_width
;
517 int h
= M_IMGDATA
->m_height
;
519 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
521 long pos
= (y
* w
+ x
) * 3;
523 return M_IMGDATA
->m_data
[pos
+2];
526 bool wxImage::Ok() const
528 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
531 char unsigned *wxImage::GetData() const
533 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
535 return M_IMGDATA
->m_data
;
538 void wxImage::SetData( char unsigned *data
)
540 wxCHECK_RET( Ok(), wxT("invalid image") );
542 wxImageRefData
*newRefData
= new wxImageRefData();
544 newRefData
->m_width
= M_IMGDATA
->m_width
;
545 newRefData
->m_height
= M_IMGDATA
->m_height
;
546 newRefData
->m_data
= data
;
547 newRefData
->m_ok
= TRUE
;
548 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
549 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
550 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
551 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
555 m_refData
= newRefData
;
558 void wxImage::SetData( char unsigned *data
, int new_width
, int new_height
)
560 wxImageRefData
*newRefData
= new wxImageRefData();
564 newRefData
->m_width
= new_width
;
565 newRefData
->m_height
= new_height
;
566 newRefData
->m_data
= data
;
567 newRefData
->m_ok
= TRUE
;
568 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
569 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
570 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
571 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
575 newRefData
->m_width
= new_width
;
576 newRefData
->m_height
= new_height
;
577 newRefData
->m_data
= data
;
578 newRefData
->m_ok
= TRUE
;
583 m_refData
= newRefData
;
586 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
588 wxCHECK_RET( Ok(), wxT("invalid image") );
590 M_IMGDATA
->m_maskRed
= r
;
591 M_IMGDATA
->m_maskGreen
= g
;
592 M_IMGDATA
->m_maskBlue
= b
;
593 M_IMGDATA
->m_hasMask
= TRUE
;
596 unsigned char wxImage::GetMaskRed() const
598 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
600 return M_IMGDATA
->m_maskRed
;
603 unsigned char wxImage::GetMaskGreen() const
605 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
607 return M_IMGDATA
->m_maskGreen
;
610 unsigned char wxImage::GetMaskBlue() const
612 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
614 return M_IMGDATA
->m_maskBlue
;
617 void wxImage::SetMask( bool mask
)
619 wxCHECK_RET( Ok(), wxT("invalid image") );
621 M_IMGDATA
->m_hasMask
= mask
;
624 bool wxImage::HasMask() const
626 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
628 return M_IMGDATA
->m_hasMask
;
631 int wxImage::GetWidth() const
633 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
635 return M_IMGDATA
->m_width
;
638 int wxImage::GetHeight() const
640 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
642 return M_IMGDATA
->m_height
;
647 bool wxImage::HasPalette() const
652 return M_IMGDATA
->m_palette
.Ok();
655 const wxPalette
& wxImage::GetPalette() const
657 wxCHECK_MSG( Ok(), wxNullPalette
, wxT("invalid image") );
659 return M_IMGDATA
->m_palette
;
662 void wxImage::SetPalette(const wxPalette
& palette
)
664 wxCHECK_RET( Ok(), wxT("invalid image") );
666 M_IMGDATA
->m_palette
= palette
;
669 // Option functions (arbitrary name/value mapping)
670 void wxImage::SetOption(const wxString
& name
, const wxString
& value
)
672 wxCHECK_RET( Ok(), wxT("invalid image") );
674 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
675 if (idx
== wxNOT_FOUND
)
677 M_IMGDATA
->m_optionNames
.Add(name
);
678 M_IMGDATA
->m_optionValues
.Add(value
);
682 M_IMGDATA
->m_optionNames
[idx
] = name
;
683 M_IMGDATA
->m_optionValues
[idx
] = value
;
687 void wxImage::SetOption(const wxString
& name
, int value
)
690 valStr
.Printf(wxT("%d"), value
);
691 SetOption(name
, valStr
);
694 wxString
wxImage::GetOption(const wxString
& name
) const
696 wxCHECK_MSG( Ok(), wxEmptyString
, wxT("invalid image") );
698 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
699 if (idx
== wxNOT_FOUND
)
700 return wxEmptyString
;
702 return M_IMGDATA
->m_optionValues
[idx
];
705 int wxImage::GetOptionInt(const wxString
& name
) const
707 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
709 return wxAtoi(GetOption(name
));
712 bool wxImage::HasOption(const wxString
& name
) const
714 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
716 return (M_IMGDATA
->m_optionNames
.Index(name
, FALSE
) != wxNOT_FOUND
);
719 bool wxImage::LoadFile( const wxString
& filename
, long type
)
722 if (wxFileExists(filename
))
724 wxFileInputStream
stream(filename
);
725 wxBufferedInputStream
bstream( stream
);
726 return LoadFile(bstream
, type
);
730 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
734 #else // !wxUSE_STREAMS
736 #endif // wxUSE_STREAMS
739 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
742 if (wxFileExists(filename
))
744 wxFileInputStream
stream(filename
);
745 wxBufferedInputStream
bstream( stream
);
746 return LoadFile(bstream
, mimetype
);
750 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
754 #else // !wxUSE_STREAMS
756 #endif // wxUSE_STREAMS
759 bool wxImage::SaveFile( const wxString
& filename
, int type
)
762 wxFileOutputStream
stream(filename
);
764 if ( stream
.LastError() == wxStream_NOERROR
)
766 wxBufferedOutputStream
bstream( stream
);
767 return SaveFile(bstream
, type
);
769 #endif // wxUSE_STREAMS
774 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
777 wxFileOutputStream
stream(filename
);
779 if ( stream
.LastError() == wxStream_NOERROR
)
781 wxBufferedOutputStream
bstream( stream
);
782 return SaveFile(bstream
, mimetype
);
784 #endif // wxUSE_STREAMS
789 bool wxImage::CanRead( const wxString
&name
)
792 wxFileInputStream
stream(name
);
793 return CanRead(stream
);
801 bool wxImage::CanRead( wxInputStream
&stream
)
803 wxList
&list
=GetHandlers();
805 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
807 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
808 if (handler
->CanRead( stream
))
815 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
819 m_refData
= new wxImageRefData
;
821 wxImageHandler
*handler
;
823 if (type
==wxBITMAP_TYPE_ANY
)
825 wxList
&list
=GetHandlers();
827 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
829 handler
=(wxImageHandler
*)node
->GetData();
830 if (handler
->CanRead( stream
))
831 return handler
->LoadFile( this, stream
);
835 wxLogWarning( _("No handler found for image type.") );
839 handler
= FindHandler(type
);
843 wxLogWarning( _("No image handler for type %d defined."), type
);
848 return handler
->LoadFile( this, stream
);
851 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
855 m_refData
= new wxImageRefData
;
857 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
861 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
866 return handler
->LoadFile( this, stream
);
869 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
871 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
873 wxImageHandler
*handler
= FindHandler(type
);
877 wxLogWarning( _("No image handler for type %d defined."), type
);
882 return handler
->SaveFile( this, stream
);
885 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
887 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
889 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
893 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
898 return handler
->SaveFile( this, stream
);
900 #endif // wxUSE_STREAMS
902 void wxImage::AddHandler( wxImageHandler
*handler
)
904 // make sure that the memory will be freed at the program end
905 sm_handlers
.DeleteContents(TRUE
);
907 sm_handlers
.Append( handler
);
910 void wxImage::InsertHandler( wxImageHandler
*handler
)
912 // make sure that the memory will be freed at the program end
913 sm_handlers
.DeleteContents(TRUE
);
915 sm_handlers
.Insert( handler
);
918 bool wxImage::RemoveHandler( const wxString
& name
)
920 wxImageHandler
*handler
= FindHandler(name
);
923 sm_handlers
.DeleteObject(handler
);
930 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
932 wxNode
*node
= sm_handlers
.First();
935 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
936 if (handler
->GetName().Cmp(name
) == 0) return handler
;
940 return (wxImageHandler
*)NULL
;
943 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
945 wxNode
*node
= sm_handlers
.First();
948 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
949 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
950 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
954 return (wxImageHandler
*)NULL
;
957 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
959 wxNode
*node
= sm_handlers
.First();
962 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
963 if (handler
->GetType() == bitmapType
) return handler
;
969 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
971 wxNode
*node
= sm_handlers
.First();
974 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
975 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
981 void wxImage::InitStandardHandlers()
983 AddHandler( new wxBMPHandler
);
986 void wxImage::CleanUpHandlers()
988 wxNode
*node
= sm_handlers
.First();
991 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
992 wxNode
*next
= node
->Next();
999 //-----------------------------------------------------------------------------
1001 //-----------------------------------------------------------------------------
1003 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
1006 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
1011 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
1016 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
1021 bool wxImageHandler::CanRead( const wxString
& name
)
1023 if (wxFileExists(name
))
1025 wxFileInputStream
stream(name
);
1026 return CanRead(stream
);
1030 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
1037 #endif // wxUSE_STREAMS
1039 //-----------------------------------------------------------------------------
1040 // MSW conversion routines
1041 //-----------------------------------------------------------------------------
1045 wxBitmap
wxImage::ConvertToBitmap() const
1048 return wxNullBitmap
;
1050 // sizeLimit is the MS upper limit for the DIB size
1052 int sizeLimit
= 1024*768*3;
1054 int sizeLimit
= 0x7fff ;
1057 // width and height of the device-dependent bitmap
1058 int width
= GetWidth();
1059 int bmpHeight
= GetHeight();
1061 // calc the number of bytes per scanline and padding
1062 int bytePerLine
= width
*3;
1063 int sizeDWORD
= sizeof( DWORD
);
1064 int lineBoundary
= bytePerLine
% sizeDWORD
;
1066 if( lineBoundary
> 0 )
1068 padding
= sizeDWORD
- lineBoundary
;
1069 bytePerLine
+= padding
;
1071 // calc the number of DIBs and heights of DIBs
1074 int height
= sizeLimit
/bytePerLine
;
1075 if( height
>= bmpHeight
)
1079 numDIB
= bmpHeight
/ height
;
1080 hRemain
= bmpHeight
% height
;
1081 if( hRemain
>0 ) numDIB
++;
1084 // set bitmap parameters
1086 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1087 bitmap
.SetWidth( width
);
1088 bitmap
.SetHeight( bmpHeight
);
1089 bitmap
.SetDepth( wxDisplayDepth() );
1091 // create a DIB header
1092 int headersize
= sizeof(BITMAPINFOHEADER
);
1093 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1094 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
1095 // Fill in the DIB header
1096 lpDIBh
->bmiHeader
.biSize
= headersize
;
1097 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
1098 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1099 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1100 // the general formula for biSizeImage:
1101 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
1102 lpDIBh
->bmiHeader
.biPlanes
= 1;
1103 lpDIBh
->bmiHeader
.biBitCount
= 24;
1104 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1105 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1106 // These seem not really needed for our purpose here.
1107 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1108 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1109 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1110 // memory for DIB data
1111 unsigned char *lpBits
;
1112 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1115 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
1120 // create and set the device-dependent bitmap
1121 HDC hdc
= ::GetDC(NULL
);
1122 HDC memdc
= ::CreateCompatibleDC( hdc
);
1124 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
1125 ::SelectObject( memdc
, hbitmap
);
1127 HPALETTE hOldPalette
= 0;
1128 if (GetPalette().Ok())
1130 hOldPalette
= ::SelectPalette(memdc
, (HPALETTE
) GetPalette().GetHPALETTE(), FALSE
);
1131 ::RealizePalette(memdc
);
1134 // copy image data into DIB data and then into DDB (in a loop)
1135 unsigned char *data
= GetData();
1138 unsigned char *ptdata
= data
;
1139 unsigned char *ptbits
;
1141 for( n
=0; n
<numDIB
; n
++ )
1143 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
1145 // redefine height and size of the (possibly) last smaller DIB
1146 // memory is not reallocated
1148 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1149 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1153 for( j
=0; j
<height
; j
++ )
1155 for( i
=0; i
<width
; i
++ )
1157 *(ptbits
++) = *(ptdata
+2);
1158 *(ptbits
++) = *(ptdata
+1);
1159 *(ptbits
++) = *(ptdata
);
1162 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
1164 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1165 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1167 // if numDIB = 1, lines below can also be used
1168 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1169 // The above line is equivalent to the following two lines.
1170 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1171 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1172 // or the following lines
1173 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1174 // HDC memdc = ::CreateCompatibleDC( hdc );
1175 // ::SelectObject( memdc, hbitmap);
1176 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1177 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1178 // ::SelectObject( memdc, 0 );
1179 // ::DeleteDC( memdc );
1181 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
1184 SelectPalette(memdc
, hOldPalette
, FALSE
);
1186 // similarly, created an mono-bitmap for the possible mask
1189 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
1190 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
1191 if( numDIB
== 1 ) height
= bmpHeight
;
1192 else height
= sizeLimit
/bytePerLine
;
1193 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1194 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1196 unsigned char r
= GetMaskRed();
1197 unsigned char g
= GetMaskGreen();
1198 unsigned char b
= GetMaskBlue();
1199 unsigned char zero
= 0, one
= 255;
1201 for( n
=0; n
<numDIB
; n
++ )
1203 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
1205 // redefine height and size of the (possibly) last smaller DIB
1206 // memory is not reallocated
1208 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1209 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1212 for( int j
=0; j
<height
; j
++ )
1214 for(i
=0; i
<width
; i
++ )
1216 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
1217 unsigned char cr
= (*(ptdata
++)) ;
1218 unsigned char cg
= (*(ptdata
++)) ;
1219 unsigned char cb
= (*(ptdata
++)) ;
1221 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
1234 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
1236 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1237 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1240 // create a wxMask object
1241 wxMask
*mask
= new wxMask();
1242 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
1243 bitmap
.SetMask( mask
);
1244 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1245 /* The following can also be used but is slow to run
1246 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1247 wxMask *mask = new wxMask( bitmap, colour );
1248 bitmap.SetMask( mask );
1251 ::SelectObject( memdc
, hbmpOld
);
1254 // free allocated resources
1255 ::DeleteDC( memdc
);
1256 ::ReleaseDC(NULL
, hdc
);
1260 #if WXWIN_COMPATIBILITY_2
1261 // check the wxBitmap object
1262 bitmap
.GetBitmapData()->SetOk();
1263 #endif // WXWIN_COMPATIBILITY_2
1268 wxImage::wxImage( const wxBitmap
&bitmap
)
1273 wxFAIL_MSG( wxT("invalid bitmap") );
1277 // create an wxImage object
1278 int width
= bitmap
.GetWidth();
1279 int height
= bitmap
.GetHeight();
1280 Create( width
, height
);
1281 unsigned char *data
= GetData();
1284 wxFAIL_MSG( wxT("could not allocate data for image") );
1288 // calc the number of bytes per scanline and padding in the DIB
1289 int bytePerLine
= width
*3;
1290 int sizeDWORD
= sizeof( DWORD
);
1291 int lineBoundary
= bytePerLine
% sizeDWORD
;
1293 if( lineBoundary
> 0 )
1295 padding
= sizeDWORD
- lineBoundary
;
1296 bytePerLine
+= padding
;
1299 // create a DIB header
1300 int headersize
= sizeof(BITMAPINFOHEADER
);
1301 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1304 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1308 // Fill in the DIB header
1309 lpDIBh
->bmiHeader
.biSize
= headersize
;
1310 lpDIBh
->bmiHeader
.biWidth
= width
;
1311 lpDIBh
->bmiHeader
.biHeight
= -height
;
1312 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
1313 lpDIBh
->bmiHeader
.biPlanes
= 1;
1314 lpDIBh
->bmiHeader
.biBitCount
= 24;
1315 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1316 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1317 // These seem not really needed for our purpose here.
1318 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1319 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1320 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1321 // memory for DIB data
1322 unsigned char *lpBits
;
1323 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1326 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1332 // copy data from the device-dependent bitmap to the DIB
1333 HDC hdc
= ::GetDC(NULL
);
1335 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1336 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1338 // copy DIB data into the wxImage object
1340 unsigned char *ptdata
= data
;
1341 unsigned char *ptbits
= lpBits
;
1342 for( i
=0; i
<height
; i
++ )
1344 for( j
=0; j
<width
; j
++ )
1346 *(ptdata
++) = *(ptbits
+2);
1347 *(ptdata
++) = *(ptbits
+1);
1348 *(ptdata
++) = *(ptbits
);
1354 // similarly, set data according to the possible mask bitmap
1355 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1357 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1358 // memory DC created, color set, data copied, and memory DC deleted
1359 HDC memdc
= ::CreateCompatibleDC( hdc
);
1360 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1361 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1362 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1363 ::DeleteDC( memdc
);
1364 // background color set to RGB(16,16,16) in consistent with wxGTK
1365 unsigned char r
=16, g
=16, b
=16;
1368 for( i
=0; i
<height
; i
++ )
1370 for( j
=0; j
<width
; j
++ )
1384 SetMaskColour( r
, g
, b
);
1391 // free allocated resources
1392 ::ReleaseDC(NULL
, hdc
);
1401 #include <PictUtils.h>
1403 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1404 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1405 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1406 extern GWorldPtr
wxMacCreateGWorld( int height
, int width
, int depth
) ;
1407 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1409 wxBitmap
wxImage::ConvertToBitmap() const
1411 // width and height of the device-dependent bitmap
1412 int width
= GetWidth();
1413 int height
= GetHeight();
1417 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1424 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1426 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1428 wxMask *mask = new wxMask();
1429 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1431 bitmap.SetMask( mask );
1437 int r_mask
= GetMaskRed();
1438 int g_mask
= GetMaskGreen();
1439 int b_mask
= GetMaskBlue();
1442 GDHandle origDevice
;
1444 GetGWorld( &origPort
, &origDevice
) ;
1445 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1447 register unsigned char* data
= GetData();
1450 for (int y
= 0; y
< height
; y
++)
1452 for (int x
= 0; x
< width
; x
++)
1454 unsigned char r
= data
[index
++];
1455 unsigned char g
= data
[index
++];
1456 unsigned char b
= data
[index
++];
1458 color
.red
= ( r
<< 8 ) + r
;
1459 color
.green
= ( g
<< 8 ) + g
;
1460 color
.blue
= ( b
<< 8 ) + b
;
1461 SetCPixel( x
, y
, &color
) ;
1465 SetGWorld( origPort
, origDevice
) ;
1469 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1470 wxMask
*mask
= new wxMask( bitmap
, colour
);
1471 bitmap
.SetMask( mask
);
1477 wxImage::wxImage( const wxBitmap
&bitmap
)
1482 wxFAIL_MSG( "invalid bitmap" );
1486 // create an wxImage object
1487 int width
= bitmap
.GetWidth();
1488 int height
= bitmap
.GetHeight();
1489 Create( width
, height
);
1491 unsigned char *data = GetData();
1494 wxFAIL_MSG( "could not allocate data for image" );
1498 // calc the number of bytes per scanline and padding in the DIB
1499 int bytePerLine = width*3;
1500 int sizeDWORD = sizeof( DWORD );
1501 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1503 if( lineBoundary.rem > 0 )
1505 padding = sizeDWORD - lineBoundary.rem;
1506 bytePerLine += padding;
1509 // create a DIB header
1510 int headersize = sizeof(BITMAPINFOHEADER);
1511 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1514 wxFAIL_MSG( "could not allocate data for DIB header" );
1518 // Fill in the DIB header
1519 lpDIBh->bmiHeader.biSize = headersize;
1520 lpDIBh->bmiHeader.biWidth = width;
1521 lpDIBh->bmiHeader.biHeight = -height;
1522 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1523 lpDIBh->bmiHeader.biPlanes = 1;
1524 lpDIBh->bmiHeader.biBitCount = 24;
1525 lpDIBh->bmiHeader.biCompression = BI_RGB;
1526 lpDIBh->bmiHeader.biClrUsed = 0;
1527 // These seem not really needed for our purpose here.
1528 lpDIBh->bmiHeader.biClrImportant = 0;
1529 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1530 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1531 // memory for DIB data
1532 unsigned char *lpBits;
1533 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1536 wxFAIL_MSG( "could not allocate data for DIB" );
1542 // copy data from the device-dependent bitmap to the DIB
1543 HDC hdc = ::GetDC(NULL);
1545 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1546 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1548 // copy DIB data into the wxImage object
1550 unsigned char *ptdata = data;
1551 unsigned char *ptbits = lpBits;
1552 for( i=0; i<height; i++ )
1554 for( j=0; j<width; j++ )
1556 *(ptdata++) = *(ptbits+2);
1557 *(ptdata++) = *(ptbits+1);
1558 *(ptdata++) = *(ptbits );
1564 // similarly, set data according to the possible mask bitmap
1565 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1567 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1568 // memory DC created, color set, data copied, and memory DC deleted
1569 HDC memdc = ::CreateCompatibleDC( hdc );
1570 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1571 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1572 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1573 ::DeleteDC( memdc );
1574 // background color set to RGB(16,16,16) in consistent with wxGTK
1575 unsigned char r=16, g=16, b=16;
1578 for( i=0; i<height; i++ )
1580 for( j=0; j<width; j++ )
1594 SetMaskColour( r, g, b );
1601 // free allocated resources
1602 ::ReleaseDC(NULL, hdc);
1610 //-----------------------------------------------------------------------------
1611 // GTK conversion routines
1612 //-----------------------------------------------------------------------------
1616 #include <gtk/gtk.h>
1617 #include <gdk/gdk.h>
1618 #include <gdk/gdkx.h>
1620 #if (GTK_MINOR_VERSION > 0)
1621 #include <gdk/gdkrgb.h>
1624 extern GtkWidget
*wxRootWindow
;
1626 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1630 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1632 int width
= GetWidth();
1633 int height
= GetHeight();
1635 bitmap
.SetHeight( height
);
1636 bitmap
.SetWidth( width
);
1638 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1640 bitmap
.SetDepth( 1 );
1642 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1645 // Create picture image
1647 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1649 GdkImage
*data_image
=
1650 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1652 // Create mask image
1654 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1658 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1660 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1662 wxMask
*mask
= new wxMask();
1663 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1665 bitmap
.SetMask( mask
);
1668 int r_mask
= GetMaskRed();
1669 int g_mask
= GetMaskGreen();
1670 int b_mask
= GetMaskBlue();
1672 unsigned char* data
= GetData();
1675 for (int y
= 0; y
< height
; y
++)
1677 for (int x
= 0; x
< width
; x
++)
1679 int r
= data
[index
];
1681 int g
= data
[index
];
1683 int b
= data
[index
];
1688 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1689 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1691 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1694 if ((r
== red
) && (b
== blue
) && (g
== green
))
1695 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1697 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1704 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1706 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1708 gdk_image_destroy( data_image
);
1709 gdk_gc_unref( data_gc
);
1715 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1717 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1719 gdk_image_destroy( mask_image
);
1720 gdk_gc_unref( mask_gc
);
1727 wxBitmap
wxImage::ConvertToBitmap() const
1731 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1733 int width
= GetWidth();
1734 int height
= GetHeight();
1736 bitmap
.SetHeight( height
);
1737 bitmap
.SetWidth( width
);
1739 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1743 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1746 int bpp
= visual
->depth
;
1748 bitmap
.SetDepth( bpp
);
1750 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1751 if (bpp
< 8) bpp
= 8;
1753 #if (GTK_MINOR_VERSION > 0)
1755 if (!HasMask() && (bpp
> 8))
1757 static bool s_hasInitialized
= FALSE
;
1759 if (!s_hasInitialized
)
1762 s_hasInitialized
= TRUE
;
1765 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1767 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1771 GDK_RGB_DITHER_NONE
,
1782 // Create picture image
1784 GdkImage
*data_image
=
1785 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1787 // Create mask image
1789 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1793 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1795 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1797 wxMask
*mask
= new wxMask();
1798 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1800 bitmap
.SetMask( mask
);
1805 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1806 byte_order b_o
= RGB
;
1810 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1811 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1812 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1813 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1814 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1815 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1818 int r_mask
= GetMaskRed();
1819 int g_mask
= GetMaskGreen();
1820 int b_mask
= GetMaskBlue();
1822 unsigned char* data
= GetData();
1825 for (int y
= 0; y
< height
; y
++)
1827 for (int x
= 0; x
< width
; x
++)
1829 int r
= data
[index
];
1831 int g
= data
[index
];
1833 int b
= data
[index
];
1838 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1839 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1841 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1849 if (wxTheApp
->m_colorCube
)
1851 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1855 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1856 GdkColor
*colors
= cmap
->colors
;
1857 int max
= 3 * (65536);
1859 for (int i
= 0; i
< cmap
->size
; i
++)
1861 int rdiff
= (r
<< 8) - colors
[i
].red
;
1862 int gdiff
= (g
<< 8) - colors
[i
].green
;
1863 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1864 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1865 if (sum
< max
) { pixel
= i
; max
= sum
; }
1869 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1875 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1876 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1881 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1882 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1891 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1892 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1893 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1894 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1895 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1896 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1898 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1907 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1909 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1911 gdk_image_destroy( data_image
);
1912 gdk_gc_unref( data_gc
);
1918 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1920 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1922 gdk_image_destroy( mask_image
);
1923 gdk_gc_unref( mask_gc
);
1929 wxImage::wxImage( const wxBitmap
&bitmap
)
1931 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1933 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1934 if (bitmap
.GetPixmap())
1936 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1938 bitmap
.GetWidth(), bitmap
.GetHeight() );
1940 if (bitmap
.GetBitmap())
1942 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1944 bitmap
.GetWidth(), bitmap
.GetHeight() );
1947 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1950 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1952 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1953 char unsigned *data
= GetData();
1957 gdk_image_destroy( gdk_image
);
1958 wxFAIL_MSG( wxT("couldn't create image") );
1962 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1963 if (bitmap
.GetMask())
1965 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1967 bitmap
.GetWidth(), bitmap
.GetHeight() );
1969 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1973 int red_shift_right
= 0;
1974 int green_shift_right
= 0;
1975 int blue_shift_right
= 0;
1976 int red_shift_left
= 0;
1977 int green_shift_left
= 0;
1978 int blue_shift_left
= 0;
1979 bool use_shift
= FALSE
;
1981 if (bitmap
.GetPixmap())
1983 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1985 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1986 bpp
= visual
->depth
;
1987 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1988 red_shift_right
= visual
->red_shift
;
1989 red_shift_left
= 8-visual
->red_prec
;
1990 green_shift_right
= visual
->green_shift
;
1991 green_shift_left
= 8-visual
->green_prec
;
1992 blue_shift_right
= visual
->blue_shift
;
1993 blue_shift_left
= 8-visual
->blue_prec
;
1995 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
1997 if (bitmap
.GetBitmap())
2003 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
2006 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2008 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2010 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
2028 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
2029 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
2030 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
2032 else if (cmap
->colors
)
2034 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
2035 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
2036 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
2040 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
2045 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
2046 if (mask_pixel
== 0)
2058 gdk_image_destroy( gdk_image
);
2059 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
2064 //-----------------------------------------------------------------------------
2065 // Motif conversion routines
2066 //-----------------------------------------------------------------------------
2070 #pragma message disable nosimpint
2074 #pragma message enable nosimpint
2076 #include "wx/utils.h"
2081 Date: Wed, 05 Jan 2000 11:45:40 +0100
2082 From: Frits Boel <boel@niob.knaw.nl>
2083 To: julian.smart@ukonline.co.uk
2084 Subject: Patch for Motif ConvertToBitmap
2088 I've been working on a wxWin application for image processing. From the
2089 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
2090 till I looked in the source code of image.cpp. I saw that converting a
2091 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
2092 to the 256 colors of the palet. A very time-consuming piece of code!
2094 Because I wanted a faster application, I've made a 'patch' for this. In
2095 short: every pixel of the image is compared to a sorted list with
2096 colors. If the color is found in the list, the palette entry is
2097 returned; if the color is not found, the color palette is searched and
2098 then the palette entry is returned and the color added to the sorted
2101 Maybe there is another method for this, namely changing the palette
2102 itself (if the colors are known, as is the case with tiffs with a
2103 colormap). I did not look at this, maybe someone else did?
2105 The code of the patch is attached, have a look on it, and maybe you will
2106 ship it with the next release of wxMotif?
2111 Software engineer at Hubrecht Laboratory, The Netherlands.
2118 wxSearchColor( void );
2119 wxSearchColor( int size
, XColor
*colors
);
2120 ~wxSearchColor( void );
2122 int SearchColor( int r
, int g
, int b
);
2124 int AddColor( unsigned int value
, int pos
);
2128 unsigned int *color
;
2135 wxSearchColor::wxSearchColor( void )
2138 colors
= (XColor
*) NULL
;
2139 color
= (unsigned int *) NULL
;
2140 entry
= (int*) NULL
;
2146 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
2151 color
= new unsigned int[size
];
2152 entry
= new int [size
];
2154 for (i
= 0; i
< size
; i
++ ) {
2158 bottom
= top
= ( size
>> 1 );
2161 wxSearchColor::~wxSearchColor( void )
2163 if ( color
) delete color
;
2164 if ( entry
) delete entry
;
2167 int wxSearchColor::SearchColor( int r
, int g
, int b
)
2169 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
2174 while ( begin
<= end
) {
2176 middle
= ( begin
+ end
) >> 1;
2178 if ( value
== color
[middle
] ) {
2179 return( entry
[middle
] );
2180 } else if ( value
< color
[middle
] ) {
2188 return AddColor( value
, middle
);
2191 int wxSearchColor::AddColor( unsigned int value
, int pos
)
2195 int max
= 3 * (65536);
2196 for ( i
= 0; i
< 256; i
++ ) {
2197 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
2198 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
2199 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
2200 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2201 if (sum
< max
) { pixel
= i
; max
= sum
; }
2204 if ( entry
[pos
] < 0 ) {
2207 } else if ( value
< color
[pos
] ) {
2210 for ( i
= bottom
; i
< pos
; i
++ ) {
2211 color
[i
-1] = color
[i
];
2212 entry
[i
-1] = entry
[i
];
2215 color
[pos
-1] = value
;
2216 entry
[pos
-1] = pixel
;
2217 } else if ( top
< size
-1 ) {
2218 for ( i
= top
; i
>= pos
; i
-- ) {
2219 color
[i
+1] = color
[i
];
2220 entry
[i
+1] = entry
[i
];
2229 if ( top
< size
-1 ) {
2230 for ( i
= top
; i
> pos
; i
-- ) {
2231 color
[i
+1] = color
[i
];
2232 entry
[i
+1] = entry
[i
];
2235 color
[pos
+1] = value
;
2236 entry
[pos
+1] = pixel
;
2237 } else if ( bottom
> 0 ) {
2238 for ( i
= bottom
; i
< pos
; i
++ ) {
2239 color
[i
-1] = color
[i
];
2240 entry
[i
-1] = entry
[i
];
2252 wxBitmap
wxImage::ConvertToBitmap() const
2256 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
2258 int width
= GetWidth();
2259 int height
= GetHeight();
2261 bitmap
.SetHeight( height
);
2262 bitmap
.SetWidth( width
);
2264 Display
*dpy
= (Display
*) wxGetDisplay();
2265 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2266 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2270 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2271 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
2273 bitmap
.Create( width
, height
, bpp
);
2277 XImage
*mask_image
= (XImage
*) NULL
;
2280 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2281 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
2284 // Retrieve depth info
2286 XVisualInfo vinfo_template
;
2289 vinfo_template
.visual
= vis
;
2290 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2291 vinfo_template
.depth
= bpp
;
2294 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2296 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
2300 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2301 if (bpp
< 8) bpp
= 8;
2305 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
2306 byte_order b_o
= RGB
;
2310 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2311 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2312 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2313 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2314 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2315 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2318 int r_mask
= GetMaskRed();
2319 int g_mask
= GetMaskGreen();
2320 int b_mask
= GetMaskBlue();
2325 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2327 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2328 XQueryColors( dpy
, cmap
, colors
, 256 );
2331 wxSearchColor
scolor( 256, colors
);
2332 unsigned char* data
= GetData();
2334 bool hasMask
= HasMask();
2337 for (int y
= 0; y
< height
; y
++)
2339 for (int x
= 0; x
< width
; x
++)
2341 int r
= data
[index
];
2343 int g
= data
[index
];
2345 int b
= data
[index
];
2350 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2351 XPutPixel( mask_image
, x
, y
, 0 );
2353 XPutPixel( mask_image
, x
, y
, 1 );
2360 #if 0 // Old, slower code
2363 if (wxTheApp->m_colorCube)
2365 pixel = wxTheApp->m_colorCube
2366 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2371 int max
= 3 * (65536);
2372 for (int i
= 0; i
< 256; i
++)
2374 int rdiff
= (r
<< 8) - colors
[i
].red
;
2375 int gdiff
= (g
<< 8) - colors
[i
].green
;
2376 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2377 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2378 if (sum
< max
) { pixel
= i
; max
= sum
; }
2385 // And this is all to get the 'right' color...
2386 int pixel
= scolor
.SearchColor( r
, g
, b
);
2387 XPutPixel( data_image
, x
, y
, pixel
);
2392 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2393 XPutPixel( data_image
, x
, y
, pixel
);
2398 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2399 XPutPixel( data_image
, x
, y
, pixel
);
2408 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2409 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2410 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2411 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2412 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2413 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2415 XPutPixel( data_image
, x
, y
, pixel
);
2425 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2426 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2427 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2429 XDestroyImage( data_image
);
2435 wxBitmap
maskBitmap(width
, height
, 1);
2437 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2438 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2440 XDestroyImage( mask_image
);
2441 XFreeGC( dpy
, gcMask
);
2443 wxMask
* mask
= new wxMask
;
2444 mask
->SetPixmap(maskBitmap
.GetPixmap());
2446 bitmap
.SetMask(mask
);
2448 maskBitmap
.SetPixmapNull();
2454 wxImage::wxImage( const wxBitmap
&bitmap
)
2456 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2458 Display
*dpy
= (Display
*) wxGetDisplay();
2459 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2460 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2462 XImage
*ximage
= XGetImage( dpy
,
2463 (Drawable
)bitmap
.GetPixmap(),
2465 bitmap
.GetWidth(), bitmap
.GetHeight(),
2466 AllPlanes
, ZPixmap
);
2468 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2470 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2471 char unsigned *data
= GetData();
2475 XDestroyImage( ximage
);
2476 wxFAIL_MSG( wxT("couldn't create image") );
2481 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2482 if (bitmap.GetMask())
2484 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2486 bitmap.GetWidth(), bitmap.GetHeight() );
2488 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2492 // Retrieve depth info
2494 XVisualInfo vinfo_template
;
2497 vinfo_template
.visual
= vis
;
2498 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2499 vinfo_template
.depth
= bpp
;
2502 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2504 wxCHECK_RET( vi
, wxT("no visual") );
2506 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2513 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2515 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2516 XQueryColors( dpy
, cmap
, colors
, 256 );
2520 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2522 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2524 int pixel
= XGetPixel( ximage
, i
, j
);
2527 data
[pos
] = colors
[pixel
].red
>> 8;
2528 data
[pos
+1] = colors
[pixel
].green
>> 8;
2529 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2530 } else if (bpp
== 15)
2532 data
[pos
] = (pixel
>> 7) & 0xf8;
2533 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2534 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2535 } else if (bpp
== 16)
2537 data
[pos
] = (pixel
>> 8) & 0xf8;
2538 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2539 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2542 data
[pos
] = (pixel
>> 16) & 0xff;
2543 data
[pos
+1] = (pixel
>> 8) & 0xff;
2544 data
[pos
+2] = pixel
& 0xff;
2550 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2551 if (mask_pixel == 0)
2564 XDestroyImage( ximage
);
2566 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2572 // OS/2 Presentation manager conversion routings
2574 wxBitmap
wxImage::ConvertToBitmap() const
2577 return wxNullBitmap
;
2578 wxBitmap bitmap
; // remove
2581 int sizeLimit = 1024*768*3;
2583 // width and height of the device-dependent bitmap
2584 int width = GetWidth();
2585 int bmpHeight = GetHeight();
2587 // calc the number of bytes per scanline and padding
2588 int bytePerLine = width*3;
2589 int sizeDWORD = sizeof( DWORD );
2590 int lineBoundary = bytePerLine % sizeDWORD;
2592 if( lineBoundary > 0 )
2594 padding = sizeDWORD - lineBoundary;
2595 bytePerLine += padding;
2597 // calc the number of DIBs and heights of DIBs
2600 int height = sizeLimit/bytePerLine;
2601 if( height >= bmpHeight )
2605 numDIB = bmpHeight / height;
2606 hRemain = bmpHeight % height;
2607 if( hRemain >0 ) numDIB++;
2610 // set bitmap parameters
2612 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2613 bitmap.SetWidth( width );
2614 bitmap.SetHeight( bmpHeight );
2615 bitmap.SetDepth( wxDisplayDepth() );
2617 // create a DIB header
2618 int headersize = sizeof(BITMAPINFOHEADER);
2619 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2620 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2621 // Fill in the DIB header
2622 lpDIBh->bmiHeader.biSize = headersize;
2623 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2624 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2625 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2626 // the general formula for biSizeImage:
2627 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2628 lpDIBh->bmiHeader.biPlanes = 1;
2629 lpDIBh->bmiHeader.biBitCount = 24;
2630 lpDIBh->bmiHeader.biCompression = BI_RGB;
2631 lpDIBh->bmiHeader.biClrUsed = 0;
2632 // These seem not really needed for our purpose here.
2633 lpDIBh->bmiHeader.biClrImportant = 0;
2634 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2635 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2636 // memory for DIB data
2637 unsigned char *lpBits;
2638 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2641 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2646 // create and set the device-dependent bitmap
2647 HDC hdc = ::GetDC(NULL);
2648 HDC memdc = ::CreateCompatibleDC( hdc );
2650 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2651 ::SelectObject( memdc, hbitmap);
2653 // copy image data into DIB data and then into DDB (in a loop)
2654 unsigned char *data = GetData();
2657 unsigned char *ptdata = data;
2658 unsigned char *ptbits;
2660 for( n=0; n<numDIB; n++ )
2662 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2664 // redefine height and size of the (possibly) last smaller DIB
2665 // memory is not reallocated
2667 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2668 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2672 for( j=0; j<height; j++ )
2674 for( i=0; i<width; i++ )
2676 *(ptbits++) = *(ptdata+2);
2677 *(ptbits++) = *(ptdata+1);
2678 *(ptbits++) = *(ptdata );
2681 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2683 ::StretchDIBits( memdc, 0, origin, width, height,\
2684 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2686 // if numDIB = 1, lines below can also be used
2687 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2688 // The above line is equivalent to the following two lines.
2689 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2690 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2691 // or the following lines
2692 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2693 // HDC memdc = ::CreateCompatibleDC( hdc );
2694 // ::SelectObject( memdc, hbitmap);
2695 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2696 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2697 // ::SelectObject( memdc, 0 );
2698 // ::DeleteDC( memdc );
2700 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2702 // similarly, created an mono-bitmap for the possible mask
2705 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2706 ::SelectObject( memdc, hbitmap);
2707 if( numDIB == 1 ) height = bmpHeight;
2708 else height = sizeLimit/bytePerLine;
2709 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2710 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2712 unsigned char r = GetMaskRed();
2713 unsigned char g = GetMaskGreen();
2714 unsigned char b = GetMaskBlue();
2715 unsigned char zero = 0, one = 255;
2717 for( n=0; n<numDIB; n++ )
2719 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2721 // redefine height and size of the (possibly) last smaller DIB
2722 // memory is not reallocated
2724 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2725 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2728 for( int j=0; j<height; j++ )
2730 for(i=0; i<width; i++ )
2732 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2745 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2747 ::StretchDIBits( memdc, 0, origin, width, height,\
2748 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2751 // create a wxMask object
2752 wxMask *mask = new wxMask();
2753 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2754 bitmap.SetMask( mask );
2757 // free allocated resources
2758 ::SelectObject( memdc, 0 );
2759 ::DeleteDC( memdc );
2760 ::ReleaseDC(NULL, hdc);
2764 // check the wxBitmap object
2765 if( bitmap.GetHBITMAP() )
2766 bitmap.SetOk( TRUE );
2768 bitmap.SetOk( FALSE );
2773 wxImage::wxImage( const wxBitmap
&bitmap
)
2778 wxFAIL_MSG( wxT("invalid bitmap") );
2782 // create an wxImage object
2783 int width
= bitmap
.GetWidth();
2784 int height
= bitmap
.GetHeight();
2785 Create( width
, height
);
2786 unsigned char *data
= GetData();
2789 wxFAIL_MSG( wxT("could not allocate data for image") );
2793 // calc the number of bytes per scanline and padding in the DIB
2794 int bytePerLine
= width
*3;
2795 int sizeDWORD
= sizeof( DWORD
);
2796 int lineBoundary
= bytePerLine
% sizeDWORD
;
2798 if( lineBoundary
> 0 )
2800 padding
= sizeDWORD
- lineBoundary
;
2801 bytePerLine
+= padding
;
2805 // create a DIB header
2806 int headersize = sizeof(BITMAPINFOHEADER);
2807 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2810 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2814 // Fill in the DIB header
2815 lpDIBh->bmiHeader.biSize = headersize;
2816 lpDIBh->bmiHeader.biWidth = width;
2817 lpDIBh->bmiHeader.biHeight = -height;
2818 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2819 lpDIBh->bmiHeader.biPlanes = 1;
2820 lpDIBh->bmiHeader.biBitCount = 24;
2821 lpDIBh->bmiHeader.biCompression = BI_RGB;
2822 lpDIBh->bmiHeader.biClrUsed = 0;
2823 // These seem not really needed for our purpose here.
2824 lpDIBh->bmiHeader.biClrImportant = 0;
2825 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2826 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2827 // memory for DIB data
2828 unsigned char *lpBits;
2829 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2832 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2838 // copy data from the device-dependent bitmap to the DIB
2839 HDC hdc = ::GetDC(NULL);
2841 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2842 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2844 // copy DIB data into the wxImage object
2846 unsigned char *ptdata = data;
2847 unsigned char *ptbits = lpBits;
2848 for( i=0; i<height; i++ )
2850 for( j=0; j<width; j++ )
2852 *(ptdata++) = *(ptbits+2);
2853 *(ptdata++) = *(ptbits+1);
2854 *(ptdata++) = *(ptbits );
2860 // similarly, set data according to the possible mask bitmap
2861 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2863 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2864 // memory DC created, color set, data copied, and memory DC deleted
2865 HDC memdc = ::CreateCompatibleDC( hdc );
2866 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2867 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2868 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2869 ::DeleteDC( memdc );
2870 // background color set to RGB(16,16,16) in consistent with wxGTK
2871 unsigned char r=16, g=16, b=16;
2874 for( i=0; i<height; i++ )
2876 for( j=0; j<width; j++ )
2890 SetMaskColour( r, g, b );
2897 // free allocated resources
2898 ::ReleaseDC(NULL, hdc);
2906 // A module to allow wxImage initialization/cleanup
2907 // without calling these functions from app.cpp or from
2908 // the user's application.
2910 class wxImageModule
: public wxModule
2912 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2915 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2916 void OnExit() { wxImage::CleanUpHandlers(); };
2919 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2922 //-----------------------------------------------------------------------------
2925 // Counts and returns the number of different colours. Optionally stops
2926 // when it exceeds 'stopafter' different colours. This is useful, for
2927 // example, to see if the image can be saved as 8-bit (256 colour or
2928 // less, in this case it would be invoked as CountColours(256)). Default
2929 // value for stopafter is -1 (don't care).
2931 unsigned long wxImage::CountColours( unsigned long stopafter
)
2935 unsigned char r
, g
, b
, *p
;
2936 unsigned long size
, nentries
, key
;
2939 size
= GetWidth() * GetHeight();
2942 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2947 key
= (r
<< 16) | (g
<< 8) | b
;
2949 if (h
.Get(key
) == NULL
)
2961 // Computes the histogram of the image and fills a hash table, indexed
2962 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2963 // wxHNode contains an 'index' (useful to build a palette with the image
2964 // colours) and a 'value', which is the number of pixels in the image with
2967 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2969 unsigned char r
, g
, b
, *p
;
2970 unsigned long size
, nentries
, key
;
2974 size
= GetWidth() * GetHeight();
2977 for (unsigned long j
= 0; j
< size
; j
++)
2982 key
= (r
<< 16) | (g
<< 8) | b
;
2984 hnode
= (wxHNode
*) h
.Get(key
);
2990 hnode
= new wxHNode();
2991 hnode
->index
= nentries
++;
2994 h
.Put(key
, (wxObject
*)hnode
);
3002 * Rotation code by Carlos Moreno
3005 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
3006 // does exactly the same thing. And I also got rid of wxRotationPixel
3007 // bacause of potential problems in architectures where alignment
3008 // is an issue, so I had to rewrite parts of the code.
3010 static const double gs_Epsilon
= 1e-10;
3012 static inline int wxCint (double x
)
3014 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
3018 // Auxiliary function to rotate a point (x,y) with respect to point p0
3019 // make it inline and use a straight return to facilitate optimization
3020 // also, the function receives the sine and cosine of the angle to avoid
3021 // repeating the time-consuming calls to these functions -- sin/cos can
3022 // be computed and stored in the calling function.
3024 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
3026 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
3027 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
3030 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
3032 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
3035 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
3038 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
3040 // Create pointer-based array to accelerate access to wxImage's data
3041 unsigned char ** data
= new unsigned char * [GetHeight()];
3043 data
[0] = GetData();
3045 for (i
= 1; i
< GetHeight(); i
++)
3046 data
[i
] = data
[i
- 1] + (3 * GetWidth());
3048 // precompute coefficients for rotation formula
3049 // (sine and cosine of the angle)
3050 const double cos_angle
= cos(angle
);
3051 const double sin_angle
= sin(angle
);
3053 // Create new Image to store the result
3054 // First, find rectangle that covers the rotated image; to do that,
3055 // rotate the four corners
3057 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
3059 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
3060 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
3061 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
3062 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
3064 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
3065 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
3066 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
3067 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
3069 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
3071 if (offset_after_rotation
!= NULL
)
3073 *offset_after_rotation
= wxPoint (x1
, y1
);
3076 // GRG: The rotated (destination) image is always accessed
3077 // sequentially, so there is no need for a pointer-based
3078 // array here (and in fact it would be slower).
3080 unsigned char * dst
= rotated
.GetData();
3082 // GRG: if the original image has a mask, use its RGB values
3083 // as the blank pixel, else, fall back to default (black).
3085 unsigned char blank_r
= 0;
3086 unsigned char blank_g
= 0;
3087 unsigned char blank_b
= 0;
3091 blank_r
= GetMaskRed();
3092 blank_g
= GetMaskGreen();
3093 blank_b
= GetMaskBlue();
3094 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
3097 // Now, for each point of the rotated image, find where it came from, by
3098 // performing an inverse rotation (a rotation of -angle) and getting the
3099 // pixel at those coordinates
3101 // GRG: I've taken the (interpolating) test out of the loops, so that
3102 // it is done only once, instead of repeating it for each pixel.
3107 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3109 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3111 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3113 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
3114 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
3116 // interpolate using the 4 enclosing grid-points. Those
3117 // points can be obtained using floor and ceiling of the
3118 // exact coordinates of the point
3119 // C.M. 2000-02-17: when the point is near the border, special care is required.
3123 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
3125 x1
= wxCint(floor(src
.x
));
3126 x2
= wxCint(ceil(src
.x
));
3128 else // else means that x is near one of the borders (0 or width-1)
3130 x1
= x2
= wxCint (src
.x
);
3133 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
3135 y1
= wxCint(floor(src
.y
));
3136 y2
= wxCint(ceil(src
.y
));
3140 y1
= y2
= wxCint (src
.y
);
3143 // get four points and the distances (square of the distance,
3144 // for efficiency reasons) for the interpolation formula
3146 // GRG: Do not calculate the points until they are
3147 // really needed -- this way we can calculate
3148 // just one, instead of four, if d1, d2, d3
3149 // or d4 are < gs_Epsilon
3151 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
3152 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
3153 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
3154 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
3156 // Now interpolate as a weighted average of the four surrounding
3157 // points, where the weights are the distances to each of those points
3159 // If the point is exactly at one point of the grid of the source
3160 // image, then don't interpolate -- just assign the pixel
3162 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
3164 unsigned char *p
= data
[y1
] + (3 * x1
);
3169 else if (d2
< gs_Epsilon
)
3171 unsigned char *p
= data
[y1
] + (3 * x2
);
3176 else if (d3
< gs_Epsilon
)
3178 unsigned char *p
= data
[y2
] + (3 * x2
);
3183 else if (d4
< gs_Epsilon
)
3185 unsigned char *p
= data
[y2
] + (3 * x1
);
3192 // weights for the weighted average are proportional to the inverse of the distance
3193 unsigned char *v1
= data
[y1
] + (3 * x1
);
3194 unsigned char *v2
= data
[y1
] + (3 * x2
);
3195 unsigned char *v3
= data
[y2
] + (3 * x2
);
3196 unsigned char *v4
= data
[y2
] + (3 * x1
);
3198 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
3202 *(dst
++) = (unsigned char)
3203 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3204 w3
* *(v3
++) + w4
* *(v4
++)) /
3205 (w1
+ w2
+ w3
+ w4
) );
3206 *(dst
++) = (unsigned char)
3207 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3208 w3
* *(v3
++) + w4
* *(v4
++)) /
3209 (w1
+ w2
+ w3
+ w4
) );
3210 *(dst
++) = (unsigned char)
3211 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3212 w3
* *(v3
++) + w4
* *(v4
++)) /
3213 (w1
+ w2
+ w3
+ w4
) );
3225 else // not interpolating
3227 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3229 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3231 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3233 const int xs
= wxCint (src
.x
); // wxCint rounds to the
3234 const int ys
= wxCint (src
.y
); // closest integer
3236 if (0 <= xs
&& xs
< GetWidth() &&
3237 0 <= ys
&& ys
< GetHeight())
3239 unsigned char *p
= data
[ys
] + (3 * xs
);