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 // image of 0 width or height can't be considered ok - at least because it
529 // causes crashes in ConvertToBitmap() if we don't catch it in time
530 wxImageRefData
*data
= M_IMGDATA
;
531 return data
&& data
->m_ok
&& data
->m_width
&& data
->m_height
;
534 char unsigned *wxImage::GetData() const
536 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
538 return M_IMGDATA
->m_data
;
541 void wxImage::SetData( char unsigned *data
)
543 wxCHECK_RET( Ok(), wxT("invalid image") );
545 wxImageRefData
*newRefData
= new wxImageRefData();
547 newRefData
->m_width
= M_IMGDATA
->m_width
;
548 newRefData
->m_height
= M_IMGDATA
->m_height
;
549 newRefData
->m_data
= data
;
550 newRefData
->m_ok
= TRUE
;
551 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
552 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
553 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
554 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
558 m_refData
= newRefData
;
561 void wxImage::SetData( char unsigned *data
, int new_width
, int new_height
)
563 wxImageRefData
*newRefData
= new wxImageRefData();
567 newRefData
->m_width
= new_width
;
568 newRefData
->m_height
= new_height
;
569 newRefData
->m_data
= data
;
570 newRefData
->m_ok
= TRUE
;
571 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
572 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
573 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
574 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
578 newRefData
->m_width
= new_width
;
579 newRefData
->m_height
= new_height
;
580 newRefData
->m_data
= data
;
581 newRefData
->m_ok
= TRUE
;
586 m_refData
= newRefData
;
589 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
591 wxCHECK_RET( Ok(), wxT("invalid image") );
593 M_IMGDATA
->m_maskRed
= r
;
594 M_IMGDATA
->m_maskGreen
= g
;
595 M_IMGDATA
->m_maskBlue
= b
;
596 M_IMGDATA
->m_hasMask
= TRUE
;
599 unsigned char wxImage::GetMaskRed() const
601 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
603 return M_IMGDATA
->m_maskRed
;
606 unsigned char wxImage::GetMaskGreen() const
608 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
610 return M_IMGDATA
->m_maskGreen
;
613 unsigned char wxImage::GetMaskBlue() const
615 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
617 return M_IMGDATA
->m_maskBlue
;
620 void wxImage::SetMask( bool mask
)
622 wxCHECK_RET( Ok(), wxT("invalid image") );
624 M_IMGDATA
->m_hasMask
= mask
;
627 bool wxImage::HasMask() const
629 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
631 return M_IMGDATA
->m_hasMask
;
634 int wxImage::GetWidth() const
636 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
638 return M_IMGDATA
->m_width
;
641 int wxImage::GetHeight() const
643 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
645 return M_IMGDATA
->m_height
;
650 bool wxImage::HasPalette() const
655 return M_IMGDATA
->m_palette
.Ok();
658 const wxPalette
& wxImage::GetPalette() const
660 wxCHECK_MSG( Ok(), wxNullPalette
, wxT("invalid image") );
662 return M_IMGDATA
->m_palette
;
665 void wxImage::SetPalette(const wxPalette
& palette
)
667 wxCHECK_RET( Ok(), wxT("invalid image") );
669 M_IMGDATA
->m_palette
= palette
;
672 // Option functions (arbitrary name/value mapping)
673 void wxImage::SetOption(const wxString
& name
, const wxString
& value
)
675 wxCHECK_RET( Ok(), wxT("invalid image") );
677 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
678 if (idx
== wxNOT_FOUND
)
680 M_IMGDATA
->m_optionNames
.Add(name
);
681 M_IMGDATA
->m_optionValues
.Add(value
);
685 M_IMGDATA
->m_optionNames
[idx
] = name
;
686 M_IMGDATA
->m_optionValues
[idx
] = value
;
690 void wxImage::SetOption(const wxString
& name
, int value
)
693 valStr
.Printf(wxT("%d"), value
);
694 SetOption(name
, valStr
);
697 wxString
wxImage::GetOption(const wxString
& name
) const
699 wxCHECK_MSG( Ok(), wxEmptyString
, wxT("invalid image") );
701 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
702 if (idx
== wxNOT_FOUND
)
703 return wxEmptyString
;
705 return M_IMGDATA
->m_optionValues
[idx
];
708 int wxImage::GetOptionInt(const wxString
& name
) const
710 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
712 return wxAtoi(GetOption(name
));
715 bool wxImage::HasOption(const wxString
& name
) const
717 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
719 return (M_IMGDATA
->m_optionNames
.Index(name
, FALSE
) != wxNOT_FOUND
);
722 bool wxImage::LoadFile( const wxString
& filename
, long type
)
725 if (wxFileExists(filename
))
727 wxFileInputStream
stream(filename
);
728 wxBufferedInputStream
bstream( stream
);
729 return LoadFile(bstream
, type
);
733 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
737 #else // !wxUSE_STREAMS
739 #endif // wxUSE_STREAMS
742 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
745 if (wxFileExists(filename
))
747 wxFileInputStream
stream(filename
);
748 wxBufferedInputStream
bstream( stream
);
749 return LoadFile(bstream
, mimetype
);
753 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
757 #else // !wxUSE_STREAMS
759 #endif // wxUSE_STREAMS
762 bool wxImage::SaveFile( const wxString
& filename
, int type
)
765 wxFileOutputStream
stream(filename
);
767 if ( stream
.LastError() == wxStream_NOERROR
)
769 wxBufferedOutputStream
bstream( stream
);
770 return SaveFile(bstream
, type
);
772 #endif // wxUSE_STREAMS
777 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
780 wxFileOutputStream
stream(filename
);
782 if ( stream
.LastError() == wxStream_NOERROR
)
784 wxBufferedOutputStream
bstream( stream
);
785 return SaveFile(bstream
, mimetype
);
787 #endif // wxUSE_STREAMS
792 bool wxImage::CanRead( const wxString
&name
)
795 wxFileInputStream
stream(name
);
796 return CanRead(stream
);
804 bool wxImage::CanRead( wxInputStream
&stream
)
806 wxList
&list
=GetHandlers();
808 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
810 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
811 if (handler
->CanRead( stream
))
818 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
822 m_refData
= new wxImageRefData
;
824 wxImageHandler
*handler
;
826 if (type
==wxBITMAP_TYPE_ANY
)
828 wxList
&list
=GetHandlers();
830 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
832 handler
=(wxImageHandler
*)node
->GetData();
833 if (handler
->CanRead( stream
))
834 return handler
->LoadFile( this, stream
);
838 wxLogWarning( _("No handler found for image type.") );
842 handler
= FindHandler(type
);
846 wxLogWarning( _("No image handler for type %d defined."), type
);
851 return handler
->LoadFile( this, stream
);
854 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
858 m_refData
= new wxImageRefData
;
860 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
864 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
869 return handler
->LoadFile( this, stream
);
872 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
874 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
876 wxImageHandler
*handler
= FindHandler(type
);
880 wxLogWarning( _("No image handler for type %d defined."), type
);
885 return handler
->SaveFile( this, stream
);
888 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
890 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
892 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
896 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
901 return handler
->SaveFile( this, stream
);
903 #endif // wxUSE_STREAMS
905 void wxImage::AddHandler( wxImageHandler
*handler
)
907 // make sure that the memory will be freed at the program end
908 sm_handlers
.DeleteContents(TRUE
);
910 sm_handlers
.Append( handler
);
913 void wxImage::InsertHandler( wxImageHandler
*handler
)
915 // make sure that the memory will be freed at the program end
916 sm_handlers
.DeleteContents(TRUE
);
918 sm_handlers
.Insert( handler
);
921 bool wxImage::RemoveHandler( const wxString
& name
)
923 wxImageHandler
*handler
= FindHandler(name
);
926 sm_handlers
.DeleteObject(handler
);
933 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
935 wxNode
*node
= sm_handlers
.First();
938 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
939 if (handler
->GetName().Cmp(name
) == 0) return handler
;
943 return (wxImageHandler
*)NULL
;
946 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
948 wxNode
*node
= sm_handlers
.First();
951 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
952 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
953 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
957 return (wxImageHandler
*)NULL
;
960 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
962 wxNode
*node
= sm_handlers
.First();
965 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
966 if (handler
->GetType() == bitmapType
) return handler
;
972 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
974 wxNode
*node
= sm_handlers
.First();
977 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
978 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
984 void wxImage::InitStandardHandlers()
986 AddHandler( new wxBMPHandler
);
989 void wxImage::CleanUpHandlers()
991 wxNode
*node
= sm_handlers
.First();
994 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
995 wxNode
*next
= node
->Next();
1002 //-----------------------------------------------------------------------------
1004 //-----------------------------------------------------------------------------
1006 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
1009 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
1014 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
1019 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
1024 bool wxImageHandler::CanRead( const wxString
& name
)
1026 if (wxFileExists(name
))
1028 wxFileInputStream
stream(name
);
1029 return CanRead(stream
);
1033 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
1040 #endif // wxUSE_STREAMS
1042 //-----------------------------------------------------------------------------
1043 // MSW conversion routines
1044 //-----------------------------------------------------------------------------
1048 wxBitmap
wxImage::ConvertToBitmap() const
1051 return wxNullBitmap
;
1053 // sizeLimit is the MS upper limit for the DIB size
1055 int sizeLimit
= 1024*768*3;
1057 int sizeLimit
= 0x7fff ;
1060 // width and height of the device-dependent bitmap
1061 int width
= GetWidth();
1062 int bmpHeight
= GetHeight();
1064 // calc the number of bytes per scanline and padding
1065 int bytePerLine
= width
*3;
1066 int sizeDWORD
= sizeof( DWORD
);
1067 int lineBoundary
= bytePerLine
% sizeDWORD
;
1069 if( lineBoundary
> 0 )
1071 padding
= sizeDWORD
- lineBoundary
;
1072 bytePerLine
+= padding
;
1074 // calc the number of DIBs and heights of DIBs
1077 int height
= sizeLimit
/bytePerLine
;
1078 if( height
>= bmpHeight
)
1082 numDIB
= bmpHeight
/ height
;
1083 hRemain
= bmpHeight
% height
;
1084 if( hRemain
>0 ) numDIB
++;
1087 // set bitmap parameters
1089 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1090 bitmap
.SetWidth( width
);
1091 bitmap
.SetHeight( bmpHeight
);
1092 bitmap
.SetDepth( wxDisplayDepth() );
1094 // create a DIB header
1095 int headersize
= sizeof(BITMAPINFOHEADER
);
1096 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1097 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
1098 // Fill in the DIB header
1099 lpDIBh
->bmiHeader
.biSize
= headersize
;
1100 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
1101 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1102 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1103 // the general formula for biSizeImage:
1104 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
1105 lpDIBh
->bmiHeader
.biPlanes
= 1;
1106 lpDIBh
->bmiHeader
.biBitCount
= 24;
1107 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1108 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1109 // These seem not really needed for our purpose here.
1110 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1111 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1112 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1113 // memory for DIB data
1114 unsigned char *lpBits
;
1115 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1118 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
1123 // create and set the device-dependent bitmap
1124 HDC hdc
= ::GetDC(NULL
);
1125 HDC memdc
= ::CreateCompatibleDC( hdc
);
1127 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
1128 ::SelectObject( memdc
, hbitmap
);
1130 HPALETTE hOldPalette
= 0;
1131 if (GetPalette().Ok())
1133 hOldPalette
= ::SelectPalette(memdc
, (HPALETTE
) GetPalette().GetHPALETTE(), FALSE
);
1134 ::RealizePalette(memdc
);
1137 // copy image data into DIB data and then into DDB (in a loop)
1138 unsigned char *data
= GetData();
1141 unsigned char *ptdata
= data
;
1142 unsigned char *ptbits
;
1144 for( n
=0; n
<numDIB
; n
++ )
1146 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
1148 // redefine height and size of the (possibly) last smaller DIB
1149 // memory is not reallocated
1151 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1152 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1156 for( j
=0; j
<height
; j
++ )
1158 for( i
=0; i
<width
; i
++ )
1160 *(ptbits
++) = *(ptdata
+2);
1161 *(ptbits
++) = *(ptdata
+1);
1162 *(ptbits
++) = *(ptdata
);
1165 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
1167 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1168 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1170 // if numDIB = 1, lines below can also be used
1171 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1172 // The above line is equivalent to the following two lines.
1173 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1174 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1175 // or the following lines
1176 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1177 // HDC memdc = ::CreateCompatibleDC( hdc );
1178 // ::SelectObject( memdc, hbitmap);
1179 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1180 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1181 // ::SelectObject( memdc, 0 );
1182 // ::DeleteDC( memdc );
1184 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
1187 SelectPalette(memdc
, hOldPalette
, FALSE
);
1189 // similarly, created an mono-bitmap for the possible mask
1192 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
1193 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
1194 if( numDIB
== 1 ) height
= bmpHeight
;
1195 else height
= sizeLimit
/bytePerLine
;
1196 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1197 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1199 unsigned char r
= GetMaskRed();
1200 unsigned char g
= GetMaskGreen();
1201 unsigned char b
= GetMaskBlue();
1202 unsigned char zero
= 0, one
= 255;
1204 for( n
=0; n
<numDIB
; n
++ )
1206 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
1208 // redefine height and size of the (possibly) last smaller DIB
1209 // memory is not reallocated
1211 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1212 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1215 for( int j
=0; j
<height
; j
++ )
1217 for(i
=0; i
<width
; i
++ )
1219 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
1220 unsigned char cr
= (*(ptdata
++)) ;
1221 unsigned char cg
= (*(ptdata
++)) ;
1222 unsigned char cb
= (*(ptdata
++)) ;
1224 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
1237 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
1239 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1240 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1243 // create a wxMask object
1244 wxMask
*mask
= new wxMask();
1245 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
1246 bitmap
.SetMask( mask
);
1247 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1248 /* The following can also be used but is slow to run
1249 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1250 wxMask *mask = new wxMask( bitmap, colour );
1251 bitmap.SetMask( mask );
1254 ::SelectObject( memdc
, hbmpOld
);
1257 // free allocated resources
1258 ::DeleteDC( memdc
);
1259 ::ReleaseDC(NULL
, hdc
);
1263 #if WXWIN_COMPATIBILITY_2
1264 // check the wxBitmap object
1265 bitmap
.GetBitmapData()->SetOk();
1266 #endif // WXWIN_COMPATIBILITY_2
1271 wxImage::wxImage( const wxBitmap
&bitmap
)
1276 wxFAIL_MSG( wxT("invalid bitmap") );
1280 // create an wxImage object
1281 int width
= bitmap
.GetWidth();
1282 int height
= bitmap
.GetHeight();
1283 Create( width
, height
);
1284 unsigned char *data
= GetData();
1287 wxFAIL_MSG( wxT("could not allocate data for image") );
1291 // calc the number of bytes per scanline and padding in the DIB
1292 int bytePerLine
= width
*3;
1293 int sizeDWORD
= sizeof( DWORD
);
1294 int lineBoundary
= bytePerLine
% sizeDWORD
;
1296 if( lineBoundary
> 0 )
1298 padding
= sizeDWORD
- lineBoundary
;
1299 bytePerLine
+= padding
;
1302 // create a DIB header
1303 int headersize
= sizeof(BITMAPINFOHEADER
);
1304 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1307 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1311 // Fill in the DIB header
1312 lpDIBh
->bmiHeader
.biSize
= headersize
;
1313 lpDIBh
->bmiHeader
.biWidth
= width
;
1314 lpDIBh
->bmiHeader
.biHeight
= -height
;
1315 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
1316 lpDIBh
->bmiHeader
.biPlanes
= 1;
1317 lpDIBh
->bmiHeader
.biBitCount
= 24;
1318 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1319 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1320 // These seem not really needed for our purpose here.
1321 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1322 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1323 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1324 // memory for DIB data
1325 unsigned char *lpBits
;
1326 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1329 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1335 // copy data from the device-dependent bitmap to the DIB
1336 HDC hdc
= ::GetDC(NULL
);
1338 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1339 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1341 // copy DIB data into the wxImage object
1343 unsigned char *ptdata
= data
;
1344 unsigned char *ptbits
= lpBits
;
1345 for( i
=0; i
<height
; i
++ )
1347 for( j
=0; j
<width
; j
++ )
1349 *(ptdata
++) = *(ptbits
+2);
1350 *(ptdata
++) = *(ptbits
+1);
1351 *(ptdata
++) = *(ptbits
);
1357 // similarly, set data according to the possible mask bitmap
1358 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1360 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1361 // memory DC created, color set, data copied, and memory DC deleted
1362 HDC memdc
= ::CreateCompatibleDC( hdc
);
1363 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1364 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1365 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1366 ::DeleteDC( memdc
);
1367 // background color set to RGB(16,16,16) in consistent with wxGTK
1368 unsigned char r
=16, g
=16, b
=16;
1371 for( i
=0; i
<height
; i
++ )
1373 for( j
=0; j
<width
; j
++ )
1387 SetMaskColour( r
, g
, b
);
1394 // free allocated resources
1395 ::ReleaseDC(NULL
, hdc
);
1405 #include <ApplicationServices/ApplicationServices.h>
1407 #include <PictUtils.h>
1410 wxBitmap
wxImage::ConvertToBitmap() const
1412 // width and height of the device-dependent bitmap
1413 int width
= GetWidth();
1414 int height
= GetHeight();
1420 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1422 bitmap
.Create( width
, height
, wxDisplayDepth() ) ;
1423 wxBitmap
maskBitmap( width
, height
, 1);
1426 GDHandle origDevice
;
1428 LockPixels( GetGWorldPixMap(bitmap
.GetHBITMAP()) );
1429 LockPixels( GetGWorldPixMap(maskBitmap
.GetHBITMAP()) );
1431 GetGWorld( &origPort
, &origDevice
) ;
1432 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1435 wxColour rgb
, maskcolor(GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1437 RGBColor white
= { 0xffff, 0xffff, 0xffff };
1438 RGBColor black
= { 0 , 0 , 0 };
1440 register unsigned char* data
= GetData();
1443 for (int y
= 0; y
< height
; y
++)
1445 for (int x
= 0; x
< width
; x
++)
1447 rgb
.Set(data
[index
++], data
[index
++], data
[index
++]);
1448 color
= rgb
.GetPixel();
1449 SetCPixel( x
, y
, &color
) ;
1452 SetGWorld(maskBitmap
.GetHBITMAP(), NULL
);
1453 if (rgb
== maskcolor
) {
1454 SetCPixel(x
,y
, &white
);
1457 SetCPixel(x
,y
, &black
);
1459 SetGWorld(bitmap
.GetHBITMAP(), NULL
);
1466 wxMask
*mask
= new wxMask( maskBitmap
);
1469 UnlockPixels( GetGWorldPixMap(bitmap
.GetHBITMAP()) );
1470 UnlockPixels( GetGWorldPixMap(maskBitmap
.GetHBITMAP()) );
1471 SetGWorld( origPort
, origDevice
);
1476 wxImage::wxImage( const wxBitmap
&bitmap
)
1479 wxCHECK_RET( bitmap
.Ok(), wxT("Invalid bitmap") );
1481 // create an wxImage object
1482 int width
= bitmap
.GetWidth();
1483 int height
= bitmap
.GetHeight();
1484 Create( width
, height
);
1486 unsigned char *data
= GetData();
1488 wxCHECK_RET( data
, wxT("Could not allocate data for image") );
1491 GDHandle origDevice
;
1494 // background color set to RGB(16,16,16) in consistent with wxGTK
1495 unsigned char mask_r
=16, mask_g
=16, mask_b
=16;
1497 wxMask
*mask
= bitmap
.GetMask();
1499 GetGWorld( &origPort
, &origDevice
);
1500 LockPixels(GetGWorldPixMap(bitmap
.GetHBITMAP()));
1501 SetGWorld( bitmap
.GetHBITMAP(), NULL
);
1503 // Copy data into image
1505 for (int yy
= 0; yy
< height
; yy
++)
1507 for (int xx
= 0; xx
< width
; xx
++)
1509 GetCPixel(xx
,yy
, &color
);
1510 r
= ((color
.red
) >> 8);
1511 g
= ((color
.green
) >> 8);
1512 b
= ((color
.blue
) >> 8);
1514 data
[index
+ 1] = g
;
1515 data
[index
+ 2] = b
;
1518 if (mask
->PointMasked(xx
,yy
))
1520 data
[index
] = mask_r
;
1521 data
[index
+ 1] = mask_g
;
1522 data
[index
+ 2] = mask_b
;
1530 SetMaskColour( mask_r
, mask_g
, mask_b
);
1535 UnlockPixels(GetGWorldPixMap(bitmap
.GetHBITMAP()));
1536 SetGWorld(origPort
, origDevice
);
1541 //-----------------------------------------------------------------------------
1542 // GTK conversion routines
1543 //-----------------------------------------------------------------------------
1547 #include <gtk/gtk.h>
1548 #include <gdk/gdk.h>
1549 #include <gdk/gdkx.h>
1551 #if (GTK_MINOR_VERSION > 0)
1552 #include <gdk/gdkrgb.h>
1555 extern GtkWidget
*wxRootWindow
;
1557 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1561 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1563 int width
= GetWidth();
1564 int height
= GetHeight();
1566 bitmap
.SetHeight( height
);
1567 bitmap
.SetWidth( width
);
1569 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1571 bitmap
.SetDepth( 1 );
1573 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1576 // Create picture image
1578 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1580 GdkImage
*data_image
=
1581 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1583 // Create mask image
1585 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1589 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1591 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1593 wxMask
*mask
= new wxMask();
1594 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1596 bitmap
.SetMask( mask
);
1599 int r_mask
= GetMaskRed();
1600 int g_mask
= GetMaskGreen();
1601 int b_mask
= GetMaskBlue();
1603 unsigned char* data
= GetData();
1606 for (int y
= 0; y
< height
; y
++)
1608 for (int x
= 0; x
< width
; x
++)
1610 int r
= data
[index
];
1612 int g
= data
[index
];
1614 int b
= data
[index
];
1619 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1620 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1622 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1625 if ((r
== red
) && (b
== blue
) && (g
== green
))
1626 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1628 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1635 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1637 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1639 gdk_image_destroy( data_image
);
1640 gdk_gc_unref( data_gc
);
1646 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1648 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1650 gdk_image_destroy( mask_image
);
1651 gdk_gc_unref( mask_gc
);
1658 wxBitmap
wxImage::ConvertToBitmap() const
1662 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1664 int width
= GetWidth();
1665 int height
= GetHeight();
1667 bitmap
.SetHeight( height
);
1668 bitmap
.SetWidth( width
);
1670 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1674 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1677 int bpp
= visual
->depth
;
1679 bitmap
.SetDepth( bpp
);
1681 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1682 if (bpp
< 8) bpp
= 8;
1684 #if (GTK_MINOR_VERSION > 0)
1686 if (!HasMask() && (bpp
> 8))
1688 static bool s_hasInitialized
= FALSE
;
1690 if (!s_hasInitialized
)
1693 s_hasInitialized
= TRUE
;
1696 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1698 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1702 GDK_RGB_DITHER_NONE
,
1713 // Create picture image
1715 GdkImage
*data_image
=
1716 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1718 // Create mask image
1720 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1724 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1726 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1728 wxMask
*mask
= new wxMask();
1729 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1731 bitmap
.SetMask( mask
);
1736 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1737 byte_order b_o
= RGB
;
1741 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1742 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1743 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1744 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1745 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1746 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1749 int r_mask
= GetMaskRed();
1750 int g_mask
= GetMaskGreen();
1751 int b_mask
= GetMaskBlue();
1753 unsigned char* data
= GetData();
1756 for (int y
= 0; y
< height
; y
++)
1758 for (int x
= 0; x
< width
; x
++)
1760 int r
= data
[index
];
1762 int g
= data
[index
];
1764 int b
= data
[index
];
1769 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1770 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1772 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1780 if (wxTheApp
->m_colorCube
)
1782 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1786 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1787 GdkColor
*colors
= cmap
->colors
;
1788 int max
= 3 * (65536);
1790 for (int i
= 0; i
< cmap
->size
; i
++)
1792 int rdiff
= (r
<< 8) - colors
[i
].red
;
1793 int gdiff
= (g
<< 8) - colors
[i
].green
;
1794 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1795 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1796 if (sum
< max
) { pixel
= i
; max
= sum
; }
1800 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1806 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1807 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1812 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1813 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1822 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1823 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1824 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1825 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1826 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1827 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1829 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1838 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1840 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1842 gdk_image_destroy( data_image
);
1843 gdk_gc_unref( data_gc
);
1849 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1851 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1853 gdk_image_destroy( mask_image
);
1854 gdk_gc_unref( mask_gc
);
1860 wxImage::wxImage( const wxBitmap
&bitmap
)
1862 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1864 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1865 if (bitmap
.GetPixmap())
1867 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1869 bitmap
.GetWidth(), bitmap
.GetHeight() );
1871 if (bitmap
.GetBitmap())
1873 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1875 bitmap
.GetWidth(), bitmap
.GetHeight() );
1878 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1881 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1883 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1884 char unsigned *data
= GetData();
1888 gdk_image_destroy( gdk_image
);
1889 wxFAIL_MSG( wxT("couldn't create image") );
1893 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1894 if (bitmap
.GetMask())
1896 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1898 bitmap
.GetWidth(), bitmap
.GetHeight() );
1900 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1904 int red_shift_right
= 0;
1905 int green_shift_right
= 0;
1906 int blue_shift_right
= 0;
1907 int red_shift_left
= 0;
1908 int green_shift_left
= 0;
1909 int blue_shift_left
= 0;
1910 bool use_shift
= FALSE
;
1912 if (bitmap
.GetPixmap())
1914 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1916 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1917 bpp
= visual
->depth
;
1918 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1919 red_shift_right
= visual
->red_shift
;
1920 red_shift_left
= 8-visual
->red_prec
;
1921 green_shift_right
= visual
->green_shift
;
1922 green_shift_left
= 8-visual
->green_prec
;
1923 blue_shift_right
= visual
->blue_shift
;
1924 blue_shift_left
= 8-visual
->blue_prec
;
1926 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
1928 if (bitmap
.GetBitmap())
1934 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1937 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1939 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1941 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1959 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
1960 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
1961 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
1963 else if (cmap
->colors
)
1965 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1966 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1967 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1971 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1976 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1977 if (mask_pixel
== 0)
1989 gdk_image_destroy( gdk_image
);
1990 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1995 //-----------------------------------------------------------------------------
1996 // Motif conversion routines
1997 //-----------------------------------------------------------------------------
2001 #pragma message disable nosimpint
2005 #pragma message enable nosimpint
2007 #include "wx/utils.h"
2012 Date: Wed, 05 Jan 2000 11:45:40 +0100
2013 From: Frits Boel <boel@niob.knaw.nl>
2014 To: julian.smart@ukonline.co.uk
2015 Subject: Patch for Motif ConvertToBitmap
2019 I've been working on a wxWin application for image processing. From the
2020 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
2021 till I looked in the source code of image.cpp. I saw that converting a
2022 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
2023 to the 256 colors of the palet. A very time-consuming piece of code!
2025 Because I wanted a faster application, I've made a 'patch' for this. In
2026 short: every pixel of the image is compared to a sorted list with
2027 colors. If the color is found in the list, the palette entry is
2028 returned; if the color is not found, the color palette is searched and
2029 then the palette entry is returned and the color added to the sorted
2032 Maybe there is another method for this, namely changing the palette
2033 itself (if the colors are known, as is the case with tiffs with a
2034 colormap). I did not look at this, maybe someone else did?
2036 The code of the patch is attached, have a look on it, and maybe you will
2037 ship it with the next release of wxMotif?
2042 Software engineer at Hubrecht Laboratory, The Netherlands.
2049 wxSearchColor( void );
2050 wxSearchColor( int size
, XColor
*colors
);
2051 ~wxSearchColor( void );
2053 int SearchColor( int r
, int g
, int b
);
2055 int AddColor( unsigned int value
, int pos
);
2059 unsigned int *color
;
2066 wxSearchColor::wxSearchColor( void )
2069 colors
= (XColor
*) NULL
;
2070 color
= (unsigned int *) NULL
;
2071 entry
= (int*) NULL
;
2077 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
2082 color
= new unsigned int[size
];
2083 entry
= new int [size
];
2085 for (i
= 0; i
< size
; i
++ ) {
2089 bottom
= top
= ( size
>> 1 );
2092 wxSearchColor::~wxSearchColor( void )
2094 if ( color
) delete color
;
2095 if ( entry
) delete entry
;
2098 int wxSearchColor::SearchColor( int r
, int g
, int b
)
2100 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
2105 while ( begin
<= end
) {
2107 middle
= ( begin
+ end
) >> 1;
2109 if ( value
== color
[middle
] ) {
2110 return( entry
[middle
] );
2111 } else if ( value
< color
[middle
] ) {
2119 return AddColor( value
, middle
);
2122 int wxSearchColor::AddColor( unsigned int value
, int pos
)
2126 int max
= 3 * (65536);
2127 for ( i
= 0; i
< 256; i
++ ) {
2128 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
2129 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
2130 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
2131 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2132 if (sum
< max
) { pixel
= i
; max
= sum
; }
2135 if ( entry
[pos
] < 0 ) {
2138 } else if ( value
< color
[pos
] ) {
2141 for ( i
= bottom
; i
< pos
; i
++ ) {
2142 color
[i
-1] = color
[i
];
2143 entry
[i
-1] = entry
[i
];
2146 color
[pos
-1] = value
;
2147 entry
[pos
-1] = pixel
;
2148 } else if ( top
< size
-1 ) {
2149 for ( i
= top
; i
>= pos
; i
-- ) {
2150 color
[i
+1] = color
[i
];
2151 entry
[i
+1] = entry
[i
];
2160 if ( top
< size
-1 ) {
2161 for ( i
= top
; i
> pos
; i
-- ) {
2162 color
[i
+1] = color
[i
];
2163 entry
[i
+1] = entry
[i
];
2166 color
[pos
+1] = value
;
2167 entry
[pos
+1] = pixel
;
2168 } else if ( bottom
> 0 ) {
2169 for ( i
= bottom
; i
< pos
; i
++ ) {
2170 color
[i
-1] = color
[i
];
2171 entry
[i
-1] = entry
[i
];
2183 wxBitmap
wxImage::ConvertToBitmap() const
2187 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
2189 int width
= GetWidth();
2190 int height
= GetHeight();
2192 bitmap
.SetHeight( height
);
2193 bitmap
.SetWidth( width
);
2195 Display
*dpy
= (Display
*) wxGetDisplay();
2196 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2197 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2201 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2202 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
2204 bitmap
.Create( width
, height
, bpp
);
2208 XImage
*mask_image
= (XImage
*) NULL
;
2211 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2212 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
2215 // Retrieve depth info
2217 XVisualInfo vinfo_template
;
2220 vinfo_template
.visual
= vis
;
2221 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2222 vinfo_template
.depth
= bpp
;
2225 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2227 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
2231 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2232 if (bpp
< 8) bpp
= 8;
2236 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
2237 byte_order b_o
= RGB
;
2241 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2242 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2243 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2244 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2245 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2246 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2249 int r_mask
= GetMaskRed();
2250 int g_mask
= GetMaskGreen();
2251 int b_mask
= GetMaskBlue();
2256 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2258 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2259 XQueryColors( dpy
, cmap
, colors
, 256 );
2262 wxSearchColor
scolor( 256, colors
);
2263 unsigned char* data
= GetData();
2265 bool hasMask
= HasMask();
2268 for (int y
= 0; y
< height
; y
++)
2270 for (int x
= 0; x
< width
; x
++)
2272 int r
= data
[index
];
2274 int g
= data
[index
];
2276 int b
= data
[index
];
2281 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2282 XPutPixel( mask_image
, x
, y
, 0 );
2284 XPutPixel( mask_image
, x
, y
, 1 );
2291 #if 0 // Old, slower code
2294 if (wxTheApp->m_colorCube)
2296 pixel = wxTheApp->m_colorCube
2297 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2302 int max
= 3 * (65536);
2303 for (int i
= 0; i
< 256; i
++)
2305 int rdiff
= (r
<< 8) - colors
[i
].red
;
2306 int gdiff
= (g
<< 8) - colors
[i
].green
;
2307 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2308 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2309 if (sum
< max
) { pixel
= i
; max
= sum
; }
2316 // And this is all to get the 'right' color...
2317 int pixel
= scolor
.SearchColor( r
, g
, b
);
2318 XPutPixel( data_image
, x
, y
, pixel
);
2323 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2324 XPutPixel( data_image
, x
, y
, pixel
);
2329 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2330 XPutPixel( data_image
, x
, y
, pixel
);
2339 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2340 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2341 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2342 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2343 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2344 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2346 XPutPixel( data_image
, x
, y
, pixel
);
2356 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2357 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2358 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2360 XDestroyImage( data_image
);
2366 wxBitmap
maskBitmap(width
, height
, 1);
2368 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2369 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2371 XDestroyImage( mask_image
);
2372 XFreeGC( dpy
, gcMask
);
2374 wxMask
* mask
= new wxMask
;
2375 mask
->SetPixmap(maskBitmap
.GetPixmap());
2377 bitmap
.SetMask(mask
);
2379 maskBitmap
.SetPixmapNull();
2385 wxImage::wxImage( const wxBitmap
&bitmap
)
2387 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2389 Display
*dpy
= (Display
*) wxGetDisplay();
2390 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2391 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2393 XImage
*ximage
= XGetImage( dpy
,
2394 (Drawable
)bitmap
.GetPixmap(),
2396 bitmap
.GetWidth(), bitmap
.GetHeight(),
2397 AllPlanes
, ZPixmap
);
2399 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2401 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2402 char unsigned *data
= GetData();
2406 XDestroyImage( ximage
);
2407 wxFAIL_MSG( wxT("couldn't create image") );
2412 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2413 if (bitmap.GetMask())
2415 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2417 bitmap.GetWidth(), bitmap.GetHeight() );
2419 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2423 // Retrieve depth info
2425 XVisualInfo vinfo_template
;
2428 vinfo_template
.visual
= vis
;
2429 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2430 vinfo_template
.depth
= bpp
;
2433 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2435 wxCHECK_RET( vi
, wxT("no visual") );
2437 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2444 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2446 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2447 XQueryColors( dpy
, cmap
, colors
, 256 );
2451 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2453 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2455 int pixel
= XGetPixel( ximage
, i
, j
);
2458 data
[pos
] = colors
[pixel
].red
>> 8;
2459 data
[pos
+1] = colors
[pixel
].green
>> 8;
2460 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2461 } else if (bpp
== 15)
2463 data
[pos
] = (pixel
>> 7) & 0xf8;
2464 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2465 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2466 } else if (bpp
== 16)
2468 data
[pos
] = (pixel
>> 8) & 0xf8;
2469 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2470 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2473 data
[pos
] = (pixel
>> 16) & 0xff;
2474 data
[pos
+1] = (pixel
>> 8) & 0xff;
2475 data
[pos
+2] = pixel
& 0xff;
2481 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2482 if (mask_pixel == 0)
2495 XDestroyImage( ximage
);
2497 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2503 // OS/2 Presentation manager conversion routings
2505 wxBitmap
wxImage::ConvertToBitmap() const
2508 return wxNullBitmap
;
2509 wxBitmap bitmap
; // remove
2512 int sizeLimit = 1024*768*3;
2514 // width and height of the device-dependent bitmap
2515 int width = GetWidth();
2516 int bmpHeight = GetHeight();
2518 // calc the number of bytes per scanline and padding
2519 int bytePerLine = width*3;
2520 int sizeDWORD = sizeof( DWORD );
2521 int lineBoundary = bytePerLine % sizeDWORD;
2523 if( lineBoundary > 0 )
2525 padding = sizeDWORD - lineBoundary;
2526 bytePerLine += padding;
2528 // calc the number of DIBs and heights of DIBs
2531 int height = sizeLimit/bytePerLine;
2532 if( height >= bmpHeight )
2536 numDIB = bmpHeight / height;
2537 hRemain = bmpHeight % height;
2538 if( hRemain >0 ) numDIB++;
2541 // set bitmap parameters
2543 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2544 bitmap.SetWidth( width );
2545 bitmap.SetHeight( bmpHeight );
2546 bitmap.SetDepth( wxDisplayDepth() );
2548 // create a DIB header
2549 int headersize = sizeof(BITMAPINFOHEADER);
2550 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2551 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2552 // Fill in the DIB header
2553 lpDIBh->bmiHeader.biSize = headersize;
2554 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2555 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2556 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2557 // the general formula for biSizeImage:
2558 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2559 lpDIBh->bmiHeader.biPlanes = 1;
2560 lpDIBh->bmiHeader.biBitCount = 24;
2561 lpDIBh->bmiHeader.biCompression = BI_RGB;
2562 lpDIBh->bmiHeader.biClrUsed = 0;
2563 // These seem not really needed for our purpose here.
2564 lpDIBh->bmiHeader.biClrImportant = 0;
2565 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2566 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2567 // memory for DIB data
2568 unsigned char *lpBits;
2569 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2572 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2577 // create and set the device-dependent bitmap
2578 HDC hdc = ::GetDC(NULL);
2579 HDC memdc = ::CreateCompatibleDC( hdc );
2581 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2582 ::SelectObject( memdc, hbitmap);
2584 // copy image data into DIB data and then into DDB (in a loop)
2585 unsigned char *data = GetData();
2588 unsigned char *ptdata = data;
2589 unsigned char *ptbits;
2591 for( n=0; n<numDIB; n++ )
2593 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2595 // redefine height and size of the (possibly) last smaller DIB
2596 // memory is not reallocated
2598 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2599 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2603 for( j=0; j<height; j++ )
2605 for( i=0; i<width; i++ )
2607 *(ptbits++) = *(ptdata+2);
2608 *(ptbits++) = *(ptdata+1);
2609 *(ptbits++) = *(ptdata );
2612 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2614 ::StretchDIBits( memdc, 0, origin, width, height,\
2615 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2617 // if numDIB = 1, lines below can also be used
2618 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2619 // The above line is equivalent to the following two lines.
2620 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2621 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2622 // or the following lines
2623 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2624 // HDC memdc = ::CreateCompatibleDC( hdc );
2625 // ::SelectObject( memdc, hbitmap);
2626 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2627 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2628 // ::SelectObject( memdc, 0 );
2629 // ::DeleteDC( memdc );
2631 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2633 // similarly, created an mono-bitmap for the possible mask
2636 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2637 ::SelectObject( memdc, hbitmap);
2638 if( numDIB == 1 ) height = bmpHeight;
2639 else height = sizeLimit/bytePerLine;
2640 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2641 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2643 unsigned char r = GetMaskRed();
2644 unsigned char g = GetMaskGreen();
2645 unsigned char b = GetMaskBlue();
2646 unsigned char zero = 0, one = 255;
2648 for( n=0; n<numDIB; n++ )
2650 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2652 // redefine height and size of the (possibly) last smaller DIB
2653 // memory is not reallocated
2655 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2656 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2659 for( int j=0; j<height; j++ )
2661 for(i=0; i<width; i++ )
2663 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2676 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2678 ::StretchDIBits( memdc, 0, origin, width, height,\
2679 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2682 // create a wxMask object
2683 wxMask *mask = new wxMask();
2684 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2685 bitmap.SetMask( mask );
2688 // free allocated resources
2689 ::SelectObject( memdc, 0 );
2690 ::DeleteDC( memdc );
2691 ::ReleaseDC(NULL, hdc);
2695 // check the wxBitmap object
2696 if( bitmap.GetHBITMAP() )
2697 bitmap.SetOk( TRUE );
2699 bitmap.SetOk( FALSE );
2704 wxImage::wxImage( const wxBitmap
&bitmap
)
2709 wxFAIL_MSG( wxT("invalid bitmap") );
2713 // create an wxImage object
2714 int width
= bitmap
.GetWidth();
2715 int height
= bitmap
.GetHeight();
2716 Create( width
, height
);
2717 unsigned char *data
= GetData();
2720 wxFAIL_MSG( wxT("could not allocate data for image") );
2724 // calc the number of bytes per scanline and padding in the DIB
2725 int bytePerLine
= width
*3;
2726 int sizeDWORD
= sizeof( DWORD
);
2727 int lineBoundary
= bytePerLine
% sizeDWORD
;
2729 if( lineBoundary
> 0 )
2731 padding
= sizeDWORD
- lineBoundary
;
2732 bytePerLine
+= padding
;
2736 // create a DIB header
2737 int headersize = sizeof(BITMAPINFOHEADER);
2738 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2741 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2745 // Fill in the DIB header
2746 lpDIBh->bmiHeader.biSize = headersize;
2747 lpDIBh->bmiHeader.biWidth = width;
2748 lpDIBh->bmiHeader.biHeight = -height;
2749 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2750 lpDIBh->bmiHeader.biPlanes = 1;
2751 lpDIBh->bmiHeader.biBitCount = 24;
2752 lpDIBh->bmiHeader.biCompression = BI_RGB;
2753 lpDIBh->bmiHeader.biClrUsed = 0;
2754 // These seem not really needed for our purpose here.
2755 lpDIBh->bmiHeader.biClrImportant = 0;
2756 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2757 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2758 // memory for DIB data
2759 unsigned char *lpBits;
2760 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2763 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2769 // copy data from the device-dependent bitmap to the DIB
2770 HDC hdc = ::GetDC(NULL);
2772 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2773 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2775 // copy DIB data into the wxImage object
2777 unsigned char *ptdata = data;
2778 unsigned char *ptbits = lpBits;
2779 for( i=0; i<height; i++ )
2781 for( j=0; j<width; j++ )
2783 *(ptdata++) = *(ptbits+2);
2784 *(ptdata++) = *(ptbits+1);
2785 *(ptdata++) = *(ptbits );
2791 // similarly, set data according to the possible mask bitmap
2792 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2794 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2795 // memory DC created, color set, data copied, and memory DC deleted
2796 HDC memdc = ::CreateCompatibleDC( hdc );
2797 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2798 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2799 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2800 ::DeleteDC( memdc );
2801 // background color set to RGB(16,16,16) in consistent with wxGTK
2802 unsigned char r=16, g=16, b=16;
2805 for( i=0; i<height; i++ )
2807 for( j=0; j<width; j++ )
2821 SetMaskColour( r, g, b );
2828 // free allocated resources
2829 ::ReleaseDC(NULL, hdc);
2837 // A module to allow wxImage initialization/cleanup
2838 // without calling these functions from app.cpp or from
2839 // the user's application.
2841 class wxImageModule
: public wxModule
2843 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2846 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2847 void OnExit() { wxImage::CleanUpHandlers(); };
2850 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2853 //-----------------------------------------------------------------------------
2856 // Counts and returns the number of different colours. Optionally stops
2857 // when it exceeds 'stopafter' different colours. This is useful, for
2858 // example, to see if the image can be saved as 8-bit (256 colour or
2859 // less, in this case it would be invoked as CountColours(256)). Default
2860 // value for stopafter is -1 (don't care).
2862 unsigned long wxImage::CountColours( unsigned long stopafter
)
2866 unsigned char r
, g
, b
, *p
;
2867 unsigned long size
, nentries
, key
;
2870 size
= GetWidth() * GetHeight();
2873 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2878 key
= (r
<< 16) | (g
<< 8) | b
;
2880 if (h
.Get(key
) == NULL
)
2892 // Computes the histogram of the image and fills a hash table, indexed
2893 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2894 // wxHNode contains an 'index' (useful to build a palette with the image
2895 // colours) and a 'value', which is the number of pixels in the image with
2898 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2900 unsigned char r
, g
, b
, *p
;
2901 unsigned long size
, nentries
, key
;
2905 size
= GetWidth() * GetHeight();
2908 for (unsigned long j
= 0; j
< size
; j
++)
2913 key
= (r
<< 16) | (g
<< 8) | b
;
2915 hnode
= (wxHNode
*) h
.Get(key
);
2921 hnode
= new wxHNode();
2922 hnode
->index
= nentries
++;
2925 h
.Put(key
, (wxObject
*)hnode
);
2933 * Rotation code by Carlos Moreno
2936 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2937 // does exactly the same thing. And I also got rid of wxRotationPixel
2938 // bacause of potential problems in architectures where alignment
2939 // is an issue, so I had to rewrite parts of the code.
2941 static const double gs_Epsilon
= 1e-10;
2943 static inline int wxCint (double x
)
2945 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
2949 // Auxiliary function to rotate a point (x,y) with respect to point p0
2950 // make it inline and use a straight return to facilitate optimization
2951 // also, the function receives the sine and cosine of the angle to avoid
2952 // repeating the time-consuming calls to these functions -- sin/cos can
2953 // be computed and stored in the calling function.
2955 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2957 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
2958 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
2961 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2963 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
2966 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
2969 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
2971 // Create pointer-based array to accelerate access to wxImage's data
2972 unsigned char ** data
= new unsigned char * [GetHeight()];
2974 data
[0] = GetData();
2976 for (i
= 1; i
< GetHeight(); i
++)
2977 data
[i
] = data
[i
- 1] + (3 * GetWidth());
2979 // precompute coefficients for rotation formula
2980 // (sine and cosine of the angle)
2981 const double cos_angle
= cos(angle
);
2982 const double sin_angle
= sin(angle
);
2984 // Create new Image to store the result
2985 // First, find rectangle that covers the rotated image; to do that,
2986 // rotate the four corners
2988 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
2990 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
2991 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
2992 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
2993 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
2995 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
2996 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
2997 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
2998 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
3000 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
3002 if (offset_after_rotation
!= NULL
)
3004 *offset_after_rotation
= wxPoint (x1
, y1
);
3007 // GRG: The rotated (destination) image is always accessed
3008 // sequentially, so there is no need for a pointer-based
3009 // array here (and in fact it would be slower).
3011 unsigned char * dst
= rotated
.GetData();
3013 // GRG: if the original image has a mask, use its RGB values
3014 // as the blank pixel, else, fall back to default (black).
3016 unsigned char blank_r
= 0;
3017 unsigned char blank_g
= 0;
3018 unsigned char blank_b
= 0;
3022 blank_r
= GetMaskRed();
3023 blank_g
= GetMaskGreen();
3024 blank_b
= GetMaskBlue();
3025 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
3028 // Now, for each point of the rotated image, find where it came from, by
3029 // performing an inverse rotation (a rotation of -angle) and getting the
3030 // pixel at those coordinates
3032 // GRG: I've taken the (interpolating) test out of the loops, so that
3033 // it is done only once, instead of repeating it for each pixel.
3038 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3040 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3042 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3044 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
3045 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
3047 // interpolate using the 4 enclosing grid-points. Those
3048 // points can be obtained using floor and ceiling of the
3049 // exact coordinates of the point
3050 // C.M. 2000-02-17: when the point is near the border, special care is required.
3054 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
3056 x1
= wxCint(floor(src
.x
));
3057 x2
= wxCint(ceil(src
.x
));
3059 else // else means that x is near one of the borders (0 or width-1)
3061 x1
= x2
= wxCint (src
.x
);
3064 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
3066 y1
= wxCint(floor(src
.y
));
3067 y2
= wxCint(ceil(src
.y
));
3071 y1
= y2
= wxCint (src
.y
);
3074 // get four points and the distances (square of the distance,
3075 // for efficiency reasons) for the interpolation formula
3077 // GRG: Do not calculate the points until they are
3078 // really needed -- this way we can calculate
3079 // just one, instead of four, if d1, d2, d3
3080 // or d4 are < gs_Epsilon
3082 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
3083 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
3084 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
3085 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
3087 // Now interpolate as a weighted average of the four surrounding
3088 // points, where the weights are the distances to each of those points
3090 // If the point is exactly at one point of the grid of the source
3091 // image, then don't interpolate -- just assign the pixel
3093 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
3095 unsigned char *p
= data
[y1
] + (3 * x1
);
3100 else if (d2
< gs_Epsilon
)
3102 unsigned char *p
= data
[y1
] + (3 * x2
);
3107 else if (d3
< gs_Epsilon
)
3109 unsigned char *p
= data
[y2
] + (3 * x2
);
3114 else if (d4
< gs_Epsilon
)
3116 unsigned char *p
= data
[y2
] + (3 * x1
);
3123 // weights for the weighted average are proportional to the inverse of the distance
3124 unsigned char *v1
= data
[y1
] + (3 * x1
);
3125 unsigned char *v2
= data
[y1
] + (3 * x2
);
3126 unsigned char *v3
= data
[y2
] + (3 * x2
);
3127 unsigned char *v4
= data
[y2
] + (3 * x1
);
3129 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
3133 *(dst
++) = (unsigned char)
3134 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3135 w3
* *(v3
++) + w4
* *(v4
++)) /
3136 (w1
+ w2
+ w3
+ w4
) );
3137 *(dst
++) = (unsigned char)
3138 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3139 w3
* *(v3
++) + w4
* *(v4
++)) /
3140 (w1
+ w2
+ w3
+ w4
) );
3141 *(dst
++) = (unsigned char)
3142 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3143 w3
* *(v3
++) + w4
* *(v4
++)) /
3144 (w1
+ w2
+ w3
+ w4
) );
3156 else // not interpolating
3158 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3160 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3162 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3164 const int xs
= wxCint (src
.x
); // wxCint rounds to the
3165 const int ys
= wxCint (src
.y
); // closest integer
3167 if (0 <= xs
&& xs
< GetWidth() &&
3168 0 <= ys
&& ys
< GetHeight())
3170 unsigned char *p
= data
[ys
] + (3 * xs
);