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
);
1402 #include <QD/PictUtils.h>
1404 #include <PictUtils.h>
1407 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1408 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1409 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1410 extern GWorldPtr
wxMacCreateGWorld( int width
, int height
, int depth
) ;
1411 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1413 wxBitmap
wxImage::ConvertToBitmap() const
1415 // width and height of the device-dependent bitmap
1416 int width
= GetWidth();
1417 int height
= GetHeight();
1421 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1428 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1430 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1432 wxMask *mask = new wxMask();
1433 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1435 bitmap.SetMask( mask );
1441 int r_mask
= GetMaskRed();
1442 int g_mask
= GetMaskGreen();
1443 int b_mask
= GetMaskBlue();
1446 GDHandle origDevice
;
1448 GetGWorld( &origPort
, &origDevice
) ;
1449 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1451 register unsigned char* data
= GetData();
1454 for (int y
= 0; y
< height
; y
++)
1456 for (int x
= 0; x
< width
; x
++)
1458 unsigned char r
= data
[index
++];
1459 unsigned char g
= data
[index
++];
1460 unsigned char b
= data
[index
++];
1462 color
.red
= ( r
<< 8 ) + r
;
1463 color
.green
= ( g
<< 8 ) + g
;
1464 color
.blue
= ( b
<< 8 ) + b
;
1465 SetCPixel( x
, y
, &color
) ;
1469 SetGWorld( origPort
, origDevice
) ;
1473 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1474 wxMask
*mask
= new wxMask( bitmap
, colour
);
1475 bitmap
.SetMask( mask
);
1481 wxImage::wxImage( const wxBitmap
&bitmap
)
1486 wxFAIL_MSG( "invalid bitmap" );
1490 // create an wxImage object
1491 int width
= bitmap
.GetWidth();
1492 int height
= bitmap
.GetHeight();
1493 Create( width
, height
);
1495 unsigned char *data = GetData();
1498 wxFAIL_MSG( "could not allocate data for image" );
1502 // calc the number of bytes per scanline and padding in the DIB
1503 int bytePerLine = width*3;
1504 int sizeDWORD = sizeof( DWORD );
1505 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1507 if( lineBoundary.rem > 0 )
1509 padding = sizeDWORD - lineBoundary.rem;
1510 bytePerLine += padding;
1513 // create a DIB header
1514 int headersize = sizeof(BITMAPINFOHEADER);
1515 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1518 wxFAIL_MSG( "could not allocate data for DIB header" );
1522 // Fill in the DIB header
1523 lpDIBh->bmiHeader.biSize = headersize;
1524 lpDIBh->bmiHeader.biWidth = width;
1525 lpDIBh->bmiHeader.biHeight = -height;
1526 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1527 lpDIBh->bmiHeader.biPlanes = 1;
1528 lpDIBh->bmiHeader.biBitCount = 24;
1529 lpDIBh->bmiHeader.biCompression = BI_RGB;
1530 lpDIBh->bmiHeader.biClrUsed = 0;
1531 // These seem not really needed for our purpose here.
1532 lpDIBh->bmiHeader.biClrImportant = 0;
1533 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1534 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1535 // memory for DIB data
1536 unsigned char *lpBits;
1537 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1540 wxFAIL_MSG( "could not allocate data for DIB" );
1546 // copy data from the device-dependent bitmap to the DIB
1547 HDC hdc = ::GetDC(NULL);
1549 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1550 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1552 // copy DIB data into the wxImage object
1554 unsigned char *ptdata = data;
1555 unsigned char *ptbits = lpBits;
1556 for( i=0; i<height; i++ )
1558 for( j=0; j<width; j++ )
1560 *(ptdata++) = *(ptbits+2);
1561 *(ptdata++) = *(ptbits+1);
1562 *(ptdata++) = *(ptbits );
1568 // similarly, set data according to the possible mask bitmap
1569 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1571 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1572 // memory DC created, color set, data copied, and memory DC deleted
1573 HDC memdc = ::CreateCompatibleDC( hdc );
1574 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1575 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1576 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1577 ::DeleteDC( memdc );
1578 // background color set to RGB(16,16,16) in consistent with wxGTK
1579 unsigned char r=16, g=16, b=16;
1582 for( i=0; i<height; i++ )
1584 for( j=0; j<width; j++ )
1598 SetMaskColour( r, g, b );
1605 // free allocated resources
1606 ::ReleaseDC(NULL, hdc);
1614 //-----------------------------------------------------------------------------
1615 // GTK conversion routines
1616 //-----------------------------------------------------------------------------
1620 #include <gtk/gtk.h>
1621 #include <gdk/gdk.h>
1622 #include <gdk/gdkx.h>
1624 #if (GTK_MINOR_VERSION > 0)
1625 #include <gdk/gdkrgb.h>
1628 extern GtkWidget
*wxRootWindow
;
1630 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1634 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1636 int width
= GetWidth();
1637 int height
= GetHeight();
1639 bitmap
.SetHeight( height
);
1640 bitmap
.SetWidth( width
);
1642 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1644 bitmap
.SetDepth( 1 );
1646 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1649 // Create picture image
1651 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1653 GdkImage
*data_image
=
1654 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1656 // Create mask image
1658 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1662 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1664 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1666 wxMask
*mask
= new wxMask();
1667 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1669 bitmap
.SetMask( mask
);
1672 int r_mask
= GetMaskRed();
1673 int g_mask
= GetMaskGreen();
1674 int b_mask
= GetMaskBlue();
1676 unsigned char* data
= GetData();
1679 for (int y
= 0; y
< height
; y
++)
1681 for (int x
= 0; x
< width
; x
++)
1683 int r
= data
[index
];
1685 int g
= data
[index
];
1687 int b
= data
[index
];
1692 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1693 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1695 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1698 if ((r
== red
) && (b
== blue
) && (g
== green
))
1699 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1701 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1708 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1710 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1712 gdk_image_destroy( data_image
);
1713 gdk_gc_unref( data_gc
);
1719 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1721 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1723 gdk_image_destroy( mask_image
);
1724 gdk_gc_unref( mask_gc
);
1731 wxBitmap
wxImage::ConvertToBitmap() const
1735 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1737 int width
= GetWidth();
1738 int height
= GetHeight();
1740 bitmap
.SetHeight( height
);
1741 bitmap
.SetWidth( width
);
1743 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1747 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1750 int bpp
= visual
->depth
;
1752 bitmap
.SetDepth( bpp
);
1754 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1755 if (bpp
< 8) bpp
= 8;
1757 #if (GTK_MINOR_VERSION > 0)
1759 if (!HasMask() && (bpp
> 8))
1761 static bool s_hasInitialized
= FALSE
;
1763 if (!s_hasInitialized
)
1766 s_hasInitialized
= TRUE
;
1769 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1771 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1775 GDK_RGB_DITHER_NONE
,
1786 // Create picture image
1788 GdkImage
*data_image
=
1789 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1791 // Create mask image
1793 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1797 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1799 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1801 wxMask
*mask
= new wxMask();
1802 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1804 bitmap
.SetMask( mask
);
1809 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1810 byte_order b_o
= RGB
;
1814 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1815 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1816 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1817 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1818 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1819 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1822 int r_mask
= GetMaskRed();
1823 int g_mask
= GetMaskGreen();
1824 int b_mask
= GetMaskBlue();
1826 unsigned char* data
= GetData();
1829 for (int y
= 0; y
< height
; y
++)
1831 for (int x
= 0; x
< width
; x
++)
1833 int r
= data
[index
];
1835 int g
= data
[index
];
1837 int b
= data
[index
];
1842 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1843 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1845 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1853 if (wxTheApp
->m_colorCube
)
1855 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1859 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1860 GdkColor
*colors
= cmap
->colors
;
1861 int max
= 3 * (65536);
1863 for (int i
= 0; i
< cmap
->size
; i
++)
1865 int rdiff
= (r
<< 8) - colors
[i
].red
;
1866 int gdiff
= (g
<< 8) - colors
[i
].green
;
1867 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1868 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1869 if (sum
< max
) { pixel
= i
; max
= sum
; }
1873 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1879 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1880 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1885 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1886 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1895 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1896 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1897 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1898 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1899 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1900 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1902 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1911 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1913 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1915 gdk_image_destroy( data_image
);
1916 gdk_gc_unref( data_gc
);
1922 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1924 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1926 gdk_image_destroy( mask_image
);
1927 gdk_gc_unref( mask_gc
);
1933 wxImage::wxImage( const wxBitmap
&bitmap
)
1935 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1937 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1938 if (bitmap
.GetPixmap())
1940 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1942 bitmap
.GetWidth(), bitmap
.GetHeight() );
1944 if (bitmap
.GetBitmap())
1946 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1948 bitmap
.GetWidth(), bitmap
.GetHeight() );
1951 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1954 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1956 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1957 char unsigned *data
= GetData();
1961 gdk_image_destroy( gdk_image
);
1962 wxFAIL_MSG( wxT("couldn't create image") );
1966 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1967 if (bitmap
.GetMask())
1969 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1971 bitmap
.GetWidth(), bitmap
.GetHeight() );
1973 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1977 int red_shift_right
= 0;
1978 int green_shift_right
= 0;
1979 int blue_shift_right
= 0;
1980 int red_shift_left
= 0;
1981 int green_shift_left
= 0;
1982 int blue_shift_left
= 0;
1983 bool use_shift
= FALSE
;
1985 if (bitmap
.GetPixmap())
1987 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1989 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1990 bpp
= visual
->depth
;
1991 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1992 red_shift_right
= visual
->red_shift
;
1993 red_shift_left
= 8-visual
->red_prec
;
1994 green_shift_right
= visual
->green_shift
;
1995 green_shift_left
= 8-visual
->green_prec
;
1996 blue_shift_right
= visual
->blue_shift
;
1997 blue_shift_left
= 8-visual
->blue_prec
;
1999 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
2001 if (bitmap
.GetBitmap())
2007 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
2010 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2012 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2014 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
2032 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
2033 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
2034 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
2036 else if (cmap
->colors
)
2038 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
2039 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
2040 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
2044 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
2049 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
2050 if (mask_pixel
== 0)
2062 gdk_image_destroy( gdk_image
);
2063 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
2068 //-----------------------------------------------------------------------------
2069 // Motif conversion routines
2070 //-----------------------------------------------------------------------------
2074 #pragma message disable nosimpint
2078 #pragma message enable nosimpint
2080 #include "wx/utils.h"
2085 Date: Wed, 05 Jan 2000 11:45:40 +0100
2086 From: Frits Boel <boel@niob.knaw.nl>
2087 To: julian.smart@ukonline.co.uk
2088 Subject: Patch for Motif ConvertToBitmap
2092 I've been working on a wxWin application for image processing. From the
2093 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
2094 till I looked in the source code of image.cpp. I saw that converting a
2095 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
2096 to the 256 colors of the palet. A very time-consuming piece of code!
2098 Because I wanted a faster application, I've made a 'patch' for this. In
2099 short: every pixel of the image is compared to a sorted list with
2100 colors. If the color is found in the list, the palette entry is
2101 returned; if the color is not found, the color palette is searched and
2102 then the palette entry is returned and the color added to the sorted
2105 Maybe there is another method for this, namely changing the palette
2106 itself (if the colors are known, as is the case with tiffs with a
2107 colormap). I did not look at this, maybe someone else did?
2109 The code of the patch is attached, have a look on it, and maybe you will
2110 ship it with the next release of wxMotif?
2115 Software engineer at Hubrecht Laboratory, The Netherlands.
2122 wxSearchColor( void );
2123 wxSearchColor( int size
, XColor
*colors
);
2124 ~wxSearchColor( void );
2126 int SearchColor( int r
, int g
, int b
);
2128 int AddColor( unsigned int value
, int pos
);
2132 unsigned int *color
;
2139 wxSearchColor::wxSearchColor( void )
2142 colors
= (XColor
*) NULL
;
2143 color
= (unsigned int *) NULL
;
2144 entry
= (int*) NULL
;
2150 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
2155 color
= new unsigned int[size
];
2156 entry
= new int [size
];
2158 for (i
= 0; i
< size
; i
++ ) {
2162 bottom
= top
= ( size
>> 1 );
2165 wxSearchColor::~wxSearchColor( void )
2167 if ( color
) delete color
;
2168 if ( entry
) delete entry
;
2171 int wxSearchColor::SearchColor( int r
, int g
, int b
)
2173 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
2178 while ( begin
<= end
) {
2180 middle
= ( begin
+ end
) >> 1;
2182 if ( value
== color
[middle
] ) {
2183 return( entry
[middle
] );
2184 } else if ( value
< color
[middle
] ) {
2192 return AddColor( value
, middle
);
2195 int wxSearchColor::AddColor( unsigned int value
, int pos
)
2199 int max
= 3 * (65536);
2200 for ( i
= 0; i
< 256; i
++ ) {
2201 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
2202 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
2203 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
2204 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2205 if (sum
< max
) { pixel
= i
; max
= sum
; }
2208 if ( entry
[pos
] < 0 ) {
2211 } else if ( value
< color
[pos
] ) {
2214 for ( i
= bottom
; i
< pos
; i
++ ) {
2215 color
[i
-1] = color
[i
];
2216 entry
[i
-1] = entry
[i
];
2219 color
[pos
-1] = value
;
2220 entry
[pos
-1] = pixel
;
2221 } else if ( top
< size
-1 ) {
2222 for ( i
= top
; i
>= pos
; i
-- ) {
2223 color
[i
+1] = color
[i
];
2224 entry
[i
+1] = entry
[i
];
2233 if ( top
< size
-1 ) {
2234 for ( i
= top
; i
> pos
; i
-- ) {
2235 color
[i
+1] = color
[i
];
2236 entry
[i
+1] = entry
[i
];
2239 color
[pos
+1] = value
;
2240 entry
[pos
+1] = pixel
;
2241 } else if ( bottom
> 0 ) {
2242 for ( i
= bottom
; i
< pos
; i
++ ) {
2243 color
[i
-1] = color
[i
];
2244 entry
[i
-1] = entry
[i
];
2256 wxBitmap
wxImage::ConvertToBitmap() const
2260 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
2262 int width
= GetWidth();
2263 int height
= GetHeight();
2265 bitmap
.SetHeight( height
);
2266 bitmap
.SetWidth( width
);
2268 Display
*dpy
= (Display
*) wxGetDisplay();
2269 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2270 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2274 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2275 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
2277 bitmap
.Create( width
, height
, bpp
);
2281 XImage
*mask_image
= (XImage
*) NULL
;
2284 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2285 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
2288 // Retrieve depth info
2290 XVisualInfo vinfo_template
;
2293 vinfo_template
.visual
= vis
;
2294 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2295 vinfo_template
.depth
= bpp
;
2298 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2300 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
2304 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2305 if (bpp
< 8) bpp
= 8;
2309 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
2310 byte_order b_o
= RGB
;
2314 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2315 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2316 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2317 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2318 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2319 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2322 int r_mask
= GetMaskRed();
2323 int g_mask
= GetMaskGreen();
2324 int b_mask
= GetMaskBlue();
2329 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2331 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2332 XQueryColors( dpy
, cmap
, colors
, 256 );
2335 wxSearchColor
scolor( 256, colors
);
2336 unsigned char* data
= GetData();
2338 bool hasMask
= HasMask();
2341 for (int y
= 0; y
< height
; y
++)
2343 for (int x
= 0; x
< width
; x
++)
2345 int r
= data
[index
];
2347 int g
= data
[index
];
2349 int b
= data
[index
];
2354 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2355 XPutPixel( mask_image
, x
, y
, 0 );
2357 XPutPixel( mask_image
, x
, y
, 1 );
2364 #if 0 // Old, slower code
2367 if (wxTheApp->m_colorCube)
2369 pixel = wxTheApp->m_colorCube
2370 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2375 int max
= 3 * (65536);
2376 for (int i
= 0; i
< 256; i
++)
2378 int rdiff
= (r
<< 8) - colors
[i
].red
;
2379 int gdiff
= (g
<< 8) - colors
[i
].green
;
2380 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2381 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2382 if (sum
< max
) { pixel
= i
; max
= sum
; }
2389 // And this is all to get the 'right' color...
2390 int pixel
= scolor
.SearchColor( r
, g
, b
);
2391 XPutPixel( data_image
, x
, y
, pixel
);
2396 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2397 XPutPixel( data_image
, x
, y
, pixel
);
2402 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2403 XPutPixel( data_image
, x
, y
, pixel
);
2412 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2413 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2414 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2415 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2416 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2417 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2419 XPutPixel( data_image
, x
, y
, pixel
);
2429 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2430 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2431 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2433 XDestroyImage( data_image
);
2439 wxBitmap
maskBitmap(width
, height
, 1);
2441 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2442 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2444 XDestroyImage( mask_image
);
2445 XFreeGC( dpy
, gcMask
);
2447 wxMask
* mask
= new wxMask
;
2448 mask
->SetPixmap(maskBitmap
.GetPixmap());
2450 bitmap
.SetMask(mask
);
2452 maskBitmap
.SetPixmapNull();
2458 wxImage::wxImage( const wxBitmap
&bitmap
)
2460 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2462 Display
*dpy
= (Display
*) wxGetDisplay();
2463 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2464 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2466 XImage
*ximage
= XGetImage( dpy
,
2467 (Drawable
)bitmap
.GetPixmap(),
2469 bitmap
.GetWidth(), bitmap
.GetHeight(),
2470 AllPlanes
, ZPixmap
);
2472 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2474 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2475 char unsigned *data
= GetData();
2479 XDestroyImage( ximage
);
2480 wxFAIL_MSG( wxT("couldn't create image") );
2485 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2486 if (bitmap.GetMask())
2488 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2490 bitmap.GetWidth(), bitmap.GetHeight() );
2492 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2496 // Retrieve depth info
2498 XVisualInfo vinfo_template
;
2501 vinfo_template
.visual
= vis
;
2502 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2503 vinfo_template
.depth
= bpp
;
2506 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2508 wxCHECK_RET( vi
, wxT("no visual") );
2510 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2517 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2519 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2520 XQueryColors( dpy
, cmap
, colors
, 256 );
2524 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2526 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2528 int pixel
= XGetPixel( ximage
, i
, j
);
2531 data
[pos
] = colors
[pixel
].red
>> 8;
2532 data
[pos
+1] = colors
[pixel
].green
>> 8;
2533 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2534 } else if (bpp
== 15)
2536 data
[pos
] = (pixel
>> 7) & 0xf8;
2537 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2538 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2539 } else if (bpp
== 16)
2541 data
[pos
] = (pixel
>> 8) & 0xf8;
2542 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2543 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2546 data
[pos
] = (pixel
>> 16) & 0xff;
2547 data
[pos
+1] = (pixel
>> 8) & 0xff;
2548 data
[pos
+2] = pixel
& 0xff;
2554 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2555 if (mask_pixel == 0)
2568 XDestroyImage( ximage
);
2570 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2576 // OS/2 Presentation manager conversion routings
2578 wxBitmap
wxImage::ConvertToBitmap() const
2581 return wxNullBitmap
;
2582 wxBitmap bitmap
; // remove
2585 int sizeLimit = 1024*768*3;
2587 // width and height of the device-dependent bitmap
2588 int width = GetWidth();
2589 int bmpHeight = GetHeight();
2591 // calc the number of bytes per scanline and padding
2592 int bytePerLine = width*3;
2593 int sizeDWORD = sizeof( DWORD );
2594 int lineBoundary = bytePerLine % sizeDWORD;
2596 if( lineBoundary > 0 )
2598 padding = sizeDWORD - lineBoundary;
2599 bytePerLine += padding;
2601 // calc the number of DIBs and heights of DIBs
2604 int height = sizeLimit/bytePerLine;
2605 if( height >= bmpHeight )
2609 numDIB = bmpHeight / height;
2610 hRemain = bmpHeight % height;
2611 if( hRemain >0 ) numDIB++;
2614 // set bitmap parameters
2616 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2617 bitmap.SetWidth( width );
2618 bitmap.SetHeight( bmpHeight );
2619 bitmap.SetDepth( wxDisplayDepth() );
2621 // create a DIB header
2622 int headersize = sizeof(BITMAPINFOHEADER);
2623 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2624 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2625 // Fill in the DIB header
2626 lpDIBh->bmiHeader.biSize = headersize;
2627 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2628 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2629 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2630 // the general formula for biSizeImage:
2631 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2632 lpDIBh->bmiHeader.biPlanes = 1;
2633 lpDIBh->bmiHeader.biBitCount = 24;
2634 lpDIBh->bmiHeader.biCompression = BI_RGB;
2635 lpDIBh->bmiHeader.biClrUsed = 0;
2636 // These seem not really needed for our purpose here.
2637 lpDIBh->bmiHeader.biClrImportant = 0;
2638 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2639 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2640 // memory for DIB data
2641 unsigned char *lpBits;
2642 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2645 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2650 // create and set the device-dependent bitmap
2651 HDC hdc = ::GetDC(NULL);
2652 HDC memdc = ::CreateCompatibleDC( hdc );
2654 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2655 ::SelectObject( memdc, hbitmap);
2657 // copy image data into DIB data and then into DDB (in a loop)
2658 unsigned char *data = GetData();
2661 unsigned char *ptdata = data;
2662 unsigned char *ptbits;
2664 for( n=0; n<numDIB; n++ )
2666 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2668 // redefine height and size of the (possibly) last smaller DIB
2669 // memory is not reallocated
2671 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2672 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2676 for( j=0; j<height; j++ )
2678 for( i=0; i<width; i++ )
2680 *(ptbits++) = *(ptdata+2);
2681 *(ptbits++) = *(ptdata+1);
2682 *(ptbits++) = *(ptdata );
2685 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2687 ::StretchDIBits( memdc, 0, origin, width, height,\
2688 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2690 // if numDIB = 1, lines below can also be used
2691 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2692 // The above line is equivalent to the following two lines.
2693 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2694 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2695 // or the following lines
2696 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2697 // HDC memdc = ::CreateCompatibleDC( hdc );
2698 // ::SelectObject( memdc, hbitmap);
2699 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2700 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2701 // ::SelectObject( memdc, 0 );
2702 // ::DeleteDC( memdc );
2704 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2706 // similarly, created an mono-bitmap for the possible mask
2709 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2710 ::SelectObject( memdc, hbitmap);
2711 if( numDIB == 1 ) height = bmpHeight;
2712 else height = sizeLimit/bytePerLine;
2713 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2714 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2716 unsigned char r = GetMaskRed();
2717 unsigned char g = GetMaskGreen();
2718 unsigned char b = GetMaskBlue();
2719 unsigned char zero = 0, one = 255;
2721 for( n=0; n<numDIB; n++ )
2723 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2725 // redefine height and size of the (possibly) last smaller DIB
2726 // memory is not reallocated
2728 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2729 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2732 for( int j=0; j<height; j++ )
2734 for(i=0; i<width; i++ )
2736 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2749 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2751 ::StretchDIBits( memdc, 0, origin, width, height,\
2752 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2755 // create a wxMask object
2756 wxMask *mask = new wxMask();
2757 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2758 bitmap.SetMask( mask );
2761 // free allocated resources
2762 ::SelectObject( memdc, 0 );
2763 ::DeleteDC( memdc );
2764 ::ReleaseDC(NULL, hdc);
2768 // check the wxBitmap object
2769 if( bitmap.GetHBITMAP() )
2770 bitmap.SetOk( TRUE );
2772 bitmap.SetOk( FALSE );
2777 wxImage::wxImage( const wxBitmap
&bitmap
)
2782 wxFAIL_MSG( wxT("invalid bitmap") );
2786 // create an wxImage object
2787 int width
= bitmap
.GetWidth();
2788 int height
= bitmap
.GetHeight();
2789 Create( width
, height
);
2790 unsigned char *data
= GetData();
2793 wxFAIL_MSG( wxT("could not allocate data for image") );
2797 // calc the number of bytes per scanline and padding in the DIB
2798 int bytePerLine
= width
*3;
2799 int sizeDWORD
= sizeof( DWORD
);
2800 int lineBoundary
= bytePerLine
% sizeDWORD
;
2802 if( lineBoundary
> 0 )
2804 padding
= sizeDWORD
- lineBoundary
;
2805 bytePerLine
+= padding
;
2809 // create a DIB header
2810 int headersize = sizeof(BITMAPINFOHEADER);
2811 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2814 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2818 // Fill in the DIB header
2819 lpDIBh->bmiHeader.biSize = headersize;
2820 lpDIBh->bmiHeader.biWidth = width;
2821 lpDIBh->bmiHeader.biHeight = -height;
2822 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2823 lpDIBh->bmiHeader.biPlanes = 1;
2824 lpDIBh->bmiHeader.biBitCount = 24;
2825 lpDIBh->bmiHeader.biCompression = BI_RGB;
2826 lpDIBh->bmiHeader.biClrUsed = 0;
2827 // These seem not really needed for our purpose here.
2828 lpDIBh->bmiHeader.biClrImportant = 0;
2829 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2830 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2831 // memory for DIB data
2832 unsigned char *lpBits;
2833 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2836 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2842 // copy data from the device-dependent bitmap to the DIB
2843 HDC hdc = ::GetDC(NULL);
2845 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2846 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2848 // copy DIB data into the wxImage object
2850 unsigned char *ptdata = data;
2851 unsigned char *ptbits = lpBits;
2852 for( i=0; i<height; i++ )
2854 for( j=0; j<width; j++ )
2856 *(ptdata++) = *(ptbits+2);
2857 *(ptdata++) = *(ptbits+1);
2858 *(ptdata++) = *(ptbits );
2864 // similarly, set data according to the possible mask bitmap
2865 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2867 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2868 // memory DC created, color set, data copied, and memory DC deleted
2869 HDC memdc = ::CreateCompatibleDC( hdc );
2870 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2871 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2872 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2873 ::DeleteDC( memdc );
2874 // background color set to RGB(16,16,16) in consistent with wxGTK
2875 unsigned char r=16, g=16, b=16;
2878 for( i=0; i<height; i++ )
2880 for( j=0; j<width; j++ )
2894 SetMaskColour( r, g, b );
2901 // free allocated resources
2902 ::ReleaseDC(NULL, hdc);
2910 // A module to allow wxImage initialization/cleanup
2911 // without calling these functions from app.cpp or from
2912 // the user's application.
2914 class wxImageModule
: public wxModule
2916 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2919 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2920 void OnExit() { wxImage::CleanUpHandlers(); };
2923 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2926 //-----------------------------------------------------------------------------
2929 // Counts and returns the number of different colours. Optionally stops
2930 // when it exceeds 'stopafter' different colours. This is useful, for
2931 // example, to see if the image can be saved as 8-bit (256 colour or
2932 // less, in this case it would be invoked as CountColours(256)). Default
2933 // value for stopafter is -1 (don't care).
2935 unsigned long wxImage::CountColours( unsigned long stopafter
)
2939 unsigned char r
, g
, b
, *p
;
2940 unsigned long size
, nentries
, key
;
2943 size
= GetWidth() * GetHeight();
2946 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2951 key
= (r
<< 16) | (g
<< 8) | b
;
2953 if (h
.Get(key
) == NULL
)
2965 // Computes the histogram of the image and fills a hash table, indexed
2966 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2967 // wxHNode contains an 'index' (useful to build a palette with the image
2968 // colours) and a 'value', which is the number of pixels in the image with
2971 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2973 unsigned char r
, g
, b
, *p
;
2974 unsigned long size
, nentries
, key
;
2978 size
= GetWidth() * GetHeight();
2981 for (unsigned long j
= 0; j
< size
; j
++)
2986 key
= (r
<< 16) | (g
<< 8) | b
;
2988 hnode
= (wxHNode
*) h
.Get(key
);
2994 hnode
= new wxHNode();
2995 hnode
->index
= nentries
++;
2998 h
.Put(key
, (wxObject
*)hnode
);
3006 * Rotation code by Carlos Moreno
3009 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
3010 // does exactly the same thing. And I also got rid of wxRotationPixel
3011 // bacause of potential problems in architectures where alignment
3012 // is an issue, so I had to rewrite parts of the code.
3014 static const double gs_Epsilon
= 1e-10;
3016 static inline int wxCint (double x
)
3018 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
3022 // Auxiliary function to rotate a point (x,y) with respect to point p0
3023 // make it inline and use a straight return to facilitate optimization
3024 // also, the function receives the sine and cosine of the angle to avoid
3025 // repeating the time-consuming calls to these functions -- sin/cos can
3026 // be computed and stored in the calling function.
3028 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
3030 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
3031 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
3034 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
3036 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
3039 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
3042 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
3044 // Create pointer-based array to accelerate access to wxImage's data
3045 unsigned char ** data
= new unsigned char * [GetHeight()];
3047 data
[0] = GetData();
3049 for (i
= 1; i
< GetHeight(); i
++)
3050 data
[i
] = data
[i
- 1] + (3 * GetWidth());
3052 // precompute coefficients for rotation formula
3053 // (sine and cosine of the angle)
3054 const double cos_angle
= cos(angle
);
3055 const double sin_angle
= sin(angle
);
3057 // Create new Image to store the result
3058 // First, find rectangle that covers the rotated image; to do that,
3059 // rotate the four corners
3061 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
3063 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
3064 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
3065 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
3066 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
3068 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
3069 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
3070 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
3071 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
3073 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
3075 if (offset_after_rotation
!= NULL
)
3077 *offset_after_rotation
= wxPoint (x1
, y1
);
3080 // GRG: The rotated (destination) image is always accessed
3081 // sequentially, so there is no need for a pointer-based
3082 // array here (and in fact it would be slower).
3084 unsigned char * dst
= rotated
.GetData();
3086 // GRG: if the original image has a mask, use its RGB values
3087 // as the blank pixel, else, fall back to default (black).
3089 unsigned char blank_r
= 0;
3090 unsigned char blank_g
= 0;
3091 unsigned char blank_b
= 0;
3095 blank_r
= GetMaskRed();
3096 blank_g
= GetMaskGreen();
3097 blank_b
= GetMaskBlue();
3098 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
3101 // Now, for each point of the rotated image, find where it came from, by
3102 // performing an inverse rotation (a rotation of -angle) and getting the
3103 // pixel at those coordinates
3105 // GRG: I've taken the (interpolating) test out of the loops, so that
3106 // it is done only once, instead of repeating it for each pixel.
3111 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3113 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3115 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3117 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
3118 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
3120 // interpolate using the 4 enclosing grid-points. Those
3121 // points can be obtained using floor and ceiling of the
3122 // exact coordinates of the point
3123 // C.M. 2000-02-17: when the point is near the border, special care is required.
3127 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
3129 x1
= wxCint(floor(src
.x
));
3130 x2
= wxCint(ceil(src
.x
));
3132 else // else means that x is near one of the borders (0 or width-1)
3134 x1
= x2
= wxCint (src
.x
);
3137 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
3139 y1
= wxCint(floor(src
.y
));
3140 y2
= wxCint(ceil(src
.y
));
3144 y1
= y2
= wxCint (src
.y
);
3147 // get four points and the distances (square of the distance,
3148 // for efficiency reasons) for the interpolation formula
3150 // GRG: Do not calculate the points until they are
3151 // really needed -- this way we can calculate
3152 // just one, instead of four, if d1, d2, d3
3153 // or d4 are < gs_Epsilon
3155 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
3156 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
3157 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
3158 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
3160 // Now interpolate as a weighted average of the four surrounding
3161 // points, where the weights are the distances to each of those points
3163 // If the point is exactly at one point of the grid of the source
3164 // image, then don't interpolate -- just assign the pixel
3166 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
3168 unsigned char *p
= data
[y1
] + (3 * x1
);
3173 else if (d2
< gs_Epsilon
)
3175 unsigned char *p
= data
[y1
] + (3 * x2
);
3180 else if (d3
< gs_Epsilon
)
3182 unsigned char *p
= data
[y2
] + (3 * x2
);
3187 else if (d4
< gs_Epsilon
)
3189 unsigned char *p
= data
[y2
] + (3 * x1
);
3196 // weights for the weighted average are proportional to the inverse of the distance
3197 unsigned char *v1
= data
[y1
] + (3 * x1
);
3198 unsigned char *v2
= data
[y1
] + (3 * x2
);
3199 unsigned char *v3
= data
[y2
] + (3 * x2
);
3200 unsigned char *v4
= data
[y2
] + (3 * x1
);
3202 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
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
) );
3214 *(dst
++) = (unsigned char)
3215 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3216 w3
* *(v3
++) + w4
* *(v4
++)) /
3217 (w1
+ w2
+ w3
+ w4
) );
3229 else // not interpolating
3231 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3233 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3235 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3237 const int xs
= wxCint (src
.x
); // wxCint rounds to the
3238 const int ys
= wxCint (src
.y
); // closest integer
3240 if (0 <= xs
&& xs
< GetWidth() &&
3241 0 <= ys
&& ys
< GetHeight())
3243 unsigned char *p
= data
[ys
] + (3 * xs
);