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 <QD/PictUtils.h>
1407 #include <PictUtils.h>
1410 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1411 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1412 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1413 extern GWorldPtr
wxMacCreateGWorld( int width
, int height
, int depth
) ;
1414 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1416 wxBitmap
wxImage::ConvertToBitmap() const
1418 // width and height of the device-dependent bitmap
1419 int width
= GetWidth();
1420 int height
= GetHeight();
1424 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1431 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1433 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1435 wxMask *mask = new wxMask();
1436 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1438 bitmap.SetMask( mask );
1444 int r_mask
= GetMaskRed();
1445 int g_mask
= GetMaskGreen();
1446 int b_mask
= GetMaskBlue();
1449 GDHandle origDevice
;
1451 GetGWorld( &origPort
, &origDevice
) ;
1452 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1454 register unsigned char* data
= GetData();
1457 for (int y
= 0; y
< height
; y
++)
1459 for (int x
= 0; x
< width
; x
++)
1461 unsigned char r
= data
[index
++];
1462 unsigned char g
= data
[index
++];
1463 unsigned char b
= data
[index
++];
1465 color
.red
= ( r
<< 8 ) + r
;
1466 color
.green
= ( g
<< 8 ) + g
;
1467 color
.blue
= ( b
<< 8 ) + b
;
1468 SetCPixel( x
, y
, &color
) ;
1472 SetGWorld( origPort
, origDevice
) ;
1476 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1477 wxMask
*mask
= new wxMask( bitmap
, colour
);
1478 bitmap
.SetMask( mask
);
1484 wxImage::wxImage( const wxBitmap
&bitmap
)
1489 wxFAIL_MSG( "invalid bitmap" );
1493 // create an wxImage object
1494 int width
= bitmap
.GetWidth();
1495 int height
= bitmap
.GetHeight();
1496 Create( width
, height
);
1498 unsigned char *data = GetData();
1501 wxFAIL_MSG( "could not allocate data for image" );
1505 // calc the number of bytes per scanline and padding in the DIB
1506 int bytePerLine = width*3;
1507 int sizeDWORD = sizeof( DWORD );
1508 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1510 if( lineBoundary.rem > 0 )
1512 padding = sizeDWORD - lineBoundary.rem;
1513 bytePerLine += padding;
1516 // create a DIB header
1517 int headersize = sizeof(BITMAPINFOHEADER);
1518 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1521 wxFAIL_MSG( "could not allocate data for DIB header" );
1525 // Fill in the DIB header
1526 lpDIBh->bmiHeader.biSize = headersize;
1527 lpDIBh->bmiHeader.biWidth = width;
1528 lpDIBh->bmiHeader.biHeight = -height;
1529 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1530 lpDIBh->bmiHeader.biPlanes = 1;
1531 lpDIBh->bmiHeader.biBitCount = 24;
1532 lpDIBh->bmiHeader.biCompression = BI_RGB;
1533 lpDIBh->bmiHeader.biClrUsed = 0;
1534 // These seem not really needed for our purpose here.
1535 lpDIBh->bmiHeader.biClrImportant = 0;
1536 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1537 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1538 // memory for DIB data
1539 unsigned char *lpBits;
1540 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1543 wxFAIL_MSG( "could not allocate data for DIB" );
1549 // copy data from the device-dependent bitmap to the DIB
1550 HDC hdc = ::GetDC(NULL);
1552 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1553 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1555 // copy DIB data into the wxImage object
1557 unsigned char *ptdata = data;
1558 unsigned char *ptbits = lpBits;
1559 for( i=0; i<height; i++ )
1561 for( j=0; j<width; j++ )
1563 *(ptdata++) = *(ptbits+2);
1564 *(ptdata++) = *(ptbits+1);
1565 *(ptdata++) = *(ptbits );
1571 // similarly, set data according to the possible mask bitmap
1572 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1574 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1575 // memory DC created, color set, data copied, and memory DC deleted
1576 HDC memdc = ::CreateCompatibleDC( hdc );
1577 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1578 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1579 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1580 ::DeleteDC( memdc );
1581 // background color set to RGB(16,16,16) in consistent with wxGTK
1582 unsigned char r=16, g=16, b=16;
1585 for( i=0; i<height; i++ )
1587 for( j=0; j<width; j++ )
1601 SetMaskColour( r, g, b );
1608 // free allocated resources
1609 ::ReleaseDC(NULL, hdc);
1617 //-----------------------------------------------------------------------------
1618 // GTK conversion routines
1619 //-----------------------------------------------------------------------------
1623 #include <gtk/gtk.h>
1624 #include <gdk/gdk.h>
1625 #include <gdk/gdkx.h>
1627 #if (GTK_MINOR_VERSION > 0)
1628 #include <gdk/gdkrgb.h>
1631 extern GtkWidget
*wxRootWindow
;
1633 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1637 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1639 int width
= GetWidth();
1640 int height
= GetHeight();
1642 bitmap
.SetHeight( height
);
1643 bitmap
.SetWidth( width
);
1645 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1647 bitmap
.SetDepth( 1 );
1649 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1652 // Create picture image
1654 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1656 GdkImage
*data_image
=
1657 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1659 // Create mask image
1661 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1665 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1667 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1669 wxMask
*mask
= new wxMask();
1670 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1672 bitmap
.SetMask( mask
);
1675 int r_mask
= GetMaskRed();
1676 int g_mask
= GetMaskGreen();
1677 int b_mask
= GetMaskBlue();
1679 unsigned char* data
= GetData();
1682 for (int y
= 0; y
< height
; y
++)
1684 for (int x
= 0; x
< width
; x
++)
1686 int r
= data
[index
];
1688 int g
= data
[index
];
1690 int b
= data
[index
];
1695 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1696 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1698 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1701 if ((r
== red
) && (b
== blue
) && (g
== green
))
1702 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1704 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1711 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1713 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1715 gdk_image_destroy( data_image
);
1716 gdk_gc_unref( data_gc
);
1722 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1724 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1726 gdk_image_destroy( mask_image
);
1727 gdk_gc_unref( mask_gc
);
1734 wxBitmap
wxImage::ConvertToBitmap() const
1738 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1740 int width
= GetWidth();
1741 int height
= GetHeight();
1743 bitmap
.SetHeight( height
);
1744 bitmap
.SetWidth( width
);
1746 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1750 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1753 int bpp
= visual
->depth
;
1755 bitmap
.SetDepth( bpp
);
1757 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1758 if (bpp
< 8) bpp
= 8;
1760 #if (GTK_MINOR_VERSION > 0)
1762 if (!HasMask() && (bpp
> 8))
1764 static bool s_hasInitialized
= FALSE
;
1766 if (!s_hasInitialized
)
1769 s_hasInitialized
= TRUE
;
1772 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1774 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1778 GDK_RGB_DITHER_NONE
,
1789 // Create picture image
1791 GdkImage
*data_image
=
1792 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1794 // Create mask image
1796 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1800 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1802 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1804 wxMask
*mask
= new wxMask();
1805 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1807 bitmap
.SetMask( mask
);
1812 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1813 byte_order b_o
= RGB
;
1817 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1818 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1819 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1820 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1821 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1822 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1825 int r_mask
= GetMaskRed();
1826 int g_mask
= GetMaskGreen();
1827 int b_mask
= GetMaskBlue();
1829 unsigned char* data
= GetData();
1832 for (int y
= 0; y
< height
; y
++)
1834 for (int x
= 0; x
< width
; x
++)
1836 int r
= data
[index
];
1838 int g
= data
[index
];
1840 int b
= data
[index
];
1845 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1846 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1848 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1856 if (wxTheApp
->m_colorCube
)
1858 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1862 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1863 GdkColor
*colors
= cmap
->colors
;
1864 int max
= 3 * (65536);
1866 for (int i
= 0; i
< cmap
->size
; i
++)
1868 int rdiff
= (r
<< 8) - colors
[i
].red
;
1869 int gdiff
= (g
<< 8) - colors
[i
].green
;
1870 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1871 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1872 if (sum
< max
) { pixel
= i
; max
= sum
; }
1876 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1882 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1883 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1888 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1889 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1898 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1899 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1900 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1901 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1902 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1903 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1905 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1914 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1916 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1918 gdk_image_destroy( data_image
);
1919 gdk_gc_unref( data_gc
);
1925 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1927 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1929 gdk_image_destroy( mask_image
);
1930 gdk_gc_unref( mask_gc
);
1936 wxImage::wxImage( const wxBitmap
&bitmap
)
1938 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1940 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1941 if (bitmap
.GetPixmap())
1943 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1945 bitmap
.GetWidth(), bitmap
.GetHeight() );
1947 if (bitmap
.GetBitmap())
1949 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1951 bitmap
.GetWidth(), bitmap
.GetHeight() );
1954 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1957 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1959 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1960 char unsigned *data
= GetData();
1964 gdk_image_destroy( gdk_image
);
1965 wxFAIL_MSG( wxT("couldn't create image") );
1969 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1970 if (bitmap
.GetMask())
1972 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1974 bitmap
.GetWidth(), bitmap
.GetHeight() );
1976 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1980 int red_shift_right
= 0;
1981 int green_shift_right
= 0;
1982 int blue_shift_right
= 0;
1983 int red_shift_left
= 0;
1984 int green_shift_left
= 0;
1985 int blue_shift_left
= 0;
1986 bool use_shift
= FALSE
;
1988 if (bitmap
.GetPixmap())
1990 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1992 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1993 bpp
= visual
->depth
;
1994 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1995 red_shift_right
= visual
->red_shift
;
1996 red_shift_left
= 8-visual
->red_prec
;
1997 green_shift_right
= visual
->green_shift
;
1998 green_shift_left
= 8-visual
->green_prec
;
1999 blue_shift_right
= visual
->blue_shift
;
2000 blue_shift_left
= 8-visual
->blue_prec
;
2002 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
2004 if (bitmap
.GetBitmap())
2010 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
2013 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2015 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2017 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
2035 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
2036 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
2037 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
2039 else if (cmap
->colors
)
2041 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
2042 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
2043 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
2047 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
2052 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
2053 if (mask_pixel
== 0)
2065 gdk_image_destroy( gdk_image
);
2066 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
2071 //-----------------------------------------------------------------------------
2072 // Motif conversion routines
2073 //-----------------------------------------------------------------------------
2077 #pragma message disable nosimpint
2081 #pragma message enable nosimpint
2083 #include "wx/utils.h"
2088 Date: Wed, 05 Jan 2000 11:45:40 +0100
2089 From: Frits Boel <boel@niob.knaw.nl>
2090 To: julian.smart@ukonline.co.uk
2091 Subject: Patch for Motif ConvertToBitmap
2095 I've been working on a wxWin application for image processing. From the
2096 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
2097 till I looked in the source code of image.cpp. I saw that converting a
2098 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
2099 to the 256 colors of the palet. A very time-consuming piece of code!
2101 Because I wanted a faster application, I've made a 'patch' for this. In
2102 short: every pixel of the image is compared to a sorted list with
2103 colors. If the color is found in the list, the palette entry is
2104 returned; if the color is not found, the color palette is searched and
2105 then the palette entry is returned and the color added to the sorted
2108 Maybe there is another method for this, namely changing the palette
2109 itself (if the colors are known, as is the case with tiffs with a
2110 colormap). I did not look at this, maybe someone else did?
2112 The code of the patch is attached, have a look on it, and maybe you will
2113 ship it with the next release of wxMotif?
2118 Software engineer at Hubrecht Laboratory, The Netherlands.
2125 wxSearchColor( void );
2126 wxSearchColor( int size
, XColor
*colors
);
2127 ~wxSearchColor( void );
2129 int SearchColor( int r
, int g
, int b
);
2131 int AddColor( unsigned int value
, int pos
);
2135 unsigned int *color
;
2142 wxSearchColor::wxSearchColor( void )
2145 colors
= (XColor
*) NULL
;
2146 color
= (unsigned int *) NULL
;
2147 entry
= (int*) NULL
;
2153 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
2158 color
= new unsigned int[size
];
2159 entry
= new int [size
];
2161 for (i
= 0; i
< size
; i
++ ) {
2165 bottom
= top
= ( size
>> 1 );
2168 wxSearchColor::~wxSearchColor( void )
2170 if ( color
) delete color
;
2171 if ( entry
) delete entry
;
2174 int wxSearchColor::SearchColor( int r
, int g
, int b
)
2176 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
2181 while ( begin
<= end
) {
2183 middle
= ( begin
+ end
) >> 1;
2185 if ( value
== color
[middle
] ) {
2186 return( entry
[middle
] );
2187 } else if ( value
< color
[middle
] ) {
2195 return AddColor( value
, middle
);
2198 int wxSearchColor::AddColor( unsigned int value
, int pos
)
2202 int max
= 3 * (65536);
2203 for ( i
= 0; i
< 256; i
++ ) {
2204 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
2205 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
2206 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
2207 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2208 if (sum
< max
) { pixel
= i
; max
= sum
; }
2211 if ( entry
[pos
] < 0 ) {
2214 } else if ( value
< color
[pos
] ) {
2217 for ( i
= bottom
; i
< pos
; i
++ ) {
2218 color
[i
-1] = color
[i
];
2219 entry
[i
-1] = entry
[i
];
2222 color
[pos
-1] = value
;
2223 entry
[pos
-1] = pixel
;
2224 } else if ( top
< size
-1 ) {
2225 for ( i
= top
; i
>= pos
; i
-- ) {
2226 color
[i
+1] = color
[i
];
2227 entry
[i
+1] = entry
[i
];
2236 if ( top
< size
-1 ) {
2237 for ( i
= top
; i
> pos
; i
-- ) {
2238 color
[i
+1] = color
[i
];
2239 entry
[i
+1] = entry
[i
];
2242 color
[pos
+1] = value
;
2243 entry
[pos
+1] = pixel
;
2244 } else if ( bottom
> 0 ) {
2245 for ( i
= bottom
; i
< pos
; i
++ ) {
2246 color
[i
-1] = color
[i
];
2247 entry
[i
-1] = entry
[i
];
2259 wxBitmap
wxImage::ConvertToBitmap() const
2263 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
2265 int width
= GetWidth();
2266 int height
= GetHeight();
2268 bitmap
.SetHeight( height
);
2269 bitmap
.SetWidth( width
);
2271 Display
*dpy
= (Display
*) wxGetDisplay();
2272 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2273 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2277 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2278 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
2280 bitmap
.Create( width
, height
, bpp
);
2284 XImage
*mask_image
= (XImage
*) NULL
;
2287 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2288 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
2291 // Retrieve depth info
2293 XVisualInfo vinfo_template
;
2296 vinfo_template
.visual
= vis
;
2297 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2298 vinfo_template
.depth
= bpp
;
2301 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2303 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
2307 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2308 if (bpp
< 8) bpp
= 8;
2312 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
2313 byte_order b_o
= RGB
;
2317 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2318 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2319 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2320 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2321 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2322 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2325 int r_mask
= GetMaskRed();
2326 int g_mask
= GetMaskGreen();
2327 int b_mask
= GetMaskBlue();
2332 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2334 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2335 XQueryColors( dpy
, cmap
, colors
, 256 );
2338 wxSearchColor
scolor( 256, colors
);
2339 unsigned char* data
= GetData();
2341 bool hasMask
= HasMask();
2344 for (int y
= 0; y
< height
; y
++)
2346 for (int x
= 0; x
< width
; x
++)
2348 int r
= data
[index
];
2350 int g
= data
[index
];
2352 int b
= data
[index
];
2357 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2358 XPutPixel( mask_image
, x
, y
, 0 );
2360 XPutPixel( mask_image
, x
, y
, 1 );
2367 #if 0 // Old, slower code
2370 if (wxTheApp->m_colorCube)
2372 pixel = wxTheApp->m_colorCube
2373 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2378 int max
= 3 * (65536);
2379 for (int i
= 0; i
< 256; i
++)
2381 int rdiff
= (r
<< 8) - colors
[i
].red
;
2382 int gdiff
= (g
<< 8) - colors
[i
].green
;
2383 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2384 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2385 if (sum
< max
) { pixel
= i
; max
= sum
; }
2392 // And this is all to get the 'right' color...
2393 int pixel
= scolor
.SearchColor( r
, g
, b
);
2394 XPutPixel( data_image
, x
, y
, pixel
);
2399 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2400 XPutPixel( data_image
, x
, y
, pixel
);
2405 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2406 XPutPixel( data_image
, x
, y
, pixel
);
2415 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2416 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2417 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2418 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2419 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2420 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2422 XPutPixel( data_image
, x
, y
, pixel
);
2432 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2433 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2434 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2436 XDestroyImage( data_image
);
2442 wxBitmap
maskBitmap(width
, height
, 1);
2444 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2445 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2447 XDestroyImage( mask_image
);
2448 XFreeGC( dpy
, gcMask
);
2450 wxMask
* mask
= new wxMask
;
2451 mask
->SetPixmap(maskBitmap
.GetPixmap());
2453 bitmap
.SetMask(mask
);
2455 maskBitmap
.SetPixmapNull();
2461 wxImage::wxImage( const wxBitmap
&bitmap
)
2463 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2465 Display
*dpy
= (Display
*) wxGetDisplay();
2466 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2467 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2469 XImage
*ximage
= XGetImage( dpy
,
2470 (Drawable
)bitmap
.GetPixmap(),
2472 bitmap
.GetWidth(), bitmap
.GetHeight(),
2473 AllPlanes
, ZPixmap
);
2475 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2477 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2478 char unsigned *data
= GetData();
2482 XDestroyImage( ximage
);
2483 wxFAIL_MSG( wxT("couldn't create image") );
2488 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2489 if (bitmap.GetMask())
2491 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2493 bitmap.GetWidth(), bitmap.GetHeight() );
2495 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2499 // Retrieve depth info
2501 XVisualInfo vinfo_template
;
2504 vinfo_template
.visual
= vis
;
2505 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2506 vinfo_template
.depth
= bpp
;
2509 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2511 wxCHECK_RET( vi
, wxT("no visual") );
2513 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2520 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2522 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2523 XQueryColors( dpy
, cmap
, colors
, 256 );
2527 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2529 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2531 int pixel
= XGetPixel( ximage
, i
, j
);
2534 data
[pos
] = colors
[pixel
].red
>> 8;
2535 data
[pos
+1] = colors
[pixel
].green
>> 8;
2536 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2537 } else if (bpp
== 15)
2539 data
[pos
] = (pixel
>> 7) & 0xf8;
2540 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2541 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2542 } else if (bpp
== 16)
2544 data
[pos
] = (pixel
>> 8) & 0xf8;
2545 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2546 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2549 data
[pos
] = (pixel
>> 16) & 0xff;
2550 data
[pos
+1] = (pixel
>> 8) & 0xff;
2551 data
[pos
+2] = pixel
& 0xff;
2557 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2558 if (mask_pixel == 0)
2571 XDestroyImage( ximage
);
2573 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2579 // OS/2 Presentation manager conversion routings
2581 wxBitmap
wxImage::ConvertToBitmap() const
2584 return wxNullBitmap
;
2585 wxBitmap bitmap
; // remove
2588 int sizeLimit = 1024*768*3;
2590 // width and height of the device-dependent bitmap
2591 int width = GetWidth();
2592 int bmpHeight = GetHeight();
2594 // calc the number of bytes per scanline and padding
2595 int bytePerLine = width*3;
2596 int sizeDWORD = sizeof( DWORD );
2597 int lineBoundary = bytePerLine % sizeDWORD;
2599 if( lineBoundary > 0 )
2601 padding = sizeDWORD - lineBoundary;
2602 bytePerLine += padding;
2604 // calc the number of DIBs and heights of DIBs
2607 int height = sizeLimit/bytePerLine;
2608 if( height >= bmpHeight )
2612 numDIB = bmpHeight / height;
2613 hRemain = bmpHeight % height;
2614 if( hRemain >0 ) numDIB++;
2617 // set bitmap parameters
2619 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2620 bitmap.SetWidth( width );
2621 bitmap.SetHeight( bmpHeight );
2622 bitmap.SetDepth( wxDisplayDepth() );
2624 // create a DIB header
2625 int headersize = sizeof(BITMAPINFOHEADER);
2626 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2627 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2628 // Fill in the DIB header
2629 lpDIBh->bmiHeader.biSize = headersize;
2630 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2631 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2632 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2633 // the general formula for biSizeImage:
2634 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2635 lpDIBh->bmiHeader.biPlanes = 1;
2636 lpDIBh->bmiHeader.biBitCount = 24;
2637 lpDIBh->bmiHeader.biCompression = BI_RGB;
2638 lpDIBh->bmiHeader.biClrUsed = 0;
2639 // These seem not really needed for our purpose here.
2640 lpDIBh->bmiHeader.biClrImportant = 0;
2641 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2642 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2643 // memory for DIB data
2644 unsigned char *lpBits;
2645 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2648 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2653 // create and set the device-dependent bitmap
2654 HDC hdc = ::GetDC(NULL);
2655 HDC memdc = ::CreateCompatibleDC( hdc );
2657 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2658 ::SelectObject( memdc, hbitmap);
2660 // copy image data into DIB data and then into DDB (in a loop)
2661 unsigned char *data = GetData();
2664 unsigned char *ptdata = data;
2665 unsigned char *ptbits;
2667 for( n=0; n<numDIB; n++ )
2669 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2671 // redefine height and size of the (possibly) last smaller DIB
2672 // memory is not reallocated
2674 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2675 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2679 for( j=0; j<height; j++ )
2681 for( i=0; i<width; i++ )
2683 *(ptbits++) = *(ptdata+2);
2684 *(ptbits++) = *(ptdata+1);
2685 *(ptbits++) = *(ptdata );
2688 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2690 ::StretchDIBits( memdc, 0, origin, width, height,\
2691 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2693 // if numDIB = 1, lines below can also be used
2694 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2695 // The above line is equivalent to the following two lines.
2696 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2697 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2698 // or the following lines
2699 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2700 // HDC memdc = ::CreateCompatibleDC( hdc );
2701 // ::SelectObject( memdc, hbitmap);
2702 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2703 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2704 // ::SelectObject( memdc, 0 );
2705 // ::DeleteDC( memdc );
2707 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2709 // similarly, created an mono-bitmap for the possible mask
2712 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2713 ::SelectObject( memdc, hbitmap);
2714 if( numDIB == 1 ) height = bmpHeight;
2715 else height = sizeLimit/bytePerLine;
2716 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2717 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2719 unsigned char r = GetMaskRed();
2720 unsigned char g = GetMaskGreen();
2721 unsigned char b = GetMaskBlue();
2722 unsigned char zero = 0, one = 255;
2724 for( n=0; n<numDIB; n++ )
2726 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2728 // redefine height and size of the (possibly) last smaller DIB
2729 // memory is not reallocated
2731 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2732 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2735 for( int j=0; j<height; j++ )
2737 for(i=0; i<width; i++ )
2739 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2752 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2754 ::StretchDIBits( memdc, 0, origin, width, height,\
2755 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2758 // create a wxMask object
2759 wxMask *mask = new wxMask();
2760 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2761 bitmap.SetMask( mask );
2764 // free allocated resources
2765 ::SelectObject( memdc, 0 );
2766 ::DeleteDC( memdc );
2767 ::ReleaseDC(NULL, hdc);
2771 // check the wxBitmap object
2772 if( bitmap.GetHBITMAP() )
2773 bitmap.SetOk( TRUE );
2775 bitmap.SetOk( FALSE );
2780 wxImage::wxImage( const wxBitmap
&bitmap
)
2785 wxFAIL_MSG( wxT("invalid bitmap") );
2789 // create an wxImage object
2790 int width
= bitmap
.GetWidth();
2791 int height
= bitmap
.GetHeight();
2792 Create( width
, height
);
2793 unsigned char *data
= GetData();
2796 wxFAIL_MSG( wxT("could not allocate data for image") );
2800 // calc the number of bytes per scanline and padding in the DIB
2801 int bytePerLine
= width
*3;
2802 int sizeDWORD
= sizeof( DWORD
);
2803 int lineBoundary
= bytePerLine
% sizeDWORD
;
2805 if( lineBoundary
> 0 )
2807 padding
= sizeDWORD
- lineBoundary
;
2808 bytePerLine
+= padding
;
2812 // create a DIB header
2813 int headersize = sizeof(BITMAPINFOHEADER);
2814 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2817 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2821 // Fill in the DIB header
2822 lpDIBh->bmiHeader.biSize = headersize;
2823 lpDIBh->bmiHeader.biWidth = width;
2824 lpDIBh->bmiHeader.biHeight = -height;
2825 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2826 lpDIBh->bmiHeader.biPlanes = 1;
2827 lpDIBh->bmiHeader.biBitCount = 24;
2828 lpDIBh->bmiHeader.biCompression = BI_RGB;
2829 lpDIBh->bmiHeader.biClrUsed = 0;
2830 // These seem not really needed for our purpose here.
2831 lpDIBh->bmiHeader.biClrImportant = 0;
2832 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2833 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2834 // memory for DIB data
2835 unsigned char *lpBits;
2836 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2839 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2845 // copy data from the device-dependent bitmap to the DIB
2846 HDC hdc = ::GetDC(NULL);
2848 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2849 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2851 // copy DIB data into the wxImage object
2853 unsigned char *ptdata = data;
2854 unsigned char *ptbits = lpBits;
2855 for( i=0; i<height; i++ )
2857 for( j=0; j<width; j++ )
2859 *(ptdata++) = *(ptbits+2);
2860 *(ptdata++) = *(ptbits+1);
2861 *(ptdata++) = *(ptbits );
2867 // similarly, set data according to the possible mask bitmap
2868 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2870 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2871 // memory DC created, color set, data copied, and memory DC deleted
2872 HDC memdc = ::CreateCompatibleDC( hdc );
2873 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2874 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2875 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2876 ::DeleteDC( memdc );
2877 // background color set to RGB(16,16,16) in consistent with wxGTK
2878 unsigned char r=16, g=16, b=16;
2881 for( i=0; i<height; i++ )
2883 for( j=0; j<width; j++ )
2897 SetMaskColour( r, g, b );
2904 // free allocated resources
2905 ::ReleaseDC(NULL, hdc);
2913 // A module to allow wxImage initialization/cleanup
2914 // without calling these functions from app.cpp or from
2915 // the user's application.
2917 class wxImageModule
: public wxModule
2919 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2922 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2923 void OnExit() { wxImage::CleanUpHandlers(); };
2926 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2929 //-----------------------------------------------------------------------------
2932 // Counts and returns the number of different colours. Optionally stops
2933 // when it exceeds 'stopafter' different colours. This is useful, for
2934 // example, to see if the image can be saved as 8-bit (256 colour or
2935 // less, in this case it would be invoked as CountColours(256)). Default
2936 // value for stopafter is -1 (don't care).
2938 unsigned long wxImage::CountColours( unsigned long stopafter
)
2942 unsigned char r
, g
, b
, *p
;
2943 unsigned long size
, nentries
, key
;
2946 size
= GetWidth() * GetHeight();
2949 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2954 key
= (r
<< 16) | (g
<< 8) | b
;
2956 if (h
.Get(key
) == NULL
)
2968 // Computes the histogram of the image and fills a hash table, indexed
2969 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2970 // wxHNode contains an 'index' (useful to build a palette with the image
2971 // colours) and a 'value', which is the number of pixels in the image with
2974 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2976 unsigned char r
, g
, b
, *p
;
2977 unsigned long size
, nentries
, key
;
2981 size
= GetWidth() * GetHeight();
2984 for (unsigned long j
= 0; j
< size
; j
++)
2989 key
= (r
<< 16) | (g
<< 8) | b
;
2991 hnode
= (wxHNode
*) h
.Get(key
);
2997 hnode
= new wxHNode();
2998 hnode
->index
= nentries
++;
3001 h
.Put(key
, (wxObject
*)hnode
);
3009 * Rotation code by Carlos Moreno
3012 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
3013 // does exactly the same thing. And I also got rid of wxRotationPixel
3014 // bacause of potential problems in architectures where alignment
3015 // is an issue, so I had to rewrite parts of the code.
3017 static const double gs_Epsilon
= 1e-10;
3019 static inline int wxCint (double x
)
3021 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
3025 // Auxiliary function to rotate a point (x,y) with respect to point p0
3026 // make it inline and use a straight return to facilitate optimization
3027 // also, the function receives the sine and cosine of the angle to avoid
3028 // repeating the time-consuming calls to these functions -- sin/cos can
3029 // be computed and stored in the calling function.
3031 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
3033 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
3034 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
3037 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
3039 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
3042 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
3045 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
3047 // Create pointer-based array to accelerate access to wxImage's data
3048 unsigned char ** data
= new unsigned char * [GetHeight()];
3050 data
[0] = GetData();
3052 for (i
= 1; i
< GetHeight(); i
++)
3053 data
[i
] = data
[i
- 1] + (3 * GetWidth());
3055 // precompute coefficients for rotation formula
3056 // (sine and cosine of the angle)
3057 const double cos_angle
= cos(angle
);
3058 const double sin_angle
= sin(angle
);
3060 // Create new Image to store the result
3061 // First, find rectangle that covers the rotated image; to do that,
3062 // rotate the four corners
3064 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
3066 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
3067 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
3068 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
3069 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
3071 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
3072 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
3073 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
3074 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
3076 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
3078 if (offset_after_rotation
!= NULL
)
3080 *offset_after_rotation
= wxPoint (x1
, y1
);
3083 // GRG: The rotated (destination) image is always accessed
3084 // sequentially, so there is no need for a pointer-based
3085 // array here (and in fact it would be slower).
3087 unsigned char * dst
= rotated
.GetData();
3089 // GRG: if the original image has a mask, use its RGB values
3090 // as the blank pixel, else, fall back to default (black).
3092 unsigned char blank_r
= 0;
3093 unsigned char blank_g
= 0;
3094 unsigned char blank_b
= 0;
3098 blank_r
= GetMaskRed();
3099 blank_g
= GetMaskGreen();
3100 blank_b
= GetMaskBlue();
3101 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
3104 // Now, for each point of the rotated image, find where it came from, by
3105 // performing an inverse rotation (a rotation of -angle) and getting the
3106 // pixel at those coordinates
3108 // GRG: I've taken the (interpolating) test out of the loops, so that
3109 // it is done only once, instead of repeating it for each pixel.
3114 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3116 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3118 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3120 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
3121 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
3123 // interpolate using the 4 enclosing grid-points. Those
3124 // points can be obtained using floor and ceiling of the
3125 // exact coordinates of the point
3126 // C.M. 2000-02-17: when the point is near the border, special care is required.
3130 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
3132 x1
= wxCint(floor(src
.x
));
3133 x2
= wxCint(ceil(src
.x
));
3135 else // else means that x is near one of the borders (0 or width-1)
3137 x1
= x2
= wxCint (src
.x
);
3140 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
3142 y1
= wxCint(floor(src
.y
));
3143 y2
= wxCint(ceil(src
.y
));
3147 y1
= y2
= wxCint (src
.y
);
3150 // get four points and the distances (square of the distance,
3151 // for efficiency reasons) for the interpolation formula
3153 // GRG: Do not calculate the points until they are
3154 // really needed -- this way we can calculate
3155 // just one, instead of four, if d1, d2, d3
3156 // or d4 are < gs_Epsilon
3158 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
3159 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
3160 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
3161 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
3163 // Now interpolate as a weighted average of the four surrounding
3164 // points, where the weights are the distances to each of those points
3166 // If the point is exactly at one point of the grid of the source
3167 // image, then don't interpolate -- just assign the pixel
3169 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
3171 unsigned char *p
= data
[y1
] + (3 * x1
);
3176 else if (d2
< gs_Epsilon
)
3178 unsigned char *p
= data
[y1
] + (3 * x2
);
3183 else if (d3
< gs_Epsilon
)
3185 unsigned char *p
= data
[y2
] + (3 * x2
);
3190 else if (d4
< gs_Epsilon
)
3192 unsigned char *p
= data
[y2
] + (3 * x1
);
3199 // weights for the weighted average are proportional to the inverse of the distance
3200 unsigned char *v1
= data
[y1
] + (3 * x1
);
3201 unsigned char *v2
= data
[y1
] + (3 * x2
);
3202 unsigned char *v3
= data
[y2
] + (3 * x2
);
3203 unsigned char *v4
= data
[y2
] + (3 * x1
);
3205 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
3209 *(dst
++) = (unsigned char)
3210 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3211 w3
* *(v3
++) + w4
* *(v4
++)) /
3212 (w1
+ w2
+ w3
+ w4
) );
3213 *(dst
++) = (unsigned char)
3214 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3215 w3
* *(v3
++) + w4
* *(v4
++)) /
3216 (w1
+ w2
+ w3
+ w4
) );
3217 *(dst
++) = (unsigned char)
3218 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3219 w3
* *(v3
++) + w4
* *(v4
++)) /
3220 (w1
+ w2
+ w3
+ w4
) );
3232 else // not interpolating
3234 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3236 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3238 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3240 const int xs
= wxCint (src
.x
); // wxCint rounds to the
3241 const int ys
= wxCint (src
.y
); // closest integer
3243 if (0 <= xs
&& xs
< GetWidth() &&
3244 0 <= ys
&& ys
< GetHeight())
3246 unsigned char *p
= data
[ys
] + (3 * xs
);