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
;
418 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
419 unsigned char r2
, unsigned char g2
, unsigned char b2
)
421 wxCHECK_RET( Ok(), wxT("invalid image") );
423 char unsigned *data
= GetData();
425 const int w
= GetWidth();
426 const int h
= GetHeight();
428 for (int j
= 0; j
< h
; j
++)
429 for (int i
= 0; i
< w
; i
++)
431 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
441 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
443 wxCHECK_RET( Ok(), wxT("invalid image") );
445 int w
= M_IMGDATA
->m_width
;
446 int h
= M_IMGDATA
->m_height
;
448 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
450 long pos
= (y
* w
+ x
) * 3;
452 M_IMGDATA
->m_data
[ pos
] = r
;
453 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
454 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
457 unsigned char wxImage::GetRed( int x
, int y
) const
459 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
461 int w
= M_IMGDATA
->m_width
;
462 int h
= M_IMGDATA
->m_height
;
464 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
466 long pos
= (y
* w
+ x
) * 3;
468 return M_IMGDATA
->m_data
[pos
];
471 unsigned char wxImage::GetGreen( int x
, int y
) const
473 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
475 int w
= M_IMGDATA
->m_width
;
476 int h
= M_IMGDATA
->m_height
;
478 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
480 long pos
= (y
* w
+ x
) * 3;
482 return M_IMGDATA
->m_data
[pos
+1];
485 unsigned char wxImage::GetBlue( int x
, int y
) const
487 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
489 int w
= M_IMGDATA
->m_width
;
490 int h
= M_IMGDATA
->m_height
;
492 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
494 long pos
= (y
* w
+ x
) * 3;
496 return M_IMGDATA
->m_data
[pos
+2];
499 bool wxImage::Ok() const
501 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
504 char unsigned *wxImage::GetData() const
506 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
508 return M_IMGDATA
->m_data
;
511 void wxImage::SetData( char unsigned *data
)
513 wxCHECK_RET( Ok(), wxT("invalid image") );
515 wxImageRefData
*newRefData
= new wxImageRefData();
517 newRefData
->m_width
= M_IMGDATA
->m_width
;
518 newRefData
->m_height
= M_IMGDATA
->m_height
;
519 newRefData
->m_data
= data
;
520 newRefData
->m_ok
= TRUE
;
521 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
522 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
523 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
524 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
528 m_refData
= newRefData
;
531 void wxImage::SetData( char unsigned *data
, int new_width
, int new_height
)
533 wxImageRefData
*newRefData
= new wxImageRefData();
537 newRefData
->m_width
= new_width
;
538 newRefData
->m_height
= new_height
;
539 newRefData
->m_data
= data
;
540 newRefData
->m_ok
= TRUE
;
541 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
542 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
543 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
544 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
548 newRefData
->m_width
= new_width
;
549 newRefData
->m_height
= new_height
;
550 newRefData
->m_data
= data
;
551 newRefData
->m_ok
= TRUE
;
556 m_refData
= newRefData
;
559 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
561 wxCHECK_RET( Ok(), wxT("invalid image") );
563 M_IMGDATA
->m_maskRed
= r
;
564 M_IMGDATA
->m_maskGreen
= g
;
565 M_IMGDATA
->m_maskBlue
= b
;
566 M_IMGDATA
->m_hasMask
= TRUE
;
569 unsigned char wxImage::GetMaskRed() const
571 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
573 return M_IMGDATA
->m_maskRed
;
576 unsigned char wxImage::GetMaskGreen() const
578 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
580 return M_IMGDATA
->m_maskGreen
;
583 unsigned char wxImage::GetMaskBlue() const
585 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
587 return M_IMGDATA
->m_maskBlue
;
590 void wxImage::SetMask( bool mask
)
592 wxCHECK_RET( Ok(), wxT("invalid image") );
594 M_IMGDATA
->m_hasMask
= mask
;
597 bool wxImage::HasMask() const
599 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
601 return M_IMGDATA
->m_hasMask
;
604 int wxImage::GetWidth() const
606 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
608 return M_IMGDATA
->m_width
;
611 int wxImage::GetHeight() const
613 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
615 return M_IMGDATA
->m_height
;
620 bool wxImage::HasPalette() const
625 return M_IMGDATA
->m_palette
.Ok();
628 const wxPalette
& wxImage::GetPalette() const
630 wxCHECK_MSG( Ok(), wxNullPalette
, wxT("invalid image") );
632 return M_IMGDATA
->m_palette
;
635 void wxImage::SetPalette(const wxPalette
& palette
)
637 wxCHECK_RET( Ok(), wxT("invalid image") );
639 M_IMGDATA
->m_palette
= palette
;
642 // Option functions (arbitrary name/value mapping)
643 void wxImage::SetOption(const wxString
& name
, const wxString
& value
)
645 wxCHECK_RET( Ok(), wxT("invalid image") );
647 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
648 if (idx
== wxNOT_FOUND
)
650 M_IMGDATA
->m_optionNames
.Add(name
);
651 M_IMGDATA
->m_optionValues
.Add(value
);
655 M_IMGDATA
->m_optionNames
[idx
] = name
;
656 M_IMGDATA
->m_optionValues
[idx
] = value
;
660 void wxImage::SetOption(const wxString
& name
, int value
)
663 valStr
.Printf(wxT("%d"), value
);
664 SetOption(name
, valStr
);
667 wxString
wxImage::GetOption(const wxString
& name
) const
669 wxCHECK_MSG( Ok(), wxEmptyString
, wxT("invalid image") );
671 int idx
= M_IMGDATA
->m_optionNames
.Index(name
, FALSE
);
672 if (idx
== wxNOT_FOUND
)
673 return wxEmptyString
;
675 return M_IMGDATA
->m_optionValues
[idx
];
678 int wxImage::GetOptionInt(const wxString
& name
) const
680 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
682 return wxAtoi(GetOption(name
));
685 bool wxImage::HasOption(const wxString
& name
) const
687 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
689 return (M_IMGDATA
->m_optionNames
.Index(name
, FALSE
) != wxNOT_FOUND
);
692 bool wxImage::LoadFile( const wxString
& filename
, long type
)
695 if (wxFileExists(filename
))
697 wxFileInputStream
stream(filename
);
698 wxBufferedInputStream
bstream( stream
);
699 return LoadFile(bstream
, type
);
703 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
707 #else // !wxUSE_STREAMS
709 #endif // wxUSE_STREAMS
712 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
715 if (wxFileExists(filename
))
717 wxFileInputStream
stream(filename
);
718 wxBufferedInputStream
bstream( stream
);
719 return LoadFile(bstream
, mimetype
);
723 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
727 #else // !wxUSE_STREAMS
729 #endif // wxUSE_STREAMS
732 bool wxImage::SaveFile( const wxString
& filename
, int type
)
735 wxFileOutputStream
stream(filename
);
737 if ( stream
.LastError() == wxStream_NOERROR
)
739 wxBufferedOutputStream
bstream( stream
);
740 return SaveFile(bstream
, type
);
742 #endif // wxUSE_STREAMS
747 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
750 wxFileOutputStream
stream(filename
);
752 if ( stream
.LastError() == wxStream_NOERROR
)
754 wxBufferedOutputStream
bstream( stream
);
755 return SaveFile(bstream
, mimetype
);
757 #endif // wxUSE_STREAMS
762 bool wxImage::CanRead( const wxString
&name
)
765 wxFileInputStream
stream(name
);
766 return CanRead(stream
);
774 bool wxImage::CanRead( wxInputStream
&stream
)
776 wxList
&list
=GetHandlers();
778 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
780 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
781 if (handler
->CanRead( stream
))
788 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
792 m_refData
= new wxImageRefData
;
794 wxImageHandler
*handler
;
796 if (type
==wxBITMAP_TYPE_ANY
)
798 wxList
&list
=GetHandlers();
800 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
802 handler
=(wxImageHandler
*)node
->GetData();
803 if (handler
->CanRead( stream
))
804 return handler
->LoadFile( this, stream
);
808 wxLogWarning( _("No handler found for image type.") );
812 handler
= FindHandler(type
);
816 wxLogWarning( _("No image handler for type %d defined."), type
);
821 return handler
->LoadFile( this, stream
);
824 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
828 m_refData
= new wxImageRefData
;
830 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
834 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
839 return handler
->LoadFile( this, stream
);
842 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
844 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
846 wxImageHandler
*handler
= FindHandler(type
);
850 wxLogWarning( _("No image handler for type %d defined."), type
);
855 return handler
->SaveFile( this, stream
);
858 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
860 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
862 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
866 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
871 return handler
->SaveFile( this, stream
);
873 #endif // wxUSE_STREAMS
875 void wxImage::AddHandler( wxImageHandler
*handler
)
877 // make sure that the memory will be freed at the program end
878 sm_handlers
.DeleteContents(TRUE
);
880 sm_handlers
.Append( handler
);
883 void wxImage::InsertHandler( wxImageHandler
*handler
)
885 // make sure that the memory will be freed at the program end
886 sm_handlers
.DeleteContents(TRUE
);
888 sm_handlers
.Insert( handler
);
891 bool wxImage::RemoveHandler( const wxString
& name
)
893 wxImageHandler
*handler
= FindHandler(name
);
896 sm_handlers
.DeleteObject(handler
);
903 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
905 wxNode
*node
= sm_handlers
.First();
908 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
909 if (handler
->GetName().Cmp(name
) == 0) return handler
;
913 return (wxImageHandler
*)NULL
;
916 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
918 wxNode
*node
= sm_handlers
.First();
921 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
922 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
923 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
927 return (wxImageHandler
*)NULL
;
930 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
932 wxNode
*node
= sm_handlers
.First();
935 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
936 if (handler
->GetType() == bitmapType
) return handler
;
942 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
944 wxNode
*node
= sm_handlers
.First();
947 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
948 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
954 void wxImage::InitStandardHandlers()
956 AddHandler( new wxBMPHandler
);
959 void wxImage::CleanUpHandlers()
961 wxNode
*node
= sm_handlers
.First();
964 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
965 wxNode
*next
= node
->Next();
972 //-----------------------------------------------------------------------------
974 //-----------------------------------------------------------------------------
976 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
979 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
984 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
989 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
994 bool wxImageHandler::CanRead( const wxString
& name
)
996 if (wxFileExists(name
))
998 wxFileInputStream
stream(name
);
999 return CanRead(stream
);
1003 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
1010 #endif // wxUSE_STREAMS
1012 //-----------------------------------------------------------------------------
1013 // MSW conversion routines
1014 //-----------------------------------------------------------------------------
1018 wxBitmap
wxImage::ConvertToBitmap() const
1021 return wxNullBitmap
;
1023 // sizeLimit is the MS upper limit for the DIB size
1025 int sizeLimit
= 1024*768*3;
1027 int sizeLimit
= 0x7fff ;
1030 // width and height of the device-dependent bitmap
1031 int width
= GetWidth();
1032 int bmpHeight
= GetHeight();
1034 // calc the number of bytes per scanline and padding
1035 int bytePerLine
= width
*3;
1036 int sizeDWORD
= sizeof( DWORD
);
1037 int lineBoundary
= bytePerLine
% sizeDWORD
;
1039 if( lineBoundary
> 0 )
1041 padding
= sizeDWORD
- lineBoundary
;
1042 bytePerLine
+= padding
;
1044 // calc the number of DIBs and heights of DIBs
1047 int height
= sizeLimit
/bytePerLine
;
1048 if( height
>= bmpHeight
)
1052 numDIB
= bmpHeight
/ height
;
1053 hRemain
= bmpHeight
% height
;
1054 if( hRemain
>0 ) numDIB
++;
1057 // set bitmap parameters
1059 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1060 bitmap
.SetWidth( width
);
1061 bitmap
.SetHeight( bmpHeight
);
1062 bitmap
.SetDepth( wxDisplayDepth() );
1064 // create a DIB header
1065 int headersize
= sizeof(BITMAPINFOHEADER
);
1066 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1067 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
1068 // Fill in the DIB header
1069 lpDIBh
->bmiHeader
.biSize
= headersize
;
1070 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
1071 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1072 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1073 // the general formula for biSizeImage:
1074 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
1075 lpDIBh
->bmiHeader
.biPlanes
= 1;
1076 lpDIBh
->bmiHeader
.biBitCount
= 24;
1077 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1078 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1079 // These seem not really needed for our purpose here.
1080 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1081 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1082 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1083 // memory for DIB data
1084 unsigned char *lpBits
;
1085 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1088 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
1093 // create and set the device-dependent bitmap
1094 HDC hdc
= ::GetDC(NULL
);
1095 HDC memdc
= ::CreateCompatibleDC( hdc
);
1097 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
1098 ::SelectObject( memdc
, hbitmap
);
1100 HPALETTE hOldPalette
= 0;
1101 if (GetPalette().Ok())
1103 hOldPalette
= ::SelectPalette(memdc
, (HPALETTE
) GetPalette().GetHPALETTE(), FALSE
);
1104 ::RealizePalette(memdc
);
1107 // copy image data into DIB data and then into DDB (in a loop)
1108 unsigned char *data
= GetData();
1111 unsigned char *ptdata
= data
;
1112 unsigned char *ptbits
;
1114 for( n
=0; n
<numDIB
; n
++ )
1116 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
1118 // redefine height and size of the (possibly) last smaller DIB
1119 // memory is not reallocated
1121 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1122 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1126 for( j
=0; j
<height
; j
++ )
1128 for( i
=0; i
<width
; i
++ )
1130 *(ptbits
++) = *(ptdata
+2);
1131 *(ptbits
++) = *(ptdata
+1);
1132 *(ptbits
++) = *(ptdata
);
1135 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
1137 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1138 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1140 // if numDIB = 1, lines below can also be used
1141 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1142 // The above line is equivalent to the following two lines.
1143 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1144 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1145 // or the following lines
1146 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1147 // HDC memdc = ::CreateCompatibleDC( hdc );
1148 // ::SelectObject( memdc, hbitmap);
1149 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1150 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1151 // ::SelectObject( memdc, 0 );
1152 // ::DeleteDC( memdc );
1154 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
1157 SelectPalette(memdc
, hOldPalette
, FALSE
);
1159 // similarly, created an mono-bitmap for the possible mask
1162 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
1163 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
1164 if( numDIB
== 1 ) height
= bmpHeight
;
1165 else height
= sizeLimit
/bytePerLine
;
1166 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1167 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1169 unsigned char r
= GetMaskRed();
1170 unsigned char g
= GetMaskGreen();
1171 unsigned char b
= GetMaskBlue();
1172 unsigned char zero
= 0, one
= 255;
1174 for( n
=0; n
<numDIB
; n
++ )
1176 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
1178 // redefine height and size of the (possibly) last smaller DIB
1179 // memory is not reallocated
1181 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1182 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1185 for( int j
=0; j
<height
; j
++ )
1187 for(i
=0; i
<width
; i
++ )
1189 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
1190 unsigned char cr
= (*(ptdata
++)) ;
1191 unsigned char cg
= (*(ptdata
++)) ;
1192 unsigned char cb
= (*(ptdata
++)) ;
1194 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
1207 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
1209 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1210 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1213 // create a wxMask object
1214 wxMask
*mask
= new wxMask();
1215 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
1216 bitmap
.SetMask( mask
);
1217 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1218 /* The following can also be used but is slow to run
1219 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1220 wxMask *mask = new wxMask( bitmap, colour );
1221 bitmap.SetMask( mask );
1224 ::SelectObject( memdc
, hbmpOld
);
1227 // free allocated resources
1228 ::DeleteDC( memdc
);
1229 ::ReleaseDC(NULL
, hdc
);
1233 #if WXWIN_COMPATIBILITY_2
1234 // check the wxBitmap object
1235 bitmap
.GetBitmapData()->SetOk();
1236 #endif // WXWIN_COMPATIBILITY_2
1241 wxImage::wxImage( const wxBitmap
&bitmap
)
1246 wxFAIL_MSG( wxT("invalid bitmap") );
1250 // create an wxImage object
1251 int width
= bitmap
.GetWidth();
1252 int height
= bitmap
.GetHeight();
1253 Create( width
, height
);
1254 unsigned char *data
= GetData();
1257 wxFAIL_MSG( wxT("could not allocate data for image") );
1261 // calc the number of bytes per scanline and padding in the DIB
1262 int bytePerLine
= width
*3;
1263 int sizeDWORD
= sizeof( DWORD
);
1264 int lineBoundary
= bytePerLine
% sizeDWORD
;
1266 if( lineBoundary
> 0 )
1268 padding
= sizeDWORD
- lineBoundary
;
1269 bytePerLine
+= padding
;
1272 // create a DIB header
1273 int headersize
= sizeof(BITMAPINFOHEADER
);
1274 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1277 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1281 // Fill in the DIB header
1282 lpDIBh
->bmiHeader
.biSize
= headersize
;
1283 lpDIBh
->bmiHeader
.biWidth
= width
;
1284 lpDIBh
->bmiHeader
.biHeight
= -height
;
1285 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
1286 lpDIBh
->bmiHeader
.biPlanes
= 1;
1287 lpDIBh
->bmiHeader
.biBitCount
= 24;
1288 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1289 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1290 // These seem not really needed for our purpose here.
1291 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1292 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1293 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1294 // memory for DIB data
1295 unsigned char *lpBits
;
1296 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1299 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1305 // copy data from the device-dependent bitmap to the DIB
1306 HDC hdc
= ::GetDC(NULL
);
1308 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1309 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1311 // copy DIB data into the wxImage object
1313 unsigned char *ptdata
= data
;
1314 unsigned char *ptbits
= lpBits
;
1315 for( i
=0; i
<height
; i
++ )
1317 for( j
=0; j
<width
; j
++ )
1319 *(ptdata
++) = *(ptbits
+2);
1320 *(ptdata
++) = *(ptbits
+1);
1321 *(ptdata
++) = *(ptbits
);
1327 // similarly, set data according to the possible mask bitmap
1328 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1330 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1331 // memory DC created, color set, data copied, and memory DC deleted
1332 HDC memdc
= ::CreateCompatibleDC( hdc
);
1333 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1334 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1335 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1336 ::DeleteDC( memdc
);
1337 // background color set to RGB(16,16,16) in consistent with wxGTK
1338 unsigned char r
=16, g
=16, b
=16;
1341 for( i
=0; i
<height
; i
++ )
1343 for( j
=0; j
<width
; j
++ )
1357 SetMaskColour( r
, g
, b
);
1364 // free allocated resources
1365 ::ReleaseDC(NULL
, hdc
);
1374 #include <PictUtils.h>
1376 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1377 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1378 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1379 extern GWorldPtr
wxMacCreateGWorld( int height
, int width
, int depth
) ;
1380 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1382 wxBitmap
wxImage::ConvertToBitmap() const
1384 // width and height of the device-dependent bitmap
1385 int width
= GetWidth();
1386 int height
= GetHeight();
1390 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1397 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1399 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1401 wxMask *mask = new wxMask();
1402 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1404 bitmap.SetMask( mask );
1410 int r_mask
= GetMaskRed();
1411 int g_mask
= GetMaskGreen();
1412 int b_mask
= GetMaskBlue();
1415 GDHandle origDevice
;
1417 GetGWorld( &origPort
, &origDevice
) ;
1418 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1420 register unsigned char* data
= GetData();
1423 for (int y
= 0; y
< height
; y
++)
1425 for (int x
= 0; x
< width
; x
++)
1427 unsigned char r
= data
[index
++];
1428 unsigned char g
= data
[index
++];
1429 unsigned char b
= data
[index
++];
1431 color
.red
= ( r
<< 8 ) + r
;
1432 color
.green
= ( g
<< 8 ) + g
;
1433 color
.blue
= ( b
<< 8 ) + b
;
1434 SetCPixel( x
, y
, &color
) ;
1438 SetGWorld( origPort
, origDevice
) ;
1442 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1443 wxMask
*mask
= new wxMask( bitmap
, colour
);
1444 bitmap
.SetMask( mask
);
1450 wxImage::wxImage( const wxBitmap
&bitmap
)
1455 wxFAIL_MSG( "invalid bitmap" );
1459 // create an wxImage object
1460 int width
= bitmap
.GetWidth();
1461 int height
= bitmap
.GetHeight();
1462 Create( width
, height
);
1464 unsigned char *data = GetData();
1467 wxFAIL_MSG( "could not allocate data for image" );
1471 // calc the number of bytes per scanline and padding in the DIB
1472 int bytePerLine = width*3;
1473 int sizeDWORD = sizeof( DWORD );
1474 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1476 if( lineBoundary.rem > 0 )
1478 padding = sizeDWORD - lineBoundary.rem;
1479 bytePerLine += padding;
1482 // create a DIB header
1483 int headersize = sizeof(BITMAPINFOHEADER);
1484 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1487 wxFAIL_MSG( "could not allocate data for DIB header" );
1491 // Fill in the DIB header
1492 lpDIBh->bmiHeader.biSize = headersize;
1493 lpDIBh->bmiHeader.biWidth = width;
1494 lpDIBh->bmiHeader.biHeight = -height;
1495 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1496 lpDIBh->bmiHeader.biPlanes = 1;
1497 lpDIBh->bmiHeader.biBitCount = 24;
1498 lpDIBh->bmiHeader.biCompression = BI_RGB;
1499 lpDIBh->bmiHeader.biClrUsed = 0;
1500 // These seem not really needed for our purpose here.
1501 lpDIBh->bmiHeader.biClrImportant = 0;
1502 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1503 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1504 // memory for DIB data
1505 unsigned char *lpBits;
1506 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1509 wxFAIL_MSG( "could not allocate data for DIB" );
1515 // copy data from the device-dependent bitmap to the DIB
1516 HDC hdc = ::GetDC(NULL);
1518 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1519 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1521 // copy DIB data into the wxImage object
1523 unsigned char *ptdata = data;
1524 unsigned char *ptbits = lpBits;
1525 for( i=0; i<height; i++ )
1527 for( j=0; j<width; j++ )
1529 *(ptdata++) = *(ptbits+2);
1530 *(ptdata++) = *(ptbits+1);
1531 *(ptdata++) = *(ptbits );
1537 // similarly, set data according to the possible mask bitmap
1538 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1540 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1541 // memory DC created, color set, data copied, and memory DC deleted
1542 HDC memdc = ::CreateCompatibleDC( hdc );
1543 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1544 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1545 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1546 ::DeleteDC( memdc );
1547 // background color set to RGB(16,16,16) in consistent with wxGTK
1548 unsigned char r=16, g=16, b=16;
1551 for( i=0; i<height; i++ )
1553 for( j=0; j<width; j++ )
1567 SetMaskColour( r, g, b );
1574 // free allocated resources
1575 ::ReleaseDC(NULL, hdc);
1583 //-----------------------------------------------------------------------------
1584 // GTK conversion routines
1585 //-----------------------------------------------------------------------------
1589 #include <gtk/gtk.h>
1590 #include <gdk/gdk.h>
1591 #include <gdk/gdkx.h>
1593 #if (GTK_MINOR_VERSION > 0)
1594 #include <gdk/gdkrgb.h>
1597 extern GtkWidget
*wxRootWindow
;
1599 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1603 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1605 int width
= GetWidth();
1606 int height
= GetHeight();
1608 bitmap
.SetHeight( height
);
1609 bitmap
.SetWidth( width
);
1611 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1613 bitmap
.SetDepth( 1 );
1615 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1618 // Create picture image
1620 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1622 GdkImage
*data_image
=
1623 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1625 // Create mask image
1627 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1631 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1633 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1635 wxMask
*mask
= new wxMask();
1636 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1638 bitmap
.SetMask( mask
);
1641 int r_mask
= GetMaskRed();
1642 int g_mask
= GetMaskGreen();
1643 int b_mask
= GetMaskBlue();
1645 unsigned char* data
= GetData();
1648 for (int y
= 0; y
< height
; y
++)
1650 for (int x
= 0; x
< width
; x
++)
1652 int r
= data
[index
];
1654 int g
= data
[index
];
1656 int b
= data
[index
];
1661 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1662 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1664 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1667 if ((r
== red
) && (b
== blue
) && (g
== green
))
1668 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1670 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1677 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1679 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1681 gdk_image_destroy( data_image
);
1682 gdk_gc_unref( data_gc
);
1688 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1690 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1692 gdk_image_destroy( mask_image
);
1693 gdk_gc_unref( mask_gc
);
1700 wxBitmap
wxImage::ConvertToBitmap() const
1704 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1706 int width
= GetWidth();
1707 int height
= GetHeight();
1709 bitmap
.SetHeight( height
);
1710 bitmap
.SetWidth( width
);
1712 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1716 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1719 int bpp
= visual
->depth
;
1721 bitmap
.SetDepth( bpp
);
1723 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1724 if (bpp
< 8) bpp
= 8;
1726 #if (GTK_MINOR_VERSION > 0)
1728 if (!HasMask() && (bpp
> 8))
1730 static bool s_hasInitialized
= FALSE
;
1732 if (!s_hasInitialized
)
1735 s_hasInitialized
= TRUE
;
1738 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1740 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1744 GDK_RGB_DITHER_NONE
,
1755 // Create picture image
1757 GdkImage
*data_image
=
1758 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1760 // Create mask image
1762 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1766 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1768 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1770 wxMask
*mask
= new wxMask();
1771 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1773 bitmap
.SetMask( mask
);
1778 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1779 byte_order b_o
= RGB
;
1783 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1784 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1785 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1786 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1787 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1788 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1791 int r_mask
= GetMaskRed();
1792 int g_mask
= GetMaskGreen();
1793 int b_mask
= GetMaskBlue();
1795 unsigned char* data
= GetData();
1798 for (int y
= 0; y
< height
; y
++)
1800 for (int x
= 0; x
< width
; x
++)
1802 int r
= data
[index
];
1804 int g
= data
[index
];
1806 int b
= data
[index
];
1811 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1812 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1814 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1822 if (wxTheApp
->m_colorCube
)
1824 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1828 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1829 GdkColor
*colors
= cmap
->colors
;
1830 int max
= 3 * (65536);
1832 for (int i
= 0; i
< cmap
->size
; i
++)
1834 int rdiff
= (r
<< 8) - colors
[i
].red
;
1835 int gdiff
= (g
<< 8) - colors
[i
].green
;
1836 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1837 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1838 if (sum
< max
) { pixel
= i
; max
= sum
; }
1842 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1848 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1849 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1854 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1855 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1864 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1865 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1866 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1867 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1868 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1869 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1871 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1880 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1882 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1884 gdk_image_destroy( data_image
);
1885 gdk_gc_unref( data_gc
);
1891 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1893 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1895 gdk_image_destroy( mask_image
);
1896 gdk_gc_unref( mask_gc
);
1902 wxImage::wxImage( const wxBitmap
&bitmap
)
1904 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1906 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1907 if (bitmap
.GetPixmap())
1909 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1911 bitmap
.GetWidth(), bitmap
.GetHeight() );
1913 if (bitmap
.GetBitmap())
1915 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1917 bitmap
.GetWidth(), bitmap
.GetHeight() );
1920 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1923 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1925 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1926 char unsigned *data
= GetData();
1930 gdk_image_destroy( gdk_image
);
1931 wxFAIL_MSG( wxT("couldn't create image") );
1935 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1936 if (bitmap
.GetMask())
1938 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1940 bitmap
.GetWidth(), bitmap
.GetHeight() );
1942 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1946 int red_shift_right
= 0;
1947 int green_shift_right
= 0;
1948 int blue_shift_right
= 0;
1949 int red_shift_left
= 0;
1950 int green_shift_left
= 0;
1951 int blue_shift_left
= 0;
1952 bool use_shift
= FALSE
;
1954 if (bitmap
.GetPixmap())
1956 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1958 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1959 bpp
= visual
->depth
;
1960 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1961 red_shift_right
= visual
->red_shift
;
1962 red_shift_left
= 8-visual
->red_prec
;
1963 green_shift_right
= visual
->green_shift
;
1964 green_shift_left
= 8-visual
->green_prec
;
1965 blue_shift_right
= visual
->blue_shift
;
1966 blue_shift_left
= 8-visual
->blue_prec
;
1968 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
1970 if (bitmap
.GetBitmap())
1976 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1979 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1981 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1983 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
2001 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
2002 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
2003 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
2005 else if (cmap
->colors
)
2007 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
2008 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
2009 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
2013 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
2018 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
2019 if (mask_pixel
== 0)
2031 gdk_image_destroy( gdk_image
);
2032 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
2037 //-----------------------------------------------------------------------------
2038 // Motif conversion routines
2039 //-----------------------------------------------------------------------------
2043 #pragma message disable nosimpint
2047 #pragma message enable nosimpint
2049 #include "wx/utils.h"
2054 Date: Wed, 05 Jan 2000 11:45:40 +0100
2055 From: Frits Boel <boel@niob.knaw.nl>
2056 To: julian.smart@ukonline.co.uk
2057 Subject: Patch for Motif ConvertToBitmap
2061 I've been working on a wxWin application for image processing. From the
2062 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
2063 till I looked in the source code of image.cpp. I saw that converting a
2064 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
2065 to the 256 colors of the palet. A very time-consuming piece of code!
2067 Because I wanted a faster application, I've made a 'patch' for this. In
2068 short: every pixel of the image is compared to a sorted list with
2069 colors. If the color is found in the list, the palette entry is
2070 returned; if the color is not found, the color palette is searched and
2071 then the palette entry is returned and the color added to the sorted
2074 Maybe there is another method for this, namely changing the palette
2075 itself (if the colors are known, as is the case with tiffs with a
2076 colormap). I did not look at this, maybe someone else did?
2078 The code of the patch is attached, have a look on it, and maybe you will
2079 ship it with the next release of wxMotif?
2084 Software engineer at Hubrecht Laboratory, The Netherlands.
2091 wxSearchColor( void );
2092 wxSearchColor( int size
, XColor
*colors
);
2093 ~wxSearchColor( void );
2095 int SearchColor( int r
, int g
, int b
);
2097 int AddColor( unsigned int value
, int pos
);
2101 unsigned int *color
;
2108 wxSearchColor::wxSearchColor( void )
2111 colors
= (XColor
*) NULL
;
2112 color
= (unsigned int *) NULL
;
2113 entry
= (int*) NULL
;
2119 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
2124 color
= new unsigned int[size
];
2125 entry
= new int [size
];
2127 for (i
= 0; i
< size
; i
++ ) {
2131 bottom
= top
= ( size
>> 1 );
2134 wxSearchColor::~wxSearchColor( void )
2136 if ( color
) delete color
;
2137 if ( entry
) delete entry
;
2140 int wxSearchColor::SearchColor( int r
, int g
, int b
)
2142 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
2147 while ( begin
<= end
) {
2149 middle
= ( begin
+ end
) >> 1;
2151 if ( value
== color
[middle
] ) {
2152 return( entry
[middle
] );
2153 } else if ( value
< color
[middle
] ) {
2161 return AddColor( value
, middle
);
2164 int wxSearchColor::AddColor( unsigned int value
, int pos
)
2168 int max
= 3 * (65536);
2169 for ( i
= 0; i
< 256; i
++ ) {
2170 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
2171 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
2172 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
2173 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2174 if (sum
< max
) { pixel
= i
; max
= sum
; }
2177 if ( entry
[pos
] < 0 ) {
2180 } else if ( value
< color
[pos
] ) {
2183 for ( i
= bottom
; i
< pos
; i
++ ) {
2184 color
[i
-1] = color
[i
];
2185 entry
[i
-1] = entry
[i
];
2188 color
[pos
-1] = value
;
2189 entry
[pos
-1] = pixel
;
2190 } else if ( top
< size
-1 ) {
2191 for ( i
= top
; i
>= pos
; i
-- ) {
2192 color
[i
+1] = color
[i
];
2193 entry
[i
+1] = entry
[i
];
2202 if ( top
< size
-1 ) {
2203 for ( i
= top
; i
> pos
; i
-- ) {
2204 color
[i
+1] = color
[i
];
2205 entry
[i
+1] = entry
[i
];
2208 color
[pos
+1] = value
;
2209 entry
[pos
+1] = pixel
;
2210 } else if ( bottom
> 0 ) {
2211 for ( i
= bottom
; i
< pos
; i
++ ) {
2212 color
[i
-1] = color
[i
];
2213 entry
[i
-1] = entry
[i
];
2225 wxBitmap
wxImage::ConvertToBitmap() const
2229 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
2231 int width
= GetWidth();
2232 int height
= GetHeight();
2234 bitmap
.SetHeight( height
);
2235 bitmap
.SetWidth( width
);
2237 Display
*dpy
= (Display
*) wxGetDisplay();
2238 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2239 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2243 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2244 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
2246 bitmap
.Create( width
, height
, bpp
);
2250 XImage
*mask_image
= (XImage
*) NULL
;
2253 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2254 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
2257 // Retrieve depth info
2259 XVisualInfo vinfo_template
;
2262 vinfo_template
.visual
= vis
;
2263 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2264 vinfo_template
.depth
= bpp
;
2267 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2269 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
2273 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2274 if (bpp
< 8) bpp
= 8;
2278 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
2279 byte_order b_o
= RGB
;
2283 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2284 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2285 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2286 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2287 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2288 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2291 int r_mask
= GetMaskRed();
2292 int g_mask
= GetMaskGreen();
2293 int b_mask
= GetMaskBlue();
2298 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2300 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2301 XQueryColors( dpy
, cmap
, colors
, 256 );
2304 wxSearchColor
scolor( 256, colors
);
2305 unsigned char* data
= GetData();
2307 bool hasMask
= HasMask();
2310 for (int y
= 0; y
< height
; y
++)
2312 for (int x
= 0; x
< width
; x
++)
2314 int r
= data
[index
];
2316 int g
= data
[index
];
2318 int b
= data
[index
];
2323 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2324 XPutPixel( mask_image
, x
, y
, 0 );
2326 XPutPixel( mask_image
, x
, y
, 1 );
2333 #if 0 // Old, slower code
2336 if (wxTheApp->m_colorCube)
2338 pixel = wxTheApp->m_colorCube
2339 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2344 int max
= 3 * (65536);
2345 for (int i
= 0; i
< 256; i
++)
2347 int rdiff
= (r
<< 8) - colors
[i
].red
;
2348 int gdiff
= (g
<< 8) - colors
[i
].green
;
2349 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2350 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2351 if (sum
< max
) { pixel
= i
; max
= sum
; }
2358 // And this is all to get the 'right' color...
2359 int pixel
= scolor
.SearchColor( r
, g
, b
);
2360 XPutPixel( data_image
, x
, y
, pixel
);
2365 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2366 XPutPixel( data_image
, x
, y
, pixel
);
2371 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2372 XPutPixel( data_image
, x
, y
, pixel
);
2381 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2382 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2383 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2384 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2385 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2386 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2388 XPutPixel( data_image
, x
, y
, pixel
);
2398 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2399 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2400 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2402 XDestroyImage( data_image
);
2408 wxBitmap
maskBitmap(width
, height
, 1);
2410 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2411 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2413 XDestroyImage( mask_image
);
2414 XFreeGC( dpy
, gcMask
);
2416 wxMask
* mask
= new wxMask
;
2417 mask
->SetPixmap(maskBitmap
.GetPixmap());
2419 bitmap
.SetMask(mask
);
2421 maskBitmap
.SetPixmapNull();
2427 wxImage::wxImage( const wxBitmap
&bitmap
)
2429 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2431 Display
*dpy
= (Display
*) wxGetDisplay();
2432 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2433 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2435 XImage
*ximage
= XGetImage( dpy
,
2436 (Drawable
)bitmap
.GetPixmap(),
2438 bitmap
.GetWidth(), bitmap
.GetHeight(),
2439 AllPlanes
, ZPixmap
);
2441 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2443 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2444 char unsigned *data
= GetData();
2448 XDestroyImage( ximage
);
2449 wxFAIL_MSG( wxT("couldn't create image") );
2454 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2455 if (bitmap.GetMask())
2457 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2459 bitmap.GetWidth(), bitmap.GetHeight() );
2461 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2465 // Retrieve depth info
2467 XVisualInfo vinfo_template
;
2470 vinfo_template
.visual
= vis
;
2471 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2472 vinfo_template
.depth
= bpp
;
2475 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2477 wxCHECK_RET( vi
, wxT("no visual") );
2479 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2486 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2488 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2489 XQueryColors( dpy
, cmap
, colors
, 256 );
2493 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2495 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2497 int pixel
= XGetPixel( ximage
, i
, j
);
2500 data
[pos
] = colors
[pixel
].red
>> 8;
2501 data
[pos
+1] = colors
[pixel
].green
>> 8;
2502 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2503 } else if (bpp
== 15)
2505 data
[pos
] = (pixel
>> 7) & 0xf8;
2506 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2507 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2508 } else if (bpp
== 16)
2510 data
[pos
] = (pixel
>> 8) & 0xf8;
2511 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2512 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2515 data
[pos
] = (pixel
>> 16) & 0xff;
2516 data
[pos
+1] = (pixel
>> 8) & 0xff;
2517 data
[pos
+2] = pixel
& 0xff;
2523 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2524 if (mask_pixel == 0)
2537 XDestroyImage( ximage
);
2539 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2545 // OS/2 Presentation manager conversion routings
2547 wxBitmap
wxImage::ConvertToBitmap() const
2550 return wxNullBitmap
;
2551 wxBitmap bitmap
; // remove
2554 int sizeLimit = 1024*768*3;
2556 // width and height of the device-dependent bitmap
2557 int width = GetWidth();
2558 int bmpHeight = GetHeight();
2560 // calc the number of bytes per scanline and padding
2561 int bytePerLine = width*3;
2562 int sizeDWORD = sizeof( DWORD );
2563 int lineBoundary = bytePerLine % sizeDWORD;
2565 if( lineBoundary > 0 )
2567 padding = sizeDWORD - lineBoundary;
2568 bytePerLine += padding;
2570 // calc the number of DIBs and heights of DIBs
2573 int height = sizeLimit/bytePerLine;
2574 if( height >= bmpHeight )
2578 numDIB = bmpHeight / height;
2579 hRemain = bmpHeight % height;
2580 if( hRemain >0 ) numDIB++;
2583 // set bitmap parameters
2585 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2586 bitmap.SetWidth( width );
2587 bitmap.SetHeight( bmpHeight );
2588 bitmap.SetDepth( wxDisplayDepth() );
2590 // create a DIB header
2591 int headersize = sizeof(BITMAPINFOHEADER);
2592 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2593 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2594 // Fill in the DIB header
2595 lpDIBh->bmiHeader.biSize = headersize;
2596 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2597 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2598 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2599 // the general formula for biSizeImage:
2600 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2601 lpDIBh->bmiHeader.biPlanes = 1;
2602 lpDIBh->bmiHeader.biBitCount = 24;
2603 lpDIBh->bmiHeader.biCompression = BI_RGB;
2604 lpDIBh->bmiHeader.biClrUsed = 0;
2605 // These seem not really needed for our purpose here.
2606 lpDIBh->bmiHeader.biClrImportant = 0;
2607 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2608 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2609 // memory for DIB data
2610 unsigned char *lpBits;
2611 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2614 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2619 // create and set the device-dependent bitmap
2620 HDC hdc = ::GetDC(NULL);
2621 HDC memdc = ::CreateCompatibleDC( hdc );
2623 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2624 ::SelectObject( memdc, hbitmap);
2626 // copy image data into DIB data and then into DDB (in a loop)
2627 unsigned char *data = GetData();
2630 unsigned char *ptdata = data;
2631 unsigned char *ptbits;
2633 for( n=0; n<numDIB; n++ )
2635 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2637 // redefine height and size of the (possibly) last smaller DIB
2638 // memory is not reallocated
2640 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2641 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2645 for( j=0; j<height; j++ )
2647 for( i=0; i<width; i++ )
2649 *(ptbits++) = *(ptdata+2);
2650 *(ptbits++) = *(ptdata+1);
2651 *(ptbits++) = *(ptdata );
2654 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2656 ::StretchDIBits( memdc, 0, origin, width, height,\
2657 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2659 // if numDIB = 1, lines below can also be used
2660 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2661 // The above line is equivalent to the following two lines.
2662 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2663 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2664 // or the following lines
2665 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2666 // HDC memdc = ::CreateCompatibleDC( hdc );
2667 // ::SelectObject( memdc, hbitmap);
2668 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2669 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2670 // ::SelectObject( memdc, 0 );
2671 // ::DeleteDC( memdc );
2673 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2675 // similarly, created an mono-bitmap for the possible mask
2678 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2679 ::SelectObject( memdc, hbitmap);
2680 if( numDIB == 1 ) height = bmpHeight;
2681 else height = sizeLimit/bytePerLine;
2682 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2683 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2685 unsigned char r = GetMaskRed();
2686 unsigned char g = GetMaskGreen();
2687 unsigned char b = GetMaskBlue();
2688 unsigned char zero = 0, one = 255;
2690 for( n=0; n<numDIB; n++ )
2692 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2694 // redefine height and size of the (possibly) last smaller DIB
2695 // memory is not reallocated
2697 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2698 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2701 for( int j=0; j<height; j++ )
2703 for(i=0; i<width; i++ )
2705 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2718 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2720 ::StretchDIBits( memdc, 0, origin, width, height,\
2721 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2724 // create a wxMask object
2725 wxMask *mask = new wxMask();
2726 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2727 bitmap.SetMask( mask );
2730 // free allocated resources
2731 ::SelectObject( memdc, 0 );
2732 ::DeleteDC( memdc );
2733 ::ReleaseDC(NULL, hdc);
2737 // check the wxBitmap object
2738 if( bitmap.GetHBITMAP() )
2739 bitmap.SetOk( TRUE );
2741 bitmap.SetOk( FALSE );
2746 wxImage::wxImage( const wxBitmap
&bitmap
)
2751 wxFAIL_MSG( wxT("invalid bitmap") );
2755 // create an wxImage object
2756 int width
= bitmap
.GetWidth();
2757 int height
= bitmap
.GetHeight();
2758 Create( width
, height
);
2759 unsigned char *data
= GetData();
2762 wxFAIL_MSG( wxT("could not allocate data for image") );
2766 // calc the number of bytes per scanline and padding in the DIB
2767 int bytePerLine
= width
*3;
2768 int sizeDWORD
= sizeof( DWORD
);
2769 int lineBoundary
= bytePerLine
% sizeDWORD
;
2771 if( lineBoundary
> 0 )
2773 padding
= sizeDWORD
- lineBoundary
;
2774 bytePerLine
+= padding
;
2778 // create a DIB header
2779 int headersize = sizeof(BITMAPINFOHEADER);
2780 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2783 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2787 // Fill in the DIB header
2788 lpDIBh->bmiHeader.biSize = headersize;
2789 lpDIBh->bmiHeader.biWidth = width;
2790 lpDIBh->bmiHeader.biHeight = -height;
2791 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2792 lpDIBh->bmiHeader.biPlanes = 1;
2793 lpDIBh->bmiHeader.biBitCount = 24;
2794 lpDIBh->bmiHeader.biCompression = BI_RGB;
2795 lpDIBh->bmiHeader.biClrUsed = 0;
2796 // These seem not really needed for our purpose here.
2797 lpDIBh->bmiHeader.biClrImportant = 0;
2798 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2799 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2800 // memory for DIB data
2801 unsigned char *lpBits;
2802 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2805 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2811 // copy data from the device-dependent bitmap to the DIB
2812 HDC hdc = ::GetDC(NULL);
2814 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2815 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2817 // copy DIB data into the wxImage object
2819 unsigned char *ptdata = data;
2820 unsigned char *ptbits = lpBits;
2821 for( i=0; i<height; i++ )
2823 for( j=0; j<width; j++ )
2825 *(ptdata++) = *(ptbits+2);
2826 *(ptdata++) = *(ptbits+1);
2827 *(ptdata++) = *(ptbits );
2833 // similarly, set data according to the possible mask bitmap
2834 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2836 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2837 // memory DC created, color set, data copied, and memory DC deleted
2838 HDC memdc = ::CreateCompatibleDC( hdc );
2839 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2840 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2841 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2842 ::DeleteDC( memdc );
2843 // background color set to RGB(16,16,16) in consistent with wxGTK
2844 unsigned char r=16, g=16, b=16;
2847 for( i=0; i<height; i++ )
2849 for( j=0; j<width; j++ )
2863 SetMaskColour( r, g, b );
2870 // free allocated resources
2871 ::ReleaseDC(NULL, hdc);
2879 // A module to allow wxImage initialization/cleanup
2880 // without calling these functions from app.cpp or from
2881 // the user's application.
2883 class wxImageModule
: public wxModule
2885 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2888 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2889 void OnExit() { wxImage::CleanUpHandlers(); };
2892 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2895 //-----------------------------------------------------------------------------
2898 // Counts and returns the number of different colours. Optionally stops
2899 // when it exceeds 'stopafter' different colours. This is useful, for
2900 // example, to see if the image can be saved as 8-bit (256 colour or
2901 // less, in this case it would be invoked as CountColours(256)). Default
2902 // value for stopafter is -1 (don't care).
2904 unsigned long wxImage::CountColours( unsigned long stopafter
)
2908 unsigned char r
, g
, b
, *p
;
2909 unsigned long size
, nentries
, key
;
2912 size
= GetWidth() * GetHeight();
2915 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2920 key
= (r
<< 16) | (g
<< 8) | b
;
2922 if (h
.Get(key
) == NULL
)
2934 // Computes the histogram of the image and fills a hash table, indexed
2935 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2936 // wxHNode contains an 'index' (useful to build a palette with the image
2937 // colours) and a 'value', which is the number of pixels in the image with
2940 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2942 unsigned char r
, g
, b
, *p
;
2943 unsigned long size
, nentries
, key
;
2947 size
= GetWidth() * GetHeight();
2950 for (unsigned long j
= 0; j
< size
; j
++)
2955 key
= (r
<< 16) | (g
<< 8) | b
;
2957 hnode
= (wxHNode
*) h
.Get(key
);
2963 hnode
= new wxHNode();
2964 hnode
->index
= nentries
++;
2967 h
.Put(key
, (wxObject
*)hnode
);
2975 * Rotation code by Carlos Moreno
2978 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2979 // does exactly the same thing. And I also got rid of wxRotationPixel
2980 // bacause of potential problems in architectures where alignment
2981 // is an issue, so I had to rewrite parts of the code.
2983 static const double gs_Epsilon
= 1e-10;
2985 static inline int wxCint (double x
)
2987 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
2991 // Auxiliary function to rotate a point (x,y) with respect to point p0
2992 // make it inline and use a straight return to facilitate optimization
2993 // also, the function receives the sine and cosine of the angle to avoid
2994 // repeating the time-consuming calls to these functions -- sin/cos can
2995 // be computed and stored in the calling function.
2997 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2999 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
3000 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
3003 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
3005 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
3008 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
3011 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
3013 // Create pointer-based array to accelerate access to wxImage's data
3014 unsigned char ** data
= new unsigned char * [GetHeight()];
3016 data
[0] = GetData();
3018 for (i
= 1; i
< GetHeight(); i
++)
3019 data
[i
] = data
[i
- 1] + (3 * GetWidth());
3021 // precompute coefficients for rotation formula
3022 // (sine and cosine of the angle)
3023 const double cos_angle
= cos(angle
);
3024 const double sin_angle
= sin(angle
);
3026 // Create new Image to store the result
3027 // First, find rectangle that covers the rotated image; to do that,
3028 // rotate the four corners
3030 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
3032 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
3033 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
3034 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
3035 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
3037 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
3038 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
3039 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
3040 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
3042 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
3044 if (offset_after_rotation
!= NULL
)
3046 *offset_after_rotation
= wxPoint (x1
, y1
);
3049 // GRG: The rotated (destination) image is always accessed
3050 // sequentially, so there is no need for a pointer-based
3051 // array here (and in fact it would be slower).
3053 unsigned char * dst
= rotated
.GetData();
3055 // GRG: if the original image has a mask, use its RGB values
3056 // as the blank pixel, else, fall back to default (black).
3058 unsigned char blank_r
= 0;
3059 unsigned char blank_g
= 0;
3060 unsigned char blank_b
= 0;
3064 blank_r
= GetMaskRed();
3065 blank_g
= GetMaskGreen();
3066 blank_b
= GetMaskBlue();
3067 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
3070 // Now, for each point of the rotated image, find where it came from, by
3071 // performing an inverse rotation (a rotation of -angle) and getting the
3072 // pixel at those coordinates
3074 // GRG: I've taken the (interpolating) test out of the loops, so that
3075 // it is done only once, instead of repeating it for each pixel.
3080 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3082 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3084 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3086 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
3087 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
3089 // interpolate using the 4 enclosing grid-points. Those
3090 // points can be obtained using floor and ceiling of the
3091 // exact coordinates of the point
3092 // C.M. 2000-02-17: when the point is near the border, special care is required.
3096 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
3098 x1
= wxCint(floor(src
.x
));
3099 x2
= wxCint(ceil(src
.x
));
3101 else // else means that x is near one of the borders (0 or width-1)
3103 x1
= x2
= wxCint (src
.x
);
3106 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
3108 y1
= wxCint(floor(src
.y
));
3109 y2
= wxCint(ceil(src
.y
));
3113 y1
= y2
= wxCint (src
.y
);
3116 // get four points and the distances (square of the distance,
3117 // for efficiency reasons) for the interpolation formula
3119 // GRG: Do not calculate the points until they are
3120 // really needed -- this way we can calculate
3121 // just one, instead of four, if d1, d2, d3
3122 // or d4 are < gs_Epsilon
3124 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
3125 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
3126 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
3127 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
3129 // Now interpolate as a weighted average of the four surrounding
3130 // points, where the weights are the distances to each of those points
3132 // If the point is exactly at one point of the grid of the source
3133 // image, then don't interpolate -- just assign the pixel
3135 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
3137 unsigned char *p
= data
[y1
] + (3 * x1
);
3142 else if (d2
< gs_Epsilon
)
3144 unsigned char *p
= data
[y1
] + (3 * x2
);
3149 else if (d3
< gs_Epsilon
)
3151 unsigned char *p
= data
[y2
] + (3 * x2
);
3156 else if (d4
< gs_Epsilon
)
3158 unsigned char *p
= data
[y2
] + (3 * x1
);
3165 // weights for the weighted average are proportional to the inverse of the distance
3166 unsigned char *v1
= data
[y1
] + (3 * x1
);
3167 unsigned char *v2
= data
[y1
] + (3 * x2
);
3168 unsigned char *v3
= data
[y2
] + (3 * x2
);
3169 unsigned char *v4
= data
[y2
] + (3 * x1
);
3171 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
3175 *(dst
++) = (unsigned char)
3176 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3177 w3
* *(v3
++) + w4
* *(v4
++)) /
3178 (w1
+ w2
+ w3
+ w4
) );
3179 *(dst
++) = (unsigned char)
3180 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3181 w3
* *(v3
++) + w4
* *(v4
++)) /
3182 (w1
+ w2
+ w3
+ w4
) );
3183 *(dst
++) = (unsigned char)
3184 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3185 w3
* *(v3
++) + w4
* *(v4
++)) /
3186 (w1
+ w2
+ w3
+ w4
) );
3198 else // not interpolating
3200 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3202 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3204 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3206 const int xs
= wxCint (src
.x
); // wxCint rounds to the
3207 const int ys
= wxCint (src
.y
); // closest integer
3209 if (0 <= xs
&& xs
< GetWidth() &&
3210 0 <= ys
&& ys
< GetHeight())
3212 unsigned char *p
= data
[ys
] + (3 * xs
);