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
;
62 wxImageRefData::wxImageRefData()
66 m_data
= (unsigned char*) NULL
;
75 wxImageRefData::~wxImageRefData()
77 if (m_data
&& !m_static
)
81 wxList
wxImage::sm_handlers
;
83 //-----------------------------------------------------------------------------
85 #define M_IMGDATA ((wxImageRefData *)m_refData)
87 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
93 wxImage::wxImage( int width
, int height
)
95 Create( width
, height
);
98 wxImage::wxImage( int width
, int height
, unsigned char* data
, bool static_data
)
100 Create( width
, height
, data
, static_data
);
103 wxImage::wxImage( const wxString
& name
, long type
)
105 LoadFile( name
, type
);
108 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
)
110 LoadFile( name
, mimetype
);
114 wxImage::wxImage( wxInputStream
& stream
, long type
)
116 LoadFile( stream
, type
);
119 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
)
121 LoadFile( stream
, mimetype
);
123 #endif // wxUSE_STREAMS
125 wxImage::wxImage( const wxImage
& image
)
130 wxImage::wxImage( const wxImage
* image
)
132 if (image
) Ref(*image
);
135 void wxImage::Create( int width
, int height
)
139 m_refData
= new wxImageRefData();
141 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
142 if (M_IMGDATA
->m_data
)
144 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
146 M_IMGDATA
->m_width
= width
;
147 M_IMGDATA
->m_height
= height
;
148 M_IMGDATA
->m_ok
= TRUE
;
156 void wxImage::Create( int width
, int height
, unsigned char* data
, bool static_data
)
160 m_refData
= new wxImageRefData();
162 M_IMGDATA
->m_data
= data
;
163 if (M_IMGDATA
->m_data
)
165 M_IMGDATA
->m_width
= width
;
166 M_IMGDATA
->m_height
= height
;
167 M_IMGDATA
->m_ok
= TRUE
;
168 M_IMGDATA
->m_static
= static_data
;
176 void wxImage::Destroy()
181 wxImage
wxImage::Copy() const
185 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
187 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
189 char unsigned *data
= image
.GetData();
191 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
193 if (M_IMGDATA
->m_hasMask
)
194 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
196 memcpy( data
, GetData(), M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3 );
201 wxImage
wxImage::Scale( int width
, int height
) const
205 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
207 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, wxT("invalid image size") );
209 image
.Create( width
, height
);
211 char unsigned *data
= image
.GetData();
213 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
215 if (M_IMGDATA
->m_hasMask
)
216 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
218 long old_height
= M_IMGDATA
->m_height
;
219 long old_width
= M_IMGDATA
->m_width
;
221 char unsigned *source_data
= M_IMGDATA
->m_data
;
222 char unsigned *target_data
= data
;
224 for (long j
= 0; j
< height
; j
++)
226 long y_offset
= (j
* old_height
/ height
) * old_width
;
228 for (long i
= 0; i
< width
; i
++)
231 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
240 wxImage
wxImage::Rotate90( bool clockwise
) const
244 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
246 image
.Create( M_IMGDATA
->m_height
, M_IMGDATA
->m_width
);
248 char unsigned *data
= image
.GetData();
250 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
252 if (M_IMGDATA
->m_hasMask
)
253 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
255 long height
= M_IMGDATA
->m_height
;
256 long width
= M_IMGDATA
->m_width
;
258 char unsigned *source_data
= M_IMGDATA
->m_data
;
259 char unsigned *target_data
;
261 for (long j
= 0; j
< height
; j
++)
263 for (long i
= 0; i
< width
; i
++)
266 target_data
= data
+ (((i
+1)*height
) - j
- 1)*3;
268 target_data
= data
+ ((height
*(width
-1)) + j
- (i
*height
))*3;
269 memcpy( target_data
, source_data
, 3 );
277 wxImage
wxImage::Mirror( bool horizontally
) const
281 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
283 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
285 char unsigned *data
= image
.GetData();
287 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
289 if (M_IMGDATA
->m_hasMask
)
290 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
292 long height
= M_IMGDATA
->m_height
;
293 long width
= M_IMGDATA
->m_width
;
295 char unsigned *source_data
= M_IMGDATA
->m_data
;
296 char unsigned *target_data
;
300 for (long j
= 0; j
< height
; j
++)
303 target_data
= data
-3;
304 for (long i
= 0; i
< width
; i
++)
306 memcpy( target_data
, source_data
, 3 );
314 for (long i
= 0; i
< height
; i
++)
316 target_data
= data
+ 3*width
*(height
-1-i
);
317 memcpy( target_data
, source_data
, 3*width
);
318 source_data
+= 3*width
;
325 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
329 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
331 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()),
332 image
, wxT("invalid subimage size") );
334 int subwidth
=rect
.GetWidth();
335 const int subheight
=rect
.GetHeight();
337 image
.Create( subwidth
, subheight
);
339 char unsigned *subdata
= image
.GetData(), *data
=GetData();
341 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
343 if (M_IMGDATA
->m_hasMask
)
344 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
346 const int subleft
=3*rect
.GetLeft();
347 const int width
=3*GetWidth();
350 data
+=rect
.GetTop()*width
+subleft
;
352 for (long j
= 0; j
< subheight
; ++j
)
354 memcpy( subdata
, data
, subwidth
);
362 void wxImage::Paste( const wxImage
&image
, int x
, int y
)
364 wxCHECK_RET( Ok(), wxT("invalid image") );
365 wxCHECK_RET( image
.Ok(), wxT("invalid image") );
369 int width
= image
.GetWidth();
370 int height
= image
.GetHeight();
383 if ((x
+xx
)+width
> M_IMGDATA
->m_width
)
384 width
= M_IMGDATA
->m_width
- (x
+xx
);
385 if ((y
+yy
)+height
> M_IMGDATA
->m_height
)
386 height
= M_IMGDATA
->m_height
- (y
+yy
);
388 if (width
< 1) return;
389 if (height
< 1) return;
391 if ((!HasMask() && !image
.HasMask()) ||
392 ((HasMask() && image
.HasMask() &&
393 (GetMaskRed()==image
.GetMaskRed()) &&
394 (GetMaskGreen()==image
.GetMaskGreen()) &&
395 (GetMaskBlue()==image
.GetMaskBlue()))))
398 unsigned char* source_data
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth();
399 int source_step
= image
.GetWidth()*3;
401 unsigned char* target_data
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
;
402 int target_step
= M_IMGDATA
->m_width
*3;
403 for (int j
= 0; j
< height
; j
++)
405 memcpy( target_data
, source_data
, width
);
406 source_data
+= source_step
;
407 target_data
+= target_step
;
415 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
416 unsigned char r2
, unsigned char g2
, unsigned char b2
)
418 wxCHECK_RET( Ok(), wxT("invalid image") );
420 char unsigned *data
= GetData();
422 const int w
= GetWidth();
423 const int h
= GetHeight();
425 for (int j
= 0; j
< h
; j
++)
426 for (int i
= 0; i
< w
; i
++)
428 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
438 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
440 wxCHECK_RET( Ok(), wxT("invalid image") );
442 int w
= M_IMGDATA
->m_width
;
443 int h
= M_IMGDATA
->m_height
;
445 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
447 long pos
= (y
* w
+ x
) * 3;
449 M_IMGDATA
->m_data
[ pos
] = r
;
450 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
451 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
454 unsigned char wxImage::GetRed( int x
, int y
) const
456 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
458 int w
= M_IMGDATA
->m_width
;
459 int h
= M_IMGDATA
->m_height
;
461 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
463 long pos
= (y
* w
+ x
) * 3;
465 return M_IMGDATA
->m_data
[pos
];
468 unsigned char wxImage::GetGreen( int x
, int y
) const
470 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
472 int w
= M_IMGDATA
->m_width
;
473 int h
= M_IMGDATA
->m_height
;
475 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
477 long pos
= (y
* w
+ x
) * 3;
479 return M_IMGDATA
->m_data
[pos
+1];
482 unsigned char wxImage::GetBlue( int x
, int y
) const
484 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
486 int w
= M_IMGDATA
->m_width
;
487 int h
= M_IMGDATA
->m_height
;
489 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
491 long pos
= (y
* w
+ x
) * 3;
493 return M_IMGDATA
->m_data
[pos
+2];
496 bool wxImage::Ok() const
498 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
501 char unsigned *wxImage::GetData() const
503 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
505 return M_IMGDATA
->m_data
;
508 void wxImage::SetData( char unsigned *data
)
510 wxCHECK_RET( Ok(), wxT("invalid image") );
512 wxImageRefData
*newRefData
= new wxImageRefData();
514 newRefData
->m_width
= M_IMGDATA
->m_width
;
515 newRefData
->m_height
= M_IMGDATA
->m_height
;
516 newRefData
->m_data
= data
;
517 newRefData
->m_ok
= TRUE
;
518 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
519 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
520 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
521 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
525 m_refData
= newRefData
;
528 void wxImage::SetData( char unsigned *data
, int new_width
, int new_height
)
530 wxImageRefData
*newRefData
= new wxImageRefData();
534 newRefData
->m_width
= new_width
;
535 newRefData
->m_height
= new_height
;
536 newRefData
->m_data
= data
;
537 newRefData
->m_ok
= TRUE
;
538 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
539 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
540 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
541 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
545 newRefData
->m_width
= new_width
;
546 newRefData
->m_height
= new_height
;
547 newRefData
->m_data
= data
;
548 newRefData
->m_ok
= TRUE
;
553 m_refData
= newRefData
;
556 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
558 wxCHECK_RET( Ok(), wxT("invalid image") );
560 M_IMGDATA
->m_maskRed
= r
;
561 M_IMGDATA
->m_maskGreen
= g
;
562 M_IMGDATA
->m_maskBlue
= b
;
563 M_IMGDATA
->m_hasMask
= TRUE
;
566 unsigned char wxImage::GetMaskRed() const
568 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
570 return M_IMGDATA
->m_maskRed
;
573 unsigned char wxImage::GetMaskGreen() const
575 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
577 return M_IMGDATA
->m_maskGreen
;
580 unsigned char wxImage::GetMaskBlue() const
582 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
584 return M_IMGDATA
->m_maskBlue
;
587 void wxImage::SetMask( bool mask
)
589 wxCHECK_RET( Ok(), wxT("invalid image") );
591 M_IMGDATA
->m_hasMask
= mask
;
594 bool wxImage::HasMask() const
596 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
598 return M_IMGDATA
->m_hasMask
;
601 int wxImage::GetWidth() const
603 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
605 return M_IMGDATA
->m_width
;
608 int wxImage::GetHeight() const
610 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
612 return M_IMGDATA
->m_height
;
615 bool wxImage::LoadFile( const wxString
& filename
, long type
)
618 if (wxFileExists(filename
))
620 wxFileInputStream
stream(filename
);
621 wxBufferedInputStream
bstream( stream
);
622 return LoadFile(bstream
, type
);
626 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
630 #else // !wxUSE_STREAMS
632 #endif // wxUSE_STREAMS
635 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
638 if (wxFileExists(filename
))
640 wxFileInputStream
stream(filename
);
641 wxBufferedInputStream
bstream( stream
);
642 return LoadFile(bstream
, mimetype
);
646 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
650 #else // !wxUSE_STREAMS
652 #endif // wxUSE_STREAMS
655 bool wxImage::SaveFile( const wxString
& filename
, int type
)
658 wxFileOutputStream
stream(filename
);
660 if ( stream
.LastError() == wxStream_NOERROR
)
662 wxBufferedOutputStream
bstream( stream
);
663 return SaveFile(bstream
, type
);
666 #endif // wxUSE_STREAMS
670 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
673 wxFileOutputStream
stream(filename
);
675 if ( stream
.LastError() == wxStream_NOERROR
)
677 wxBufferedOutputStream
bstream( stream
);
678 return SaveFile(bstream
, mimetype
);
681 #endif // wxUSE_STREAMS
685 bool wxImage::CanRead( const wxString
&name
)
688 wxFileInputStream
stream(name
);
689 return CanRead(stream
);
697 bool wxImage::CanRead( wxInputStream
&stream
)
699 wxList
&list
=GetHandlers();
701 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
703 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
704 if (handler
->CanRead( stream
))
711 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
715 m_refData
= new wxImageRefData
;
717 wxImageHandler
*handler
;
719 if (type
==wxBITMAP_TYPE_ANY
)
721 wxList
&list
=GetHandlers();
723 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
725 handler
=(wxImageHandler
*)node
->GetData();
726 if (handler
->CanRead( stream
))
727 return handler
->LoadFile( this, stream
);
731 wxLogWarning( _("No handler found for image type.") );
735 handler
= FindHandler(type
);
739 wxLogWarning( _("No image handler for type %d defined."), type
);
744 return handler
->LoadFile( this, stream
);
747 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
751 m_refData
= new wxImageRefData
;
753 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
757 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
762 return handler
->LoadFile( this, stream
);
765 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
767 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
769 wxImageHandler
*handler
= FindHandler(type
);
773 wxLogWarning( _("No image handler for type %d defined."), type
);
778 return handler
->SaveFile( this, stream
);
781 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
783 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
785 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
789 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
794 return handler
->SaveFile( this, stream
);
796 #endif // wxUSE_STREAMS
798 void wxImage::AddHandler( wxImageHandler
*handler
)
800 // make sure that the memory will be freed at the program end
801 sm_handlers
.DeleteContents(TRUE
);
803 sm_handlers
.Append( handler
);
806 void wxImage::InsertHandler( wxImageHandler
*handler
)
808 // make sure that the memory will be freed at the program end
809 sm_handlers
.DeleteContents(TRUE
);
811 sm_handlers
.Insert( handler
);
814 bool wxImage::RemoveHandler( const wxString
& name
)
816 wxImageHandler
*handler
= FindHandler(name
);
819 sm_handlers
.DeleteObject(handler
);
826 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
828 wxNode
*node
= sm_handlers
.First();
831 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
832 if (handler
->GetName().Cmp(name
) == 0) return handler
;
836 return (wxImageHandler
*)NULL
;
839 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
841 wxNode
*node
= sm_handlers
.First();
844 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
845 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
846 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
850 return (wxImageHandler
*)NULL
;
853 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
855 wxNode
*node
= sm_handlers
.First();
858 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
859 if (handler
->GetType() == bitmapType
) return handler
;
865 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
867 wxNode
*node
= sm_handlers
.First();
870 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
871 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
877 void wxImage::InitStandardHandlers()
879 AddHandler( new wxBMPHandler
);
882 void wxImage::CleanUpHandlers()
884 wxNode
*node
= sm_handlers
.First();
887 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
888 wxNode
*next
= node
->Next();
895 //-----------------------------------------------------------------------------
897 //-----------------------------------------------------------------------------
899 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
902 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
907 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
912 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
917 bool wxImageHandler::CanRead( const wxString
& name
)
919 if (wxFileExists(name
))
921 wxFileInputStream
stream(name
);
922 return CanRead(stream
);
926 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
933 #endif // wxUSE_STREAMS
935 //-----------------------------------------------------------------------------
936 // MSW conversion routines
937 //-----------------------------------------------------------------------------
941 wxBitmap
wxImage::ConvertToBitmap() const
946 // sizeLimit is the MS upper limit for the DIB size
948 int sizeLimit
= 1024*768*3;
950 int sizeLimit
= 0x7fff ;
953 // width and height of the device-dependent bitmap
954 int width
= GetWidth();
955 int bmpHeight
= GetHeight();
957 // calc the number of bytes per scanline and padding
958 int bytePerLine
= width
*3;
959 int sizeDWORD
= sizeof( DWORD
);
960 int lineBoundary
= bytePerLine
% sizeDWORD
;
962 if( lineBoundary
> 0 )
964 padding
= sizeDWORD
- lineBoundary
;
965 bytePerLine
+= padding
;
967 // calc the number of DIBs and heights of DIBs
970 int height
= sizeLimit
/bytePerLine
;
971 if( height
>= bmpHeight
)
975 numDIB
= bmpHeight
/ height
;
976 hRemain
= bmpHeight
% height
;
977 if( hRemain
>0 ) numDIB
++;
980 // set bitmap parameters
982 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
983 bitmap
.SetWidth( width
);
984 bitmap
.SetHeight( bmpHeight
);
985 bitmap
.SetDepth( wxDisplayDepth() );
987 // create a DIB header
988 int headersize
= sizeof(BITMAPINFOHEADER
);
989 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
990 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
991 // Fill in the DIB header
992 lpDIBh
->bmiHeader
.biSize
= headersize
;
993 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
994 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
995 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
996 // the general formula for biSizeImage:
997 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
998 lpDIBh
->bmiHeader
.biPlanes
= 1;
999 lpDIBh
->bmiHeader
.biBitCount
= 24;
1000 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1001 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1002 // These seem not really needed for our purpose here.
1003 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1004 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1005 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1006 // memory for DIB data
1007 unsigned char *lpBits
;
1008 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1011 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
1016 // create and set the device-dependent bitmap
1017 HDC hdc
= ::GetDC(NULL
);
1018 HDC memdc
= ::CreateCompatibleDC( hdc
);
1020 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
1021 ::SelectObject( memdc
, hbitmap
);
1023 HPALETTE hOldPalette
= 0;
1024 if (GetPalette().Ok())
1026 hOldPalette
= ::SelectPalette(memdc
, (HPALETTE
) GetPalette().GetHPALETTE(), FALSE
);
1027 ::RealizePalette(memdc
);
1030 // copy image data into DIB data and then into DDB (in a loop)
1031 unsigned char *data
= GetData();
1034 unsigned char *ptdata
= data
;
1035 unsigned char *ptbits
;
1037 for( n
=0; n
<numDIB
; n
++ )
1039 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
1041 // redefine height and size of the (possibly) last smaller DIB
1042 // memory is not reallocated
1044 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1045 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1049 for( j
=0; j
<height
; j
++ )
1051 for( i
=0; i
<width
; i
++ )
1053 *(ptbits
++) = *(ptdata
+2);
1054 *(ptbits
++) = *(ptdata
+1);
1055 *(ptbits
++) = *(ptdata
);
1058 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
1060 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1061 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1063 // if numDIB = 1, lines below can also be used
1064 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1065 // The above line is equivalent to the following two lines.
1066 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1067 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1068 // or the following lines
1069 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1070 // HDC memdc = ::CreateCompatibleDC( hdc );
1071 // ::SelectObject( memdc, hbitmap);
1072 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1073 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1074 // ::SelectObject( memdc, 0 );
1075 // ::DeleteDC( memdc );
1077 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
1080 SelectPalette(memdc
, hOldPalette
, FALSE
);
1082 // similarly, created an mono-bitmap for the possible mask
1085 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
1086 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
1087 if( numDIB
== 1 ) height
= bmpHeight
;
1088 else height
= sizeLimit
/bytePerLine
;
1089 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1090 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1092 unsigned char r
= GetMaskRed();
1093 unsigned char g
= GetMaskGreen();
1094 unsigned char b
= GetMaskBlue();
1095 unsigned char zero
= 0, one
= 255;
1097 for( n
=0; n
<numDIB
; n
++ )
1099 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
1101 // redefine height and size of the (possibly) last smaller DIB
1102 // memory is not reallocated
1104 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1105 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1108 for( int j
=0; j
<height
; j
++ )
1110 for(i
=0; i
<width
; i
++ )
1112 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
1113 unsigned char cr
= (*(ptdata
++)) ;
1114 unsigned char cg
= (*(ptdata
++)) ;
1115 unsigned char cb
= (*(ptdata
++)) ;
1117 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
1130 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
1132 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1133 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1136 // create a wxMask object
1137 wxMask
*mask
= new wxMask();
1138 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
1139 bitmap
.SetMask( mask
);
1140 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1141 /* The following can also be used but is slow to run
1142 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1143 wxMask *mask = new wxMask( bitmap, colour );
1144 bitmap.SetMask( mask );
1147 ::SelectObject( memdc
, hbmpOld
);
1150 // free allocated resources
1151 ::DeleteDC( memdc
);
1152 ::ReleaseDC(NULL
, hdc
);
1156 #if WXWIN_COMPATIBILITY_2
1157 // check the wxBitmap object
1158 bitmap
.GetBitmapData()->SetOk();
1159 #endif // WXWIN_COMPATIBILITY_2
1164 wxImage::wxImage( const wxBitmap
&bitmap
)
1169 wxFAIL_MSG( wxT("invalid bitmap") );
1173 // create an wxImage object
1174 int width
= bitmap
.GetWidth();
1175 int height
= bitmap
.GetHeight();
1176 Create( width
, height
);
1177 unsigned char *data
= GetData();
1180 wxFAIL_MSG( wxT("could not allocate data for image") );
1184 // calc the number of bytes per scanline and padding in the DIB
1185 int bytePerLine
= width
*3;
1186 int sizeDWORD
= sizeof( DWORD
);
1187 int lineBoundary
= bytePerLine
% sizeDWORD
;
1189 if( lineBoundary
> 0 )
1191 padding
= sizeDWORD
- lineBoundary
;
1192 bytePerLine
+= padding
;
1195 // create a DIB header
1196 int headersize
= sizeof(BITMAPINFOHEADER
);
1197 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1200 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1204 // Fill in the DIB header
1205 lpDIBh
->bmiHeader
.biSize
= headersize
;
1206 lpDIBh
->bmiHeader
.biWidth
= width
;
1207 lpDIBh
->bmiHeader
.biHeight
= -height
;
1208 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
1209 lpDIBh
->bmiHeader
.biPlanes
= 1;
1210 lpDIBh
->bmiHeader
.biBitCount
= 24;
1211 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1212 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1213 // These seem not really needed for our purpose here.
1214 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1215 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1216 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1217 // memory for DIB data
1218 unsigned char *lpBits
;
1219 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1222 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1228 // copy data from the device-dependent bitmap to the DIB
1229 HDC hdc
= ::GetDC(NULL
);
1231 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1232 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1234 // copy DIB data into the wxImage object
1236 unsigned char *ptdata
= data
;
1237 unsigned char *ptbits
= lpBits
;
1238 for( i
=0; i
<height
; i
++ )
1240 for( j
=0; j
<width
; j
++ )
1242 *(ptdata
++) = *(ptbits
+2);
1243 *(ptdata
++) = *(ptbits
+1);
1244 *(ptdata
++) = *(ptbits
);
1250 // similarly, set data according to the possible mask bitmap
1251 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1253 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1254 // memory DC created, color set, data copied, and memory DC deleted
1255 HDC memdc
= ::CreateCompatibleDC( hdc
);
1256 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1257 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1258 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1259 ::DeleteDC( memdc
);
1260 // background color set to RGB(16,16,16) in consistent with wxGTK
1261 unsigned char r
=16, g
=16, b
=16;
1264 for( i
=0; i
<height
; i
++ )
1266 for( j
=0; j
<width
; j
++ )
1280 SetMaskColour( r
, g
, b
);
1287 // free allocated resources
1288 ::ReleaseDC(NULL
, hdc
);
1297 #include <PictUtils.h>
1299 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1300 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1301 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1302 extern GWorldPtr
wxMacCreateGWorld( int height
, int width
, int depth
) ;
1303 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1305 wxBitmap
wxImage::ConvertToBitmap() const
1307 // width and height of the device-dependent bitmap
1308 int width
= GetWidth();
1309 int height
= GetHeight();
1313 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1320 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1322 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1324 wxMask *mask = new wxMask();
1325 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1327 bitmap.SetMask( mask );
1333 int r_mask
= GetMaskRed();
1334 int g_mask
= GetMaskGreen();
1335 int b_mask
= GetMaskBlue();
1338 GDHandle origDevice
;
1340 GetGWorld( &origPort
, &origDevice
) ;
1341 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1343 register unsigned char* data
= GetData();
1346 for (int y
= 0; y
< height
; y
++)
1348 for (int x
= 0; x
< width
; x
++)
1350 unsigned char r
= data
[index
++];
1351 unsigned char g
= data
[index
++];
1352 unsigned char b
= data
[index
++];
1354 color
.red
= ( r
<< 8 ) + r
;
1355 color
.green
= ( g
<< 8 ) + g
;
1356 color
.blue
= ( b
<< 8 ) + b
;
1357 SetCPixel( x
, y
, &color
) ;
1361 SetGWorld( origPort
, origDevice
) ;
1365 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1366 wxMask
*mask
= new wxMask( bitmap
, colour
);
1367 bitmap
.SetMask( mask
);
1373 wxImage::wxImage( const wxBitmap
&bitmap
)
1378 wxFAIL_MSG( "invalid bitmap" );
1382 // create an wxImage object
1383 int width
= bitmap
.GetWidth();
1384 int height
= bitmap
.GetHeight();
1385 Create( width
, height
);
1387 unsigned char *data = GetData();
1390 wxFAIL_MSG( "could not allocate data for image" );
1394 // calc the number of bytes per scanline and padding in the DIB
1395 int bytePerLine = width*3;
1396 int sizeDWORD = sizeof( DWORD );
1397 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1399 if( lineBoundary.rem > 0 )
1401 padding = sizeDWORD - lineBoundary.rem;
1402 bytePerLine += padding;
1405 // create a DIB header
1406 int headersize = sizeof(BITMAPINFOHEADER);
1407 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1410 wxFAIL_MSG( "could not allocate data for DIB header" );
1414 // Fill in the DIB header
1415 lpDIBh->bmiHeader.biSize = headersize;
1416 lpDIBh->bmiHeader.biWidth = width;
1417 lpDIBh->bmiHeader.biHeight = -height;
1418 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1419 lpDIBh->bmiHeader.biPlanes = 1;
1420 lpDIBh->bmiHeader.biBitCount = 24;
1421 lpDIBh->bmiHeader.biCompression = BI_RGB;
1422 lpDIBh->bmiHeader.biClrUsed = 0;
1423 // These seem not really needed for our purpose here.
1424 lpDIBh->bmiHeader.biClrImportant = 0;
1425 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1426 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1427 // memory for DIB data
1428 unsigned char *lpBits;
1429 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1432 wxFAIL_MSG( "could not allocate data for DIB" );
1438 // copy data from the device-dependent bitmap to the DIB
1439 HDC hdc = ::GetDC(NULL);
1441 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1442 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1444 // copy DIB data into the wxImage object
1446 unsigned char *ptdata = data;
1447 unsigned char *ptbits = lpBits;
1448 for( i=0; i<height; i++ )
1450 for( j=0; j<width; j++ )
1452 *(ptdata++) = *(ptbits+2);
1453 *(ptdata++) = *(ptbits+1);
1454 *(ptdata++) = *(ptbits );
1460 // similarly, set data according to the possible mask bitmap
1461 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1463 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1464 // memory DC created, color set, data copied, and memory DC deleted
1465 HDC memdc = ::CreateCompatibleDC( hdc );
1466 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1467 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1468 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1469 ::DeleteDC( memdc );
1470 // background color set to RGB(16,16,16) in consistent with wxGTK
1471 unsigned char r=16, g=16, b=16;
1474 for( i=0; i<height; i++ )
1476 for( j=0; j<width; j++ )
1490 SetMaskColour( r, g, b );
1497 // free allocated resources
1498 ::ReleaseDC(NULL, hdc);
1506 //-----------------------------------------------------------------------------
1507 // GTK conversion routines
1508 //-----------------------------------------------------------------------------
1512 #include <gtk/gtk.h>
1513 #include <gdk/gdk.h>
1514 #include <gdk/gdkx.h>
1516 #if (GTK_MINOR_VERSION > 0)
1517 #include <gdk/gdkrgb.h>
1520 extern GtkWidget
*wxRootWindow
;
1522 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1526 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1528 int width
= GetWidth();
1529 int height
= GetHeight();
1531 bitmap
.SetHeight( height
);
1532 bitmap
.SetWidth( width
);
1534 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1536 bitmap
.SetDepth( 1 );
1538 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1541 // Create picture image
1543 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1545 GdkImage
*data_image
=
1546 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1548 // Create mask image
1550 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1554 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1556 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1558 wxMask
*mask
= new wxMask();
1559 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1561 bitmap
.SetMask( mask
);
1564 int r_mask
= GetMaskRed();
1565 int g_mask
= GetMaskGreen();
1566 int b_mask
= GetMaskBlue();
1568 unsigned char* data
= GetData();
1571 for (int y
= 0; y
< height
; y
++)
1573 for (int x
= 0; x
< width
; x
++)
1575 int r
= data
[index
];
1577 int g
= data
[index
];
1579 int b
= data
[index
];
1584 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1585 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1587 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1590 if ((r
== red
) && (b
== blue
) && (g
== green
))
1591 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1593 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1600 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1602 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1604 gdk_image_destroy( data_image
);
1605 gdk_gc_unref( data_gc
);
1611 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1613 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1615 gdk_image_destroy( mask_image
);
1616 gdk_gc_unref( mask_gc
);
1623 wxBitmap
wxImage::ConvertToBitmap() const
1627 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1629 int width
= GetWidth();
1630 int height
= GetHeight();
1632 bitmap
.SetHeight( height
);
1633 bitmap
.SetWidth( width
);
1635 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1639 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1642 int bpp
= visual
->depth
;
1644 bitmap
.SetDepth( bpp
);
1646 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1647 if (bpp
< 8) bpp
= 8;
1649 #if (GTK_MINOR_VERSION > 0)
1651 if (!HasMask() && (bpp
> 8))
1653 static bool s_hasInitialized
= FALSE
;
1655 if (!s_hasInitialized
)
1658 s_hasInitialized
= TRUE
;
1661 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1663 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1667 GDK_RGB_DITHER_NONE
,
1678 // Create picture image
1680 GdkImage
*data_image
=
1681 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1683 // Create mask image
1685 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1689 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1691 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1693 wxMask
*mask
= new wxMask();
1694 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1696 bitmap
.SetMask( mask
);
1701 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1702 byte_order b_o
= RGB
;
1706 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1707 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1708 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1709 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1710 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1711 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1714 int r_mask
= GetMaskRed();
1715 int g_mask
= GetMaskGreen();
1716 int b_mask
= GetMaskBlue();
1718 unsigned char* data
= GetData();
1721 for (int y
= 0; y
< height
; y
++)
1723 for (int x
= 0; x
< width
; x
++)
1725 int r
= data
[index
];
1727 int g
= data
[index
];
1729 int b
= data
[index
];
1734 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1735 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1737 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1745 if (wxTheApp
->m_colorCube
)
1747 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1751 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1752 GdkColor
*colors
= cmap
->colors
;
1753 int max
= 3 * (65536);
1755 for (int i
= 0; i
< cmap
->size
; i
++)
1757 int rdiff
= (r
<< 8) - colors
[i
].red
;
1758 int gdiff
= (g
<< 8) - colors
[i
].green
;
1759 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1760 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1761 if (sum
< max
) { pixel
= i
; max
= sum
; }
1765 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1771 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1772 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1777 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1778 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1787 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1788 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1789 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1790 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1791 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1792 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1794 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1803 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1805 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1807 gdk_image_destroy( data_image
);
1808 gdk_gc_unref( data_gc
);
1814 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1816 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1818 gdk_image_destroy( mask_image
);
1819 gdk_gc_unref( mask_gc
);
1825 wxImage::wxImage( const wxBitmap
&bitmap
)
1827 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1829 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1830 if (bitmap
.GetPixmap())
1832 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1834 bitmap
.GetWidth(), bitmap
.GetHeight() );
1836 if (bitmap
.GetBitmap())
1838 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1840 bitmap
.GetWidth(), bitmap
.GetHeight() );
1843 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1846 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1848 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1849 char unsigned *data
= GetData();
1853 gdk_image_destroy( gdk_image
);
1854 wxFAIL_MSG( wxT("couldn't create image") );
1858 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1859 if (bitmap
.GetMask())
1861 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1863 bitmap
.GetWidth(), bitmap
.GetHeight() );
1865 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1869 int red_shift_right
= 0;
1870 int green_shift_right
= 0;
1871 int blue_shift_right
= 0;
1872 int red_shift_left
= 0;
1873 int green_shift_left
= 0;
1874 int blue_shift_left
= 0;
1875 bool use_shift
= FALSE
;
1877 if (bitmap
.GetPixmap())
1879 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1881 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1882 bpp
= visual
->depth
;
1883 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1884 red_shift_right
= visual
->red_shift
;
1885 red_shift_left
= 8-visual
->red_prec
;
1886 green_shift_right
= visual
->green_shift
;
1887 green_shift_left
= 8-visual
->green_prec
;
1888 blue_shift_right
= visual
->blue_shift
;
1889 blue_shift_left
= 8-visual
->blue_prec
;
1891 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
1893 if (bitmap
.GetBitmap())
1899 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1902 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1904 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1906 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1924 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
1925 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
1926 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
1928 else if (cmap
->colors
)
1930 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1931 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1932 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1936 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1941 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1942 if (mask_pixel
== 0)
1954 gdk_image_destroy( gdk_image
);
1955 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1960 //-----------------------------------------------------------------------------
1961 // Motif conversion routines
1962 //-----------------------------------------------------------------------------
1966 #pragma message disable nosimpint
1970 #pragma message enable nosimpint
1972 #include "wx/utils.h"
1977 Date: Wed, 05 Jan 2000 11:45:40 +0100
1978 From: Frits Boel <boel@niob.knaw.nl>
1979 To: julian.smart@ukonline.co.uk
1980 Subject: Patch for Motif ConvertToBitmap
1984 I've been working on a wxWin application for image processing. From the
1985 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1986 till I looked in the source code of image.cpp. I saw that converting a
1987 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1988 to the 256 colors of the palet. A very time-consuming piece of code!
1990 Because I wanted a faster application, I've made a 'patch' for this. In
1991 short: every pixel of the image is compared to a sorted list with
1992 colors. If the color is found in the list, the palette entry is
1993 returned; if the color is not found, the color palette is searched and
1994 then the palette entry is returned and the color added to the sorted
1997 Maybe there is another method for this, namely changing the palette
1998 itself (if the colors are known, as is the case with tiffs with a
1999 colormap). I did not look at this, maybe someone else did?
2001 The code of the patch is attached, have a look on it, and maybe you will
2002 ship it with the next release of wxMotif?
2007 Software engineer at Hubrecht Laboratory, The Netherlands.
2014 wxSearchColor( void );
2015 wxSearchColor( int size
, XColor
*colors
);
2016 ~wxSearchColor( void );
2018 int SearchColor( int r
, int g
, int b
);
2020 int AddColor( unsigned int value
, int pos
);
2024 unsigned int *color
;
2031 wxSearchColor::wxSearchColor( void )
2034 colors
= (XColor
*) NULL
;
2035 color
= (unsigned int *) NULL
;
2036 entry
= (int*) NULL
;
2042 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
2047 color
= new unsigned int[size
];
2048 entry
= new int [size
];
2050 for (i
= 0; i
< size
; i
++ ) {
2054 bottom
= top
= ( size
>> 1 );
2057 wxSearchColor::~wxSearchColor( void )
2059 if ( color
) delete color
;
2060 if ( entry
) delete entry
;
2063 int wxSearchColor::SearchColor( int r
, int g
, int b
)
2065 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
2070 while ( begin
<= end
) {
2072 middle
= ( begin
+ end
) >> 1;
2074 if ( value
== color
[middle
] ) {
2075 return( entry
[middle
] );
2076 } else if ( value
< color
[middle
] ) {
2084 return AddColor( value
, middle
);
2087 int wxSearchColor::AddColor( unsigned int value
, int pos
)
2091 int max
= 3 * (65536);
2092 for ( i
= 0; i
< 256; i
++ ) {
2093 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
2094 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
2095 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
2096 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2097 if (sum
< max
) { pixel
= i
; max
= sum
; }
2100 if ( entry
[pos
] < 0 ) {
2103 } else if ( value
< color
[pos
] ) {
2106 for ( i
= bottom
; i
< pos
; i
++ ) {
2107 color
[i
-1] = color
[i
];
2108 entry
[i
-1] = entry
[i
];
2111 color
[pos
-1] = value
;
2112 entry
[pos
-1] = pixel
;
2113 } else if ( top
< size
-1 ) {
2114 for ( i
= top
; i
>= pos
; i
-- ) {
2115 color
[i
+1] = color
[i
];
2116 entry
[i
+1] = entry
[i
];
2125 if ( top
< size
-1 ) {
2126 for ( i
= top
; i
> pos
; i
-- ) {
2127 color
[i
+1] = color
[i
];
2128 entry
[i
+1] = entry
[i
];
2131 color
[pos
+1] = value
;
2132 entry
[pos
+1] = pixel
;
2133 } else if ( bottom
> 0 ) {
2134 for ( i
= bottom
; i
< pos
; i
++ ) {
2135 color
[i
-1] = color
[i
];
2136 entry
[i
-1] = entry
[i
];
2148 wxBitmap
wxImage::ConvertToBitmap() const
2152 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
2154 int width
= GetWidth();
2155 int height
= GetHeight();
2157 bitmap
.SetHeight( height
);
2158 bitmap
.SetWidth( width
);
2160 Display
*dpy
= (Display
*) wxGetDisplay();
2161 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2162 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2166 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2167 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
2169 bitmap
.Create( width
, height
, bpp
);
2173 XImage
*mask_image
= (XImage
*) NULL
;
2176 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2177 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
2180 // Retrieve depth info
2182 XVisualInfo vinfo_template
;
2185 vinfo_template
.visual
= vis
;
2186 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2187 vinfo_template
.depth
= bpp
;
2190 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2192 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
2196 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2197 if (bpp
< 8) bpp
= 8;
2201 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
2202 byte_order b_o
= RGB
;
2206 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2207 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2208 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2209 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2210 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2211 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2214 int r_mask
= GetMaskRed();
2215 int g_mask
= GetMaskGreen();
2216 int b_mask
= GetMaskBlue();
2221 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2223 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2224 XQueryColors( dpy
, cmap
, colors
, 256 );
2227 wxSearchColor
scolor( 256, colors
);
2228 unsigned char* data
= GetData();
2230 bool hasMask
= HasMask();
2233 for (int y
= 0; y
< height
; y
++)
2235 for (int x
= 0; x
< width
; x
++)
2237 int r
= data
[index
];
2239 int g
= data
[index
];
2241 int b
= data
[index
];
2246 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2247 XPutPixel( mask_image
, x
, y
, 0 );
2249 XPutPixel( mask_image
, x
, y
, 1 );
2256 #if 0 // Old, slower code
2259 if (wxTheApp->m_colorCube)
2261 pixel = wxTheApp->m_colorCube
2262 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2267 int max
= 3 * (65536);
2268 for (int i
= 0; i
< 256; i
++)
2270 int rdiff
= (r
<< 8) - colors
[i
].red
;
2271 int gdiff
= (g
<< 8) - colors
[i
].green
;
2272 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2273 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2274 if (sum
< max
) { pixel
= i
; max
= sum
; }
2281 // And this is all to get the 'right' color...
2282 int pixel
= scolor
.SearchColor( r
, g
, b
);
2283 XPutPixel( data_image
, x
, y
, pixel
);
2288 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2289 XPutPixel( data_image
, x
, y
, pixel
);
2294 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2295 XPutPixel( data_image
, x
, y
, pixel
);
2304 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2305 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2306 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2307 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2308 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2309 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2311 XPutPixel( data_image
, x
, y
, pixel
);
2321 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2322 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2323 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2325 XDestroyImage( data_image
);
2331 wxBitmap
maskBitmap(width
, height
, 1);
2333 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2334 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2336 XDestroyImage( mask_image
);
2337 XFreeGC( dpy
, gcMask
);
2339 wxMask
* mask
= new wxMask
;
2340 mask
->SetPixmap(maskBitmap
.GetPixmap());
2342 bitmap
.SetMask(mask
);
2344 maskBitmap
.SetPixmapNull();
2350 wxImage::wxImage( const wxBitmap
&bitmap
)
2352 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2354 Display
*dpy
= (Display
*) wxGetDisplay();
2355 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2356 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2358 XImage
*ximage
= XGetImage( dpy
,
2359 (Drawable
)bitmap
.GetPixmap(),
2361 bitmap
.GetWidth(), bitmap
.GetHeight(),
2362 AllPlanes
, ZPixmap
);
2364 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2366 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2367 char unsigned *data
= GetData();
2371 XDestroyImage( ximage
);
2372 wxFAIL_MSG( wxT("couldn't create image") );
2377 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2378 if (bitmap.GetMask())
2380 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2382 bitmap.GetWidth(), bitmap.GetHeight() );
2384 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2388 // Retrieve depth info
2390 XVisualInfo vinfo_template
;
2393 vinfo_template
.visual
= vis
;
2394 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2395 vinfo_template
.depth
= bpp
;
2398 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2400 wxCHECK_RET( vi
, wxT("no visual") );
2402 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2409 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2411 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2412 XQueryColors( dpy
, cmap
, colors
, 256 );
2416 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2418 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2420 int pixel
= XGetPixel( ximage
, i
, j
);
2423 data
[pos
] = colors
[pixel
].red
>> 8;
2424 data
[pos
+1] = colors
[pixel
].green
>> 8;
2425 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2426 } else if (bpp
== 15)
2428 data
[pos
] = (pixel
>> 7) & 0xf8;
2429 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2430 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2431 } else if (bpp
== 16)
2433 data
[pos
] = (pixel
>> 8) & 0xf8;
2434 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2435 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2438 data
[pos
] = (pixel
>> 16) & 0xff;
2439 data
[pos
+1] = (pixel
>> 8) & 0xff;
2440 data
[pos
+2] = pixel
& 0xff;
2446 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2447 if (mask_pixel == 0)
2460 XDestroyImage( ximage
);
2462 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2468 // OS/2 Presentation manager conversion routings
2470 wxBitmap
wxImage::ConvertToBitmap() const
2473 return wxNullBitmap
;
2474 wxBitmap bitmap
; // remove
2477 int sizeLimit = 1024*768*3;
2479 // width and height of the device-dependent bitmap
2480 int width = GetWidth();
2481 int bmpHeight = GetHeight();
2483 // calc the number of bytes per scanline and padding
2484 int bytePerLine = width*3;
2485 int sizeDWORD = sizeof( DWORD );
2486 int lineBoundary = bytePerLine % sizeDWORD;
2488 if( lineBoundary > 0 )
2490 padding = sizeDWORD - lineBoundary;
2491 bytePerLine += padding;
2493 // calc the number of DIBs and heights of DIBs
2496 int height = sizeLimit/bytePerLine;
2497 if( height >= bmpHeight )
2501 numDIB = bmpHeight / height;
2502 hRemain = bmpHeight % height;
2503 if( hRemain >0 ) numDIB++;
2506 // set bitmap parameters
2508 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2509 bitmap.SetWidth( width );
2510 bitmap.SetHeight( bmpHeight );
2511 bitmap.SetDepth( wxDisplayDepth() );
2513 // create a DIB header
2514 int headersize = sizeof(BITMAPINFOHEADER);
2515 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2516 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2517 // Fill in the DIB header
2518 lpDIBh->bmiHeader.biSize = headersize;
2519 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2520 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2521 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2522 // the general formula for biSizeImage:
2523 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2524 lpDIBh->bmiHeader.biPlanes = 1;
2525 lpDIBh->bmiHeader.biBitCount = 24;
2526 lpDIBh->bmiHeader.biCompression = BI_RGB;
2527 lpDIBh->bmiHeader.biClrUsed = 0;
2528 // These seem not really needed for our purpose here.
2529 lpDIBh->bmiHeader.biClrImportant = 0;
2530 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2531 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2532 // memory for DIB data
2533 unsigned char *lpBits;
2534 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2537 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2542 // create and set the device-dependent bitmap
2543 HDC hdc = ::GetDC(NULL);
2544 HDC memdc = ::CreateCompatibleDC( hdc );
2546 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2547 ::SelectObject( memdc, hbitmap);
2549 // copy image data into DIB data and then into DDB (in a loop)
2550 unsigned char *data = GetData();
2553 unsigned char *ptdata = data;
2554 unsigned char *ptbits;
2556 for( n=0; n<numDIB; n++ )
2558 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2560 // redefine height and size of the (possibly) last smaller DIB
2561 // memory is not reallocated
2563 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2564 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2568 for( j=0; j<height; j++ )
2570 for( i=0; i<width; i++ )
2572 *(ptbits++) = *(ptdata+2);
2573 *(ptbits++) = *(ptdata+1);
2574 *(ptbits++) = *(ptdata );
2577 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2579 ::StretchDIBits( memdc, 0, origin, width, height,\
2580 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2582 // if numDIB = 1, lines below can also be used
2583 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2584 // The above line is equivalent to the following two lines.
2585 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2586 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2587 // or the following lines
2588 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2589 // HDC memdc = ::CreateCompatibleDC( hdc );
2590 // ::SelectObject( memdc, hbitmap);
2591 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2592 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2593 // ::SelectObject( memdc, 0 );
2594 // ::DeleteDC( memdc );
2596 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2598 // similarly, created an mono-bitmap for the possible mask
2601 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2602 ::SelectObject( memdc, hbitmap);
2603 if( numDIB == 1 ) height = bmpHeight;
2604 else height = sizeLimit/bytePerLine;
2605 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2606 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2608 unsigned char r = GetMaskRed();
2609 unsigned char g = GetMaskGreen();
2610 unsigned char b = GetMaskBlue();
2611 unsigned char zero = 0, one = 255;
2613 for( n=0; n<numDIB; n++ )
2615 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2617 // redefine height and size of the (possibly) last smaller DIB
2618 // memory is not reallocated
2620 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2621 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2624 for( int j=0; j<height; j++ )
2626 for(i=0; i<width; i++ )
2628 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2641 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2643 ::StretchDIBits( memdc, 0, origin, width, height,\
2644 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2647 // create a wxMask object
2648 wxMask *mask = new wxMask();
2649 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2650 bitmap.SetMask( mask );
2653 // free allocated resources
2654 ::SelectObject( memdc, 0 );
2655 ::DeleteDC( memdc );
2656 ::ReleaseDC(NULL, hdc);
2660 // check the wxBitmap object
2661 if( bitmap.GetHBITMAP() )
2662 bitmap.SetOk( TRUE );
2664 bitmap.SetOk( FALSE );
2669 wxImage::wxImage( const wxBitmap
&bitmap
)
2674 wxFAIL_MSG( wxT("invalid bitmap") );
2678 // create an wxImage object
2679 int width
= bitmap
.GetWidth();
2680 int height
= bitmap
.GetHeight();
2681 Create( width
, height
);
2682 unsigned char *data
= GetData();
2685 wxFAIL_MSG( wxT("could not allocate data for image") );
2689 // calc the number of bytes per scanline and padding in the DIB
2690 int bytePerLine
= width
*3;
2691 int sizeDWORD
= sizeof( DWORD
);
2692 int lineBoundary
= bytePerLine
% sizeDWORD
;
2694 if( lineBoundary
> 0 )
2696 padding
= sizeDWORD
- lineBoundary
;
2697 bytePerLine
+= padding
;
2701 // create a DIB header
2702 int headersize = sizeof(BITMAPINFOHEADER);
2703 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2706 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2710 // Fill in the DIB header
2711 lpDIBh->bmiHeader.biSize = headersize;
2712 lpDIBh->bmiHeader.biWidth = width;
2713 lpDIBh->bmiHeader.biHeight = -height;
2714 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2715 lpDIBh->bmiHeader.biPlanes = 1;
2716 lpDIBh->bmiHeader.biBitCount = 24;
2717 lpDIBh->bmiHeader.biCompression = BI_RGB;
2718 lpDIBh->bmiHeader.biClrUsed = 0;
2719 // These seem not really needed for our purpose here.
2720 lpDIBh->bmiHeader.biClrImportant = 0;
2721 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2722 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2723 // memory for DIB data
2724 unsigned char *lpBits;
2725 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2728 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2734 // copy data from the device-dependent bitmap to the DIB
2735 HDC hdc = ::GetDC(NULL);
2737 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2738 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2740 // copy DIB data into the wxImage object
2742 unsigned char *ptdata = data;
2743 unsigned char *ptbits = lpBits;
2744 for( i=0; i<height; i++ )
2746 for( j=0; j<width; j++ )
2748 *(ptdata++) = *(ptbits+2);
2749 *(ptdata++) = *(ptbits+1);
2750 *(ptdata++) = *(ptbits );
2756 // similarly, set data according to the possible mask bitmap
2757 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2759 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2760 // memory DC created, color set, data copied, and memory DC deleted
2761 HDC memdc = ::CreateCompatibleDC( hdc );
2762 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2763 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2764 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2765 ::DeleteDC( memdc );
2766 // background color set to RGB(16,16,16) in consistent with wxGTK
2767 unsigned char r=16, g=16, b=16;
2770 for( i=0; i<height; i++ )
2772 for( j=0; j<width; j++ )
2786 SetMaskColour( r, g, b );
2793 // free allocated resources
2794 ::ReleaseDC(NULL, hdc);
2802 // A module to allow wxImage initialization/cleanup
2803 // without calling these functions from app.cpp or from
2804 // the user's application.
2806 class wxImageModule
: public wxModule
2808 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2811 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2812 void OnExit() { wxImage::CleanUpHandlers(); };
2815 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2818 //-----------------------------------------------------------------------------
2821 // Counts and returns the number of different colours. Optionally stops
2822 // when it exceeds 'stopafter' different colours. This is useful, for
2823 // example, to see if the image can be saved as 8-bit (256 colour or
2824 // less, in this case it would be invoked as CountColours(256)). Default
2825 // value for stopafter is -1 (don't care).
2827 unsigned long wxImage::CountColours( unsigned long stopafter
)
2831 unsigned char r
, g
, b
, *p
;
2832 unsigned long size
, nentries
, key
;
2835 size
= GetWidth() * GetHeight();
2838 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2843 key
= (r
<< 16) | (g
<< 8) | b
;
2845 if (h
.Get(key
) == NULL
)
2857 // Computes the histogram of the image and fills a hash table, indexed
2858 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2859 // wxHNode contains an 'index' (useful to build a palette with the image
2860 // colours) and a 'value', which is the number of pixels in the image with
2863 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2865 unsigned char r
, g
, b
, *p
;
2866 unsigned long size
, nentries
, key
;
2870 size
= GetWidth() * GetHeight();
2873 for (unsigned long j
= 0; j
< size
; j
++)
2878 key
= (r
<< 16) | (g
<< 8) | b
;
2880 hnode
= (wxHNode
*) h
.Get(key
);
2886 hnode
= new wxHNode();
2887 hnode
->index
= nentries
++;
2890 h
.Put(key
, (wxObject
*)hnode
);
2898 * Rotation code by Carlos Moreno
2901 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2902 // does exactly the same thing. And I also got rid of wxRotationPixel
2903 // bacause of potential problems in architectures where alignment
2904 // is an issue, so I had to rewrite parts of the code.
2906 static const double gs_Epsilon
= 1e-10;
2908 static inline int wxCint (double x
)
2910 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
2914 // Auxiliary function to rotate a point (x,y) with respect to point p0
2915 // make it inline and use a straight return to facilitate optimization
2916 // also, the function receives the sine and cosine of the angle to avoid
2917 // repeating the time-consuming calls to these functions -- sin/cos can
2918 // be computed and stored in the calling function.
2920 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2922 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
2923 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
2926 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2928 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
2931 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
2934 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
2936 // Create pointer-based array to accelerate access to wxImage's data
2937 unsigned char ** data
= new unsigned char * [GetHeight()];
2939 data
[0] = GetData();
2941 for (i
= 1; i
< GetHeight(); i
++)
2942 data
[i
] = data
[i
- 1] + (3 * GetWidth());
2944 // precompute coefficients for rotation formula
2945 // (sine and cosine of the angle)
2946 const double cos_angle
= cos(angle
);
2947 const double sin_angle
= sin(angle
);
2949 // Create new Image to store the result
2950 // First, find rectangle that covers the rotated image; to do that,
2951 // rotate the four corners
2953 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
2955 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
2956 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
2957 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
2958 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
2960 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
2961 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
2962 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
2963 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
2965 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
2967 if (offset_after_rotation
!= NULL
)
2969 *offset_after_rotation
= wxPoint (x1
, y1
);
2972 // GRG: The rotated (destination) image is always accessed
2973 // sequentially, so there is no need for a pointer-based
2974 // array here (and in fact it would be slower).
2976 unsigned char * dst
= rotated
.GetData();
2978 // GRG: if the original image has a mask, use its RGB values
2979 // as the blank pixel, else, fall back to default (black).
2981 unsigned char blank_r
= 0;
2982 unsigned char blank_g
= 0;
2983 unsigned char blank_b
= 0;
2987 blank_r
= GetMaskRed();
2988 blank_g
= GetMaskGreen();
2989 blank_b
= GetMaskBlue();
2990 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
2993 // Now, for each point of the rotated image, find where it came from, by
2994 // performing an inverse rotation (a rotation of -angle) and getting the
2995 // pixel at those coordinates
2997 // GRG: I've taken the (interpolating) test out of the loops, so that
2998 // it is done only once, instead of repeating it for each pixel.
3003 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3005 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3007 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3009 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
3010 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
3012 // interpolate using the 4 enclosing grid-points. Those
3013 // points can be obtained using floor and ceiling of the
3014 // exact coordinates of the point
3015 // C.M. 2000-02-17: when the point is near the border, special care is required.
3019 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
3021 x1
= wxCint(floor(src
.x
));
3022 x2
= wxCint(ceil(src
.x
));
3024 else // else means that x is near one of the borders (0 or width-1)
3026 x1
= x2
= wxCint (src
.x
);
3029 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
3031 y1
= wxCint(floor(src
.y
));
3032 y2
= wxCint(ceil(src
.y
));
3036 y1
= y2
= wxCint (src
.y
);
3039 // get four points and the distances (square of the distance,
3040 // for efficiency reasons) for the interpolation formula
3042 // GRG: Do not calculate the points until they are
3043 // really needed -- this way we can calculate
3044 // just one, instead of four, if d1, d2, d3
3045 // or d4 are < gs_Epsilon
3047 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
3048 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
3049 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
3050 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
3052 // Now interpolate as a weighted average of the four surrounding
3053 // points, where the weights are the distances to each of those points
3055 // If the point is exactly at one point of the grid of the source
3056 // image, then don't interpolate -- just assign the pixel
3058 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
3060 unsigned char *p
= data
[y1
] + (3 * x1
);
3065 else if (d2
< gs_Epsilon
)
3067 unsigned char *p
= data
[y1
] + (3 * x2
);
3072 else if (d3
< gs_Epsilon
)
3074 unsigned char *p
= data
[y2
] + (3 * x2
);
3079 else if (d4
< gs_Epsilon
)
3081 unsigned char *p
= data
[y2
] + (3 * x1
);
3088 // weights for the weighted average are proportional to the inverse of the distance
3089 unsigned char *v1
= data
[y1
] + (3 * x1
);
3090 unsigned char *v2
= data
[y1
] + (3 * x2
);
3091 unsigned char *v3
= data
[y2
] + (3 * x2
);
3092 unsigned char *v4
= data
[y2
] + (3 * x1
);
3094 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
3098 *(dst
++) = (unsigned char)
3099 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3100 w3
* *(v3
++) + w4
* *(v4
++)) /
3101 (w1
+ w2
+ w3
+ w4
) );
3102 *(dst
++) = (unsigned char)
3103 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3104 w3
* *(v3
++) + w4
* *(v4
++)) /
3105 (w1
+ w2
+ w3
+ w4
) );
3106 *(dst
++) = (unsigned char)
3107 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3108 w3
* *(v3
++) + w4
* *(v4
++)) /
3109 (w1
+ w2
+ w3
+ w4
) );
3121 else // not interpolating
3123 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3125 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3127 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3129 const int xs
= wxCint (src
.x
); // wxCint rounds to the
3130 const int ys
= wxCint (src
.y
); // closest integer
3132 if (0 <= xs
&& xs
< GetWidth() &&
3133 0 <= ys
&& ys
< GetHeight())
3135 unsigned char *p
= data
[ys
] + (3 * xs
);