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"
39 #include "wx/msw/private.h"
42 //-----------------------------------------------------------------------------
44 //-----------------------------------------------------------------------------
46 class wxImageRefData
: public wxObjectRefData
54 unsigned char *m_data
;
56 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
60 wxImageRefData::wxImageRefData()
64 m_data
= (unsigned char*) NULL
;
72 wxImageRefData::~wxImageRefData()
78 wxList
wxImage::sm_handlers
;
80 //-----------------------------------------------------------------------------
82 #define M_IMGDATA ((wxImageRefData *)m_refData)
84 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
90 wxImage::wxImage( int width
, int height
)
92 Create( width
, height
);
95 wxImage::wxImage( const wxString
& name
, long type
)
97 LoadFile( name
, type
);
100 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
)
102 LoadFile( name
, mimetype
);
106 wxImage::wxImage( wxInputStream
& stream
, long type
)
108 LoadFile( stream
, type
);
111 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
)
113 LoadFile( stream
, mimetype
);
115 #endif // wxUSE_STREAMS
117 wxImage::wxImage( const wxImage
& image
)
122 wxImage::wxImage( const wxImage
* image
)
124 if (image
) Ref(*image
);
127 void wxImage::Create( int width
, int height
)
129 m_refData
= new wxImageRefData();
131 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
132 if (M_IMGDATA
->m_data
)
134 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
136 M_IMGDATA
->m_width
= width
;
137 M_IMGDATA
->m_height
= height
;
138 M_IMGDATA
->m_ok
= TRUE
;
146 void wxImage::Destroy()
151 wxImage
wxImage::Scale( int width
, int height
) const
155 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
157 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, wxT("invalid image size") );
159 image
.Create( width
, height
);
161 char unsigned *data
= image
.GetData();
163 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
165 if (M_IMGDATA
->m_hasMask
)
166 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
168 long old_height
= M_IMGDATA
->m_height
;
169 long old_width
= M_IMGDATA
->m_width
;
171 char unsigned *source_data
= M_IMGDATA
->m_data
;
172 char unsigned *target_data
= data
;
174 for (long j
= 0; j
< height
; j
++)
176 long y_offset
= (j
* old_height
/ height
) * old_width
;
178 for (long i
= 0; i
< width
; i
++)
181 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
190 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
194 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
196 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()),
197 image
, wxT("invalid subimage size") );
199 int subwidth
=rect
.GetWidth();
200 const int subheight
=rect
.GetHeight();
202 image
.Create( subwidth
, subheight
);
204 char unsigned *subdata
= image
.GetData(), *data
=GetData();
206 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
208 if (M_IMGDATA
->m_hasMask
)
209 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
211 const int subleft
=3*rect
.GetLeft();
212 const int width
=3*GetWidth();
215 data
+=rect
.GetTop()*width
+subleft
;
217 for (long j
= 0; j
< subheight
; ++j
)
219 memcpy( subdata
, data
, subwidth
);
227 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
228 unsigned char r2
, unsigned char g2
, unsigned char b2
)
230 wxCHECK_RET( Ok(), wxT("invalid image") );
232 char unsigned *data
= GetData();
234 const int w
= GetWidth();
235 const int h
= GetHeight();
237 for (int j
= 0; j
< h
; j
++)
238 for (int i
= 0; i
< w
; i
++)
240 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
250 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
252 wxCHECK_RET( Ok(), wxT("invalid image") );
254 int w
= M_IMGDATA
->m_width
;
255 int h
= M_IMGDATA
->m_height
;
257 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
259 long pos
= (y
* w
+ x
) * 3;
261 M_IMGDATA
->m_data
[ pos
] = r
;
262 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
263 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
266 unsigned char wxImage::GetRed( int x
, int y
)
268 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
270 int w
= M_IMGDATA
->m_width
;
271 int h
= M_IMGDATA
->m_height
;
273 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
275 long pos
= (y
* w
+ x
) * 3;
277 return M_IMGDATA
->m_data
[pos
];
280 unsigned char wxImage::GetGreen( int x
, int y
)
282 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
284 int w
= M_IMGDATA
->m_width
;
285 int h
= M_IMGDATA
->m_height
;
287 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
289 long pos
= (y
* w
+ x
) * 3;
291 return M_IMGDATA
->m_data
[pos
+1];
294 unsigned char wxImage::GetBlue( int x
, int y
)
296 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
298 int w
= M_IMGDATA
->m_width
;
299 int h
= M_IMGDATA
->m_height
;
301 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
303 long pos
= (y
* w
+ x
) * 3;
305 return M_IMGDATA
->m_data
[pos
+2];
308 bool wxImage::Ok() const
310 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
313 char unsigned *wxImage::GetData() const
315 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
317 return M_IMGDATA
->m_data
;
320 void wxImage::SetData( char unsigned *data
)
322 wxCHECK_RET( Ok(), wxT("invalid image") );
324 wxImageRefData
*newRefData
= new wxImageRefData();
326 newRefData
->m_width
= M_IMGDATA
->m_width
;
327 newRefData
->m_height
= M_IMGDATA
->m_height
;
328 newRefData
->m_data
= data
;
329 newRefData
->m_ok
= TRUE
;
330 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
331 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
332 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
333 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
337 m_refData
= newRefData
;
340 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
342 wxCHECK_RET( Ok(), wxT("invalid image") );
344 M_IMGDATA
->m_maskRed
= r
;
345 M_IMGDATA
->m_maskGreen
= g
;
346 M_IMGDATA
->m_maskBlue
= b
;
347 M_IMGDATA
->m_hasMask
= TRUE
;
350 unsigned char wxImage::GetMaskRed() const
352 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
354 return M_IMGDATA
->m_maskRed
;
357 unsigned char wxImage::GetMaskGreen() const
359 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
361 return M_IMGDATA
->m_maskGreen
;
364 unsigned char wxImage::GetMaskBlue() const
366 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
368 return M_IMGDATA
->m_maskBlue
;
371 void wxImage::SetMask( bool mask
)
373 wxCHECK_RET( Ok(), wxT("invalid image") );
375 M_IMGDATA
->m_hasMask
= mask
;
378 bool wxImage::HasMask() const
380 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
382 return M_IMGDATA
->m_hasMask
;
385 int wxImage::GetWidth() const
387 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
389 return M_IMGDATA
->m_width
;
392 int wxImage::GetHeight() const
394 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
396 return M_IMGDATA
->m_height
;
399 bool wxImage::LoadFile( const wxString
& filename
, long type
)
402 if (wxFileExists(filename
))
404 wxFileInputStream
stream(filename
);
405 wxBufferedInputStream
bstream( stream
);
406 return LoadFile(bstream
, type
);
410 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
414 #else // !wxUSE_STREAMS
416 #endif // wxUSE_STREAMS
419 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
422 if (wxFileExists(filename
))
424 wxFileInputStream
stream(filename
);
425 wxBufferedInputStream
bstream( stream
);
426 return LoadFile(bstream
, mimetype
);
430 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
434 #else // !wxUSE_STREAMS
436 #endif // wxUSE_STREAMS
439 bool wxImage::SaveFile( const wxString
& filename
, int type
)
442 wxFileOutputStream
stream(filename
);
444 if ( stream
.LastError() == wxStream_NOERROR
)
446 wxBufferedOutputStream
bstream( stream
);
447 return SaveFile(bstream
, type
);
450 #endif // wxUSE_STREAMS
454 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
457 wxFileOutputStream
stream(filename
);
459 if ( stream
.LastError() == wxStream_NOERROR
)
461 wxBufferedOutputStream
bstream( stream
);
462 return SaveFile(bstream
, mimetype
);
465 #endif // wxUSE_STREAMS
469 bool wxImage::CanRead( const wxString
&name
)
472 wxFileInputStream
stream(name
);
473 return CanRead(stream
);
481 bool wxImage::CanRead( wxInputStream
&stream
)
483 wxList
&list
=GetHandlers();
485 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
487 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
488 if (handler
->CanRead( stream
))
495 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
499 m_refData
= new wxImageRefData
;
501 wxImageHandler
*handler
;
503 if (type
==wxBITMAP_TYPE_ANY
)
505 wxList
&list
=GetHandlers();
507 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
509 handler
=(wxImageHandler
*)node
->GetData();
510 if (handler
->CanRead( stream
))
511 return handler
->LoadFile( this, stream
);
515 wxLogWarning( _("No handler found for image type.") );
519 handler
= FindHandler(type
);
523 wxLogWarning( _("No image handler for type %d defined."), type
);
528 return handler
->LoadFile( this, stream
);
531 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
535 m_refData
= new wxImageRefData
;
537 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
541 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
546 return handler
->LoadFile( this, stream
);
549 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
551 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
553 wxImageHandler
*handler
= FindHandler(type
);
557 wxLogWarning( _("No image handler for type %d defined."), type
);
562 return handler
->SaveFile( this, stream
);
565 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
567 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
569 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
573 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
578 return handler
->SaveFile( this, stream
);
580 #endif // wxUSE_STREAMS
582 void wxImage::AddHandler( wxImageHandler
*handler
)
584 // make sure that the memory will be freed at the program end
585 sm_handlers
.DeleteContents(TRUE
);
587 sm_handlers
.Append( handler
);
590 void wxImage::InsertHandler( wxImageHandler
*handler
)
592 // make sure that the memory will be freed at the program end
593 sm_handlers
.DeleteContents(TRUE
);
595 sm_handlers
.Insert( handler
);
598 bool wxImage::RemoveHandler( const wxString
& name
)
600 wxImageHandler
*handler
= FindHandler(name
);
603 sm_handlers
.DeleteObject(handler
);
610 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
612 wxNode
*node
= sm_handlers
.First();
615 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
616 if (handler
->GetName().Cmp(name
) == 0) return handler
;
620 return (wxImageHandler
*)NULL
;
623 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
625 wxNode
*node
= sm_handlers
.First();
628 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
629 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
630 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
634 return (wxImageHandler
*)NULL
;
637 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
639 wxNode
*node
= sm_handlers
.First();
642 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
643 if (handler
->GetType() == bitmapType
) return handler
;
649 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
651 wxNode
*node
= sm_handlers
.First();
654 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
655 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
661 void wxImage::InitStandardHandlers()
663 AddHandler( new wxBMPHandler
);
666 void wxImage::CleanUpHandlers()
668 wxNode
*node
= sm_handlers
.First();
671 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
672 wxNode
*next
= node
->Next();
679 //-----------------------------------------------------------------------------
681 //-----------------------------------------------------------------------------
683 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
686 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
691 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
696 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
701 bool wxImageHandler::CanRead( const wxString
& name
)
703 if (wxFileExists(name
))
705 wxFileInputStream
stream(name
);
706 return CanRead(stream
);
710 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
717 #endif // wxUSE_STREAMS
719 //-----------------------------------------------------------------------------
720 // MSW conversion routines
721 //-----------------------------------------------------------------------------
725 wxBitmap
wxImage::ConvertToBitmap() const
730 // sizeLimit is the MS upper limit for the DIB size
732 int sizeLimit
= 1024*768*3;
734 int sizeLimit
= 0x7fff ;
737 // width and height of the device-dependent bitmap
738 int width
= GetWidth();
739 int bmpHeight
= GetHeight();
741 // calc the number of bytes per scanline and padding
742 int bytePerLine
= width
*3;
743 int sizeDWORD
= sizeof( DWORD
);
744 int lineBoundary
= bytePerLine
% sizeDWORD
;
746 if( lineBoundary
> 0 )
748 padding
= sizeDWORD
- lineBoundary
;
749 bytePerLine
+= padding
;
751 // calc the number of DIBs and heights of DIBs
754 int height
= sizeLimit
/bytePerLine
;
755 if( height
>= bmpHeight
)
759 numDIB
= bmpHeight
/ height
;
760 hRemain
= bmpHeight
% height
;
761 if( hRemain
>0 ) numDIB
++;
764 // set bitmap parameters
766 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
767 bitmap
.SetWidth( width
);
768 bitmap
.SetHeight( bmpHeight
);
769 bitmap
.SetDepth( wxDisplayDepth() );
771 // create a DIB header
772 int headersize
= sizeof(BITMAPINFOHEADER
);
773 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
774 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
775 // Fill in the DIB header
776 lpDIBh
->bmiHeader
.biSize
= headersize
;
777 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
778 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
779 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
780 // the general formula for biSizeImage:
781 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
782 lpDIBh
->bmiHeader
.biPlanes
= 1;
783 lpDIBh
->bmiHeader
.biBitCount
= 24;
784 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
785 lpDIBh
->bmiHeader
.biClrUsed
= 0;
786 // These seem not really needed for our purpose here.
787 lpDIBh
->bmiHeader
.biClrImportant
= 0;
788 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
789 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
790 // memory for DIB data
791 unsigned char *lpBits
;
792 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
795 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
800 // create and set the device-dependent bitmap
801 HDC hdc
= ::GetDC(NULL
);
802 HDC memdc
= ::CreateCompatibleDC( hdc
);
804 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
805 ::SelectObject( memdc
, hbitmap
);
807 // copy image data into DIB data and then into DDB (in a loop)
808 unsigned char *data
= GetData();
811 unsigned char *ptdata
= data
;
812 unsigned char *ptbits
;
814 for( n
=0; n
<numDIB
; n
++ )
816 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
818 // redefine height and size of the (possibly) last smaller DIB
819 // memory is not reallocated
821 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
822 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
826 for( j
=0; j
<height
; j
++ )
828 for( i
=0; i
<width
; i
++ )
830 *(ptbits
++) = *(ptdata
+2);
831 *(ptbits
++) = *(ptdata
+1);
832 *(ptbits
++) = *(ptdata
);
835 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
837 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
838 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
840 // if numDIB = 1, lines below can also be used
841 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
842 // The above line is equivalent to the following two lines.
843 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
844 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
845 // or the following lines
846 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
847 // HDC memdc = ::CreateCompatibleDC( hdc );
848 // ::SelectObject( memdc, hbitmap);
849 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
850 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
851 // ::SelectObject( memdc, 0 );
852 // ::DeleteDC( memdc );
854 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
856 // similarly, created an mono-bitmap for the possible mask
859 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
860 ::SelectObject( memdc
, hbitmap
);
861 if( numDIB
== 1 ) height
= bmpHeight
;
862 else height
= sizeLimit
/bytePerLine
;
863 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
864 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
866 unsigned char r
= GetMaskRed();
867 unsigned char g
= GetMaskGreen();
868 unsigned char b
= GetMaskBlue();
869 unsigned char zero
= 0, one
= 255;
871 for( n
=0; n
<numDIB
; n
++ )
873 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
875 // redefine height and size of the (possibly) last smaller DIB
876 // memory is not reallocated
878 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
879 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
882 for( int j
=0; j
<height
; j
++ )
884 for(i
=0; i
<width
; i
++ )
886 if( (*(ptdata
++)!=r
) | (*(ptdata
++)!=g
) | (*(ptdata
++)!=b
) )
899 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
901 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
902 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
905 // create a wxMask object
906 wxMask
*mask
= new wxMask();
907 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
908 bitmap
.SetMask( mask
);
909 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
910 /* The following can also be used but is slow to run
911 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
912 wxMask *mask = new wxMask( bitmap, colour );
913 bitmap.SetMask( mask );
917 // free allocated resources
918 ::SelectObject( memdc
, 0 );
920 ::ReleaseDC(NULL
, hdc
);
924 #if WXWIN_COMPATIBILITY_2
925 // check the wxBitmap object
926 bitmap
.GetBitmapData()->SetOk();
927 #endif // WXWIN_COMPATIBILITY_2
932 wxImage::wxImage( const wxBitmap
&bitmap
)
937 wxFAIL_MSG( wxT("invalid bitmap") );
941 // create an wxImage object
942 int width
= bitmap
.GetWidth();
943 int height
= bitmap
.GetHeight();
944 Create( width
, height
);
945 unsigned char *data
= GetData();
948 wxFAIL_MSG( wxT("could not allocate data for image") );
952 // calc the number of bytes per scanline and padding in the DIB
953 int bytePerLine
= width
*3;
954 int sizeDWORD
= sizeof( DWORD
);
955 int lineBoundary
= bytePerLine
% sizeDWORD
;
957 if( lineBoundary
> 0 )
959 padding
= sizeDWORD
- lineBoundary
;
960 bytePerLine
+= padding
;
963 // create a DIB header
964 int headersize
= sizeof(BITMAPINFOHEADER
);
965 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
968 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
972 // Fill in the DIB header
973 lpDIBh
->bmiHeader
.biSize
= headersize
;
974 lpDIBh
->bmiHeader
.biWidth
= width
;
975 lpDIBh
->bmiHeader
.biHeight
= -height
;
976 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
977 lpDIBh
->bmiHeader
.biPlanes
= 1;
978 lpDIBh
->bmiHeader
.biBitCount
= 24;
979 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
980 lpDIBh
->bmiHeader
.biClrUsed
= 0;
981 // These seem not really needed for our purpose here.
982 lpDIBh
->bmiHeader
.biClrImportant
= 0;
983 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
984 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
985 // memory for DIB data
986 unsigned char *lpBits
;
987 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
990 wxFAIL_MSG( wxT("could not allocate data for DIB") );
996 // copy data from the device-dependent bitmap to the DIB
997 HDC hdc
= ::GetDC(NULL
);
999 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1000 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1002 // copy DIB data into the wxImage object
1004 unsigned char *ptdata
= data
;
1005 unsigned char *ptbits
= lpBits
;
1006 for( i
=0; i
<height
; i
++ )
1008 for( j
=0; j
<width
; j
++ )
1010 *(ptdata
++) = *(ptbits
+2);
1011 *(ptdata
++) = *(ptbits
+1);
1012 *(ptdata
++) = *(ptbits
);
1018 // similarly, set data according to the possible mask bitmap
1019 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1021 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1022 // memory DC created, color set, data copied, and memory DC deleted
1023 HDC memdc
= ::CreateCompatibleDC( hdc
);
1024 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1025 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1026 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1027 ::DeleteDC( memdc
);
1028 // background color set to RGB(16,16,16) in consistent with wxGTK
1029 unsigned char r
=16, g
=16, b
=16;
1032 for( i
=0; i
<height
; i
++ )
1034 for( j
=0; j
<width
; j
++ )
1048 SetMaskColour( r
, g
, b
);
1055 // free allocated resources
1056 ::ReleaseDC(NULL
, hdc
);
1065 #include <PictUtils.h>
1067 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1068 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1069 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1070 extern GWorldPtr
wxMacCreateGWorld( int height
, int width
, int depth
) ;
1071 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1073 wxBitmap
wxImage::ConvertToBitmap() const
1075 // width and height of the device-dependent bitmap
1076 int width
= GetWidth();
1077 int height
= GetHeight();
1081 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1088 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1090 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1092 wxMask *mask = new wxMask();
1093 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1095 bitmap.SetMask( mask );
1101 int r_mask
= GetMaskRed();
1102 int g_mask
= GetMaskGreen();
1103 int b_mask
= GetMaskBlue();
1106 GDHandle origDevice
;
1108 GetGWorld( &origPort
, &origDevice
) ;
1109 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1111 register unsigned char* data
= GetData();
1114 for (int y
= 0; y
< height
; y
++)
1116 for (int x
= 0; x
< width
; x
++)
1118 unsigned char r
= data
[index
++];
1119 unsigned char g
= data
[index
++];
1120 unsigned char b
= data
[index
++];
1122 color
.red
= ( r
<< 8 ) + r
;
1123 color
.green
= ( g
<< 8 ) + g
;
1124 color
.blue
= ( b
<< 8 ) + b
;
1125 SetCPixel( x
, y
, &color
) ;
1129 SetGWorld( origPort
, origDevice
) ;
1135 wxImage::wxImage( const wxBitmap
&bitmap
)
1140 wxFAIL_MSG( "invalid bitmap" );
1144 // create an wxImage object
1145 int width
= bitmap
.GetWidth();
1146 int height
= bitmap
.GetHeight();
1147 Create( width
, height
);
1149 unsigned char *data = GetData();
1152 wxFAIL_MSG( "could not allocate data for image" );
1156 // calc the number of bytes per scanline and padding in the DIB
1157 int bytePerLine = width*3;
1158 int sizeDWORD = sizeof( DWORD );
1159 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1161 if( lineBoundary.rem > 0 )
1163 padding = sizeDWORD - lineBoundary.rem;
1164 bytePerLine += padding;
1167 // create a DIB header
1168 int headersize = sizeof(BITMAPINFOHEADER);
1169 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1172 wxFAIL_MSG( "could not allocate data for DIB header" );
1176 // Fill in the DIB header
1177 lpDIBh->bmiHeader.biSize = headersize;
1178 lpDIBh->bmiHeader.biWidth = width;
1179 lpDIBh->bmiHeader.biHeight = -height;
1180 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1181 lpDIBh->bmiHeader.biPlanes = 1;
1182 lpDIBh->bmiHeader.biBitCount = 24;
1183 lpDIBh->bmiHeader.biCompression = BI_RGB;
1184 lpDIBh->bmiHeader.biClrUsed = 0;
1185 // These seem not really needed for our purpose here.
1186 lpDIBh->bmiHeader.biClrImportant = 0;
1187 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1188 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1189 // memory for DIB data
1190 unsigned char *lpBits;
1191 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1194 wxFAIL_MSG( "could not allocate data for DIB" );
1200 // copy data from the device-dependent bitmap to the DIB
1201 HDC hdc = ::GetDC(NULL);
1203 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1204 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1206 // copy DIB data into the wxImage object
1208 unsigned char *ptdata = data;
1209 unsigned char *ptbits = lpBits;
1210 for( i=0; i<height; i++ )
1212 for( j=0; j<width; j++ )
1214 *(ptdata++) = *(ptbits+2);
1215 *(ptdata++) = *(ptbits+1);
1216 *(ptdata++) = *(ptbits );
1222 // similarly, set data according to the possible mask bitmap
1223 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1225 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1226 // memory DC created, color set, data copied, and memory DC deleted
1227 HDC memdc = ::CreateCompatibleDC( hdc );
1228 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1229 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1230 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1231 ::DeleteDC( memdc );
1232 // background color set to RGB(16,16,16) in consistent with wxGTK
1233 unsigned char r=16, g=16, b=16;
1236 for( i=0; i<height; i++ )
1238 for( j=0; j<width; j++ )
1252 SetMaskColour( r, g, b );
1259 // free allocated resources
1260 ::ReleaseDC(NULL, hdc);
1268 //-----------------------------------------------------------------------------
1269 // GTK conversion routines
1270 //-----------------------------------------------------------------------------
1274 #include <gtk/gtk.h>
1275 #include <gdk/gdk.h>
1276 #include <gdk/gdkx.h>
1278 #if (GTK_MINOR_VERSION > 0)
1279 #include <gdk/gdkrgb.h>
1282 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1286 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1288 int width
= GetWidth();
1289 int height
= GetHeight();
1291 bitmap
.SetHeight( height
);
1292 bitmap
.SetWidth( width
);
1294 bitmap
.SetBitmap( gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 ) );
1296 bitmap
.SetDepth( 1 );
1298 // Create picture image
1300 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1302 GdkImage
*data_image
=
1303 gdk_image_new_bitmap( gdk_visual_get_system(), data_data
, width
, height
);
1305 // Create mask image
1307 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1311 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1313 mask_image
= gdk_image_new_bitmap( gdk_visual_get_system(), mask_data
, width
, height
);
1315 wxMask
*mask
= new wxMask();
1316 mask
->m_bitmap
= gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 );
1318 bitmap
.SetMask( mask
);
1321 int r_mask
= GetMaskRed();
1322 int g_mask
= GetMaskGreen();
1323 int b_mask
= GetMaskBlue();
1325 unsigned char* data
= GetData();
1328 for (int y
= 0; y
< height
; y
++)
1330 for (int x
= 0; x
< width
; x
++)
1332 int r
= data
[index
];
1334 int g
= data
[index
];
1336 int b
= data
[index
];
1341 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1342 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1344 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1347 if ((r
== red
) && (b
== blue
) && (g
== green
))
1348 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1350 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1357 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1359 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1361 gdk_image_destroy( data_image
);
1362 gdk_gc_unref( data_gc
);
1368 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1370 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1372 gdk_image_destroy( mask_image
);
1373 gdk_gc_unref( mask_gc
);
1380 wxBitmap
wxImage::ConvertToBitmap() const
1384 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1386 int width
= GetWidth();
1387 int height
= GetHeight();
1389 bitmap
.SetHeight( height
);
1390 bitmap
.SetWidth( width
);
1392 bitmap
.SetPixmap( gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, -1 ) );
1396 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1397 if (visual
== NULL
) visual
= gdk_visual_get_system();
1398 int bpp
= visual
->depth
;
1400 bitmap
.SetDepth( bpp
);
1402 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1403 if (bpp
< 8) bpp
= 8;
1405 #if (GTK_MINOR_VERSION > 0)
1407 if (!HasMask() && (bpp
> 8))
1409 static bool s_hasInitialized
= FALSE
;
1411 if (!s_hasInitialized
)
1414 s_hasInitialized
= TRUE
;
1417 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1419 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1423 GDK_RGB_DITHER_NONE
,
1434 // Create picture image
1436 GdkImage
*data_image
=
1437 gdk_image_new( GDK_IMAGE_FASTEST
, gdk_visual_get_system(), width
, height
);
1439 // Create mask image
1441 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1445 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1447 mask_image
= gdk_image_new_bitmap( gdk_visual_get_system(), mask_data
, width
, height
);
1449 wxMask
*mask
= new wxMask();
1450 mask
->m_bitmap
= gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 );
1452 bitmap
.SetMask( mask
);
1457 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1458 byte_order b_o
= RGB
;
1462 GdkVisual
*visual
= gdk_visual_get_system();
1463 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1464 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1465 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1466 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1467 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1468 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1471 int r_mask
= GetMaskRed();
1472 int g_mask
= GetMaskGreen();
1473 int b_mask
= GetMaskBlue();
1475 unsigned char* data
= GetData();
1478 for (int y
= 0; y
< height
; y
++)
1480 for (int x
= 0; x
< width
; x
++)
1482 int r
= data
[index
];
1484 int g
= data
[index
];
1486 int b
= data
[index
];
1491 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1492 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1494 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1502 if (wxTheApp
->m_colorCube
)
1504 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1508 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1509 GdkColor
*colors
= cmap
->colors
;
1510 int max
= 3 * (65536);
1512 for (int i
= 0; i
< cmap
->size
; i
++)
1514 int rdiff
= (r
<< 8) - colors
[i
].red
;
1515 int gdiff
= (g
<< 8) - colors
[i
].green
;
1516 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1517 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1518 if (sum
< max
) { pixel
= i
; max
= sum
; }
1522 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1528 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1529 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1534 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1535 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1544 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1545 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1546 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1547 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1548 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1549 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1551 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1560 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1562 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1564 gdk_image_destroy( data_image
);
1565 gdk_gc_unref( data_gc
);
1571 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1573 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1575 gdk_image_destroy( mask_image
);
1576 gdk_gc_unref( mask_gc
);
1582 wxImage::wxImage( const wxBitmap
&bitmap
)
1584 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1586 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1587 if (bitmap
.GetPixmap())
1589 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1591 bitmap
.GetWidth(), bitmap
.GetHeight() );
1593 if (bitmap
.GetBitmap())
1595 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1597 bitmap
.GetWidth(), bitmap
.GetHeight() );
1600 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1603 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1605 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1606 char unsigned *data
= GetData();
1610 gdk_image_destroy( gdk_image
);
1611 wxFAIL_MSG( wxT("couldn't create image") );
1615 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1616 if (bitmap
.GetMask())
1618 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1620 bitmap
.GetWidth(), bitmap
.GetHeight() );
1622 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1626 if (bitmap
.GetPixmap())
1628 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1630 if (visual
== NULL
) visual
= gdk_window_get_visual( (GdkWindow
*) &gdk_root_parent
);
1631 bpp
= visual
->depth
;
1632 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1634 if (bitmap
.GetBitmap())
1639 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1642 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1644 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1646 wxInt32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1661 } else if (bpp
<= 8)
1663 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1664 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1665 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1666 } else if (bpp
== 15)
1668 #if (wxBYTE_ORDER == wxBIG_ENDIAN)
1671 data
[pos
] = (pixel
>> 7) & 0xf8;
1672 data
[pos
+1] = (pixel
>> 2) & 0xf8;
1673 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1674 } else if (bpp
== 16)
1676 #if (wxBYTE_ORDER == wxBIG_ENDIAN)
1679 data
[pos
] = (pixel
>> 8) & 0xf8;
1680 data
[pos
+1] = (pixel
>> 3) & 0xfc;
1681 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1684 #if (wxBYTE_ORDER == wxBIG_ENDIAN)
1685 data
[pos
] = (pixel
) & 0xff; // Red
1686 data
[pos
+1] = (pixel
>> 8) & 0xff; // Green
1687 data
[pos
+2] = (pixel
>> 16) & 0xff; // Blue
1689 data
[pos
] = (pixel
>> 16) & 0xff;
1690 data
[pos
+1] = (pixel
>> 8) & 0xff;
1691 data
[pos
+2] = pixel
& 0xff;
1697 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1698 if (mask_pixel
== 0)
1710 gdk_image_destroy( gdk_image
);
1711 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1716 //-----------------------------------------------------------------------------
1717 // Motif conversion routines
1718 //-----------------------------------------------------------------------------
1722 #pragma message disable nosimpint
1726 #pragma message enable nosimpint
1728 #include "wx/utils.h"
1733 Date: Wed, 05 Jan 2000 11:45:40 +0100
1734 From: Frits Boel <boel@niob.knaw.nl>
1735 To: julian.smart@ukonline.co.uk
1736 Subject: Patch for Motif ConvertToBitmap
1740 I've been working on a wxWin application for image processing. From the
1741 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1742 till I looked in the source code of image.cpp. I saw that converting a
1743 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1744 to the 256 colors of the palet. A very time-consuming piece of code!
1746 Because I wanted a faster application, I've made a 'patch' for this. In
1747 short: every pixel of the image is compared to a sorted list with
1748 colors. If the color is found in the list, the palette entry is
1749 returned; if the color is not found, the color palette is searched and
1750 then the palette entry is returned and the color added to the sorted
1753 Maybe there is another method for this, namely changing the palette
1754 itself (if the colors are known, as is the case with tiffs with a
1755 colormap). I did not look at this, maybe someone else did?
1757 The code of the patch is attached, have a look on it, and maybe you will
1758 ship it with the next release of wxMotif?
1763 Software engineer at Hubrecht Laboratory, The Netherlands.
1770 wxSearchColor( void );
1771 wxSearchColor( int size
, XColor
*colors
);
1772 ~wxSearchColor( void );
1774 int SearchColor( int r
, int g
, int b
);
1776 int AddColor( unsigned int value
, int pos
);
1780 unsigned int *color
;
1787 wxSearchColor::wxSearchColor( void )
1790 this->colors
= (XColor
*) NULL
;
1791 this->color
= (unsigned int *) NULL
;
1792 this->entry
= (int*) NULL
;
1798 wxSearchColor::wxSearchColor( int size
, XColor
*colors
)
1802 this->colors
= colors
;
1803 this->color
= new unsigned int[size
];
1804 this->entry
= new int [size
];
1806 for (i
= 0; i
< this->size
; i
++ ) {
1807 this->entry
[i
] = -1;
1810 this->bottom
= this->top
= ( size
>> 1 );
1813 wxSearchColor::~wxSearchColor( void )
1815 if ( this->color
) delete this->color
;
1816 if ( this->entry
) delete this->entry
;
1819 int wxSearchColor::SearchColor( int r
, int g
, int b
)
1821 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
1822 int begin
= this->bottom
;
1823 int end
= this->top
;
1826 while ( begin
<= end
) {
1828 middle
= ( begin
+ end
) >> 1;
1830 if ( value
== this->color
[middle
] ) {
1831 return( this->entry
[middle
] );
1832 } else if ( value
< this->color
[middle
] ) {
1840 return AddColor( value
, middle
);
1843 int wxSearchColor::AddColor( unsigned int value
, int pos
)
1847 int max
= 3 * (65536);
1848 for ( i
= 0; i
< 256; i
++ ) {
1849 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
1850 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
1851 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
1852 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1853 if (sum
< max
) { pixel
= i
; max
= sum
; }
1856 if ( this->entry
[pos
] < 0 ) {
1857 this->color
[pos
] = value
;
1858 this->entry
[pos
] = pixel
;
1859 } else if ( value
< this->color
[pos
] ) {
1861 if ( this->bottom
> 0 ) {
1862 for ( i
= this->bottom
; i
< pos
; i
++ ) {
1863 this->color
[i
-1] = this->color
[i
];
1864 this->entry
[i
-1] = this->entry
[i
];
1867 this->color
[pos
-1] = value
;
1868 this->entry
[pos
-1] = pixel
;
1869 } else if ( this->top
< this->size
-1 ) {
1870 for ( i
= this->top
; i
>= pos
; i
-- ) {
1871 this->color
[i
+1] = this->color
[i
];
1872 this->entry
[i
+1] = this->entry
[i
];
1875 this->color
[pos
] = value
;
1876 this->entry
[pos
] = pixel
;
1881 if ( this->top
< this->size
-1 ) {
1882 for ( i
= this->top
; i
> pos
; i
-- ) {
1883 this->color
[i
+1] = this->color
[i
];
1884 this->entry
[i
+1] = this->entry
[i
];
1887 this->color
[pos
+1] = value
;
1888 this->entry
[pos
+1] = pixel
;
1889 } else if ( this->bottom
> 0 ) {
1890 for ( i
= this->bottom
; i
< pos
; i
++ ) {
1891 this->color
[i
-1] = this->color
[i
];
1892 this->entry
[i
-1] = this->entry
[i
];
1895 this->color
[pos
] = value
;
1896 this->entry
[pos
] = pixel
;
1904 wxBitmap
wxImage::ConvertToBitmap() const
1908 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1910 int width
= GetWidth();
1911 int height
= GetHeight();
1913 bitmap
.SetHeight( height
);
1914 bitmap
.SetWidth( width
);
1916 Display
*dpy
= (Display
*) wxGetDisplay();
1917 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1918 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1922 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1923 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
1925 bitmap
.Create( width
, height
, bpp
);
1930 GdkImage *mask_image = (GdkImage*) NULL;
1934 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1936 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1938 wxMask *mask = new wxMask();
1939 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1941 bitmap.SetMask( mask );
1945 // Retrieve depth info
1947 XVisualInfo vinfo_template
;
1950 vinfo_template
.visual
= vis
;
1951 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1952 vinfo_template
.depth
= bpp
;
1955 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1957 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
1961 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1962 if (bpp
< 8) bpp
= 8;
1966 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1967 byte_order b_o
= RGB
;
1971 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
1972 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
1973 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
1974 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
1975 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
1976 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
1980 int r_mask = GetMaskRed();
1981 int g_mask = GetMaskGreen();
1982 int b_mask = GetMaskBlue();
1988 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
1990 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
1991 XQueryColors( dpy
, cmap
, colors
, 256 );
1994 wxSearchColor
scolor( 256, colors
);
1995 unsigned char* data
= GetData();
1998 for (int y
= 0; y
< height
; y
++)
2000 for (int x
= 0; x
< width
; x
++)
2002 int r
= data
[index
];
2004 int g
= data
[index
];
2006 int b
= data
[index
];
2012 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2013 gdk_image_put_pixel( mask_image, x, y, 1 );
2015 gdk_image_put_pixel( mask_image, x, y, 0 );
2023 #if 0 // Old, slower code
2026 if (wxTheApp->m_colorCube)
2028 pixel = wxTheApp->m_colorCube
2029 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2034 int max
= 3 * (65536);
2035 for (int i
= 0; i
< 256; i
++)
2037 int rdiff
= (r
<< 8) - colors
[i
].red
;
2038 int gdiff
= (g
<< 8) - colors
[i
].green
;
2039 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2040 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2041 if (sum
< max
) { pixel
= i
; max
= sum
; }
2048 // And this is all to get the 'right' color...
2049 int pixel
= scolor
.SearchColor( r
, g
, b
);
2050 XPutPixel( data_image
, x
, y
, pixel
);
2055 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2056 XPutPixel( data_image
, x
, y
, pixel
);
2061 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2062 XPutPixel( data_image
, x
, y
, pixel
);
2071 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2072 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2073 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2074 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2075 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2076 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2078 XPutPixel( data_image
, x
, y
, pixel
);
2088 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2089 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2090 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2092 XDestroyImage( data_image
);
2100 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
2102 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
2104 gdk_image_destroy( mask_image );
2105 gdk_gc_unref( mask_gc );
2112 wxImage::wxImage( const wxBitmap
&bitmap
)
2114 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2116 Display
*dpy
= (Display
*) wxGetDisplay();
2117 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2118 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2120 XImage
*ximage
= XGetImage( dpy
,
2121 (Drawable
)bitmap
.GetPixmap(),
2123 bitmap
.GetWidth(), bitmap
.GetHeight(),
2124 AllPlanes
, ZPixmap
);
2126 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2128 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2129 char unsigned *data
= GetData();
2133 XDestroyImage( ximage
);
2134 wxFAIL_MSG( wxT("couldn't create image") );
2139 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2140 if (bitmap.GetMask())
2142 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2144 bitmap.GetWidth(), bitmap.GetHeight() );
2146 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2150 // Retrieve depth info
2152 XVisualInfo vinfo_template
;
2155 vinfo_template
.visual
= vis
;
2156 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2157 vinfo_template
.depth
= bpp
;
2160 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2162 wxCHECK_RET( vi
, wxT("no visual") );
2164 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2171 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2173 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2174 XQueryColors( dpy
, cmap
, colors
, 256 );
2178 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2180 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2182 int pixel
= XGetPixel( ximage
, i
, j
);
2185 data
[pos
] = colors
[pixel
].red
>> 8;
2186 data
[pos
+1] = colors
[pixel
].green
>> 8;
2187 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2188 } else if (bpp
== 15)
2190 data
[pos
] = (pixel
>> 7) & 0xf8;
2191 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2192 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2193 } else if (bpp
== 16)
2195 data
[pos
] = (pixel
>> 8) & 0xf8;
2196 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2197 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2200 data
[pos
] = (pixel
>> 16) & 0xff;
2201 data
[pos
+1] = (pixel
>> 8) & 0xff;
2202 data
[pos
+2] = pixel
& 0xff;
2208 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2209 if (mask_pixel == 0)
2222 XDestroyImage( ximage
);
2224 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2230 // OS/2 Presentation manager conversion routings
2232 wxBitmap
wxImage::ConvertToBitmap() const
2235 return wxNullBitmap
;
2236 wxBitmap bitmap
; // remove
2239 int sizeLimit = 1024*768*3;
2241 // width and height of the device-dependent bitmap
2242 int width = GetWidth();
2243 int bmpHeight = GetHeight();
2245 // calc the number of bytes per scanline and padding
2246 int bytePerLine = width*3;
2247 int sizeDWORD = sizeof( DWORD );
2248 int lineBoundary = bytePerLine % sizeDWORD;
2250 if( lineBoundary > 0 )
2252 padding = sizeDWORD - lineBoundary;
2253 bytePerLine += padding;
2255 // calc the number of DIBs and heights of DIBs
2258 int height = sizeLimit/bytePerLine;
2259 if( height >= bmpHeight )
2263 numDIB = bmpHeight / height;
2264 hRemain = bmpHeight % height;
2265 if( hRemain >0 ) numDIB++;
2268 // set bitmap parameters
2270 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2271 bitmap.SetWidth( width );
2272 bitmap.SetHeight( bmpHeight );
2273 bitmap.SetDepth( wxDisplayDepth() );
2275 // create a DIB header
2276 int headersize = sizeof(BITMAPINFOHEADER);
2277 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2278 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2279 // Fill in the DIB header
2280 lpDIBh->bmiHeader.biSize = headersize;
2281 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2282 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2283 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2284 // the general formula for biSizeImage:
2285 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2286 lpDIBh->bmiHeader.biPlanes = 1;
2287 lpDIBh->bmiHeader.biBitCount = 24;
2288 lpDIBh->bmiHeader.biCompression = BI_RGB;
2289 lpDIBh->bmiHeader.biClrUsed = 0;
2290 // These seem not really needed for our purpose here.
2291 lpDIBh->bmiHeader.biClrImportant = 0;
2292 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2293 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2294 // memory for DIB data
2295 unsigned char *lpBits;
2296 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2299 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2304 // create and set the device-dependent bitmap
2305 HDC hdc = ::GetDC(NULL);
2306 HDC memdc = ::CreateCompatibleDC( hdc );
2308 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2309 ::SelectObject( memdc, hbitmap);
2311 // copy image data into DIB data and then into DDB (in a loop)
2312 unsigned char *data = GetData();
2315 unsigned char *ptdata = data;
2316 unsigned char *ptbits;
2318 for( n=0; n<numDIB; n++ )
2320 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2322 // redefine height and size of the (possibly) last smaller DIB
2323 // memory is not reallocated
2325 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2326 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2330 for( j=0; j<height; j++ )
2332 for( i=0; i<width; i++ )
2334 *(ptbits++) = *(ptdata+2);
2335 *(ptbits++) = *(ptdata+1);
2336 *(ptbits++) = *(ptdata );
2339 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2341 ::StretchDIBits( memdc, 0, origin, width, height,\
2342 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2344 // if numDIB = 1, lines below can also be used
2345 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2346 // The above line is equivalent to the following two lines.
2347 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2348 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2349 // or the following lines
2350 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2351 // HDC memdc = ::CreateCompatibleDC( hdc );
2352 // ::SelectObject( memdc, hbitmap);
2353 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2354 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2355 // ::SelectObject( memdc, 0 );
2356 // ::DeleteDC( memdc );
2358 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2360 // similarly, created an mono-bitmap for the possible mask
2363 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2364 ::SelectObject( memdc, hbitmap);
2365 if( numDIB == 1 ) height = bmpHeight;
2366 else height = sizeLimit/bytePerLine;
2367 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2368 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2370 unsigned char r = GetMaskRed();
2371 unsigned char g = GetMaskGreen();
2372 unsigned char b = GetMaskBlue();
2373 unsigned char zero = 0, one = 255;
2375 for( n=0; n<numDIB; n++ )
2377 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2379 // redefine height and size of the (possibly) last smaller DIB
2380 // memory is not reallocated
2382 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2383 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2386 for( int j=0; j<height; j++ )
2388 for(i=0; i<width; i++ )
2390 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2403 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2405 ::StretchDIBits( memdc, 0, origin, width, height,\
2406 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2409 // create a wxMask object
2410 wxMask *mask = new wxMask();
2411 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2412 bitmap.SetMask( mask );
2415 // free allocated resources
2416 ::SelectObject( memdc, 0 );
2417 ::DeleteDC( memdc );
2418 ::ReleaseDC(NULL, hdc);
2422 // check the wxBitmap object
2423 if( bitmap.GetHBITMAP() )
2424 bitmap.SetOk( TRUE );
2426 bitmap.SetOk( FALSE );
2431 wxImage::wxImage( const wxBitmap
&bitmap
)
2436 wxFAIL_MSG( wxT("invalid bitmap") );
2440 // create an wxImage object
2441 int width
= bitmap
.GetWidth();
2442 int height
= bitmap
.GetHeight();
2443 Create( width
, height
);
2444 unsigned char *data
= GetData();
2447 wxFAIL_MSG( wxT("could not allocate data for image") );
2451 // calc the number of bytes per scanline and padding in the DIB
2452 int bytePerLine
= width
*3;
2453 int sizeDWORD
= sizeof( DWORD
);
2454 int lineBoundary
= bytePerLine
% sizeDWORD
;
2456 if( lineBoundary
> 0 )
2458 padding
= sizeDWORD
- lineBoundary
;
2459 bytePerLine
+= padding
;
2463 // create a DIB header
2464 int headersize = sizeof(BITMAPINFOHEADER);
2465 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2468 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2472 // Fill in the DIB header
2473 lpDIBh->bmiHeader.biSize = headersize;
2474 lpDIBh->bmiHeader.biWidth = width;
2475 lpDIBh->bmiHeader.biHeight = -height;
2476 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2477 lpDIBh->bmiHeader.biPlanes = 1;
2478 lpDIBh->bmiHeader.biBitCount = 24;
2479 lpDIBh->bmiHeader.biCompression = BI_RGB;
2480 lpDIBh->bmiHeader.biClrUsed = 0;
2481 // These seem not really needed for our purpose here.
2482 lpDIBh->bmiHeader.biClrImportant = 0;
2483 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2484 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2485 // memory for DIB data
2486 unsigned char *lpBits;
2487 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2490 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2496 // copy data from the device-dependent bitmap to the DIB
2497 HDC hdc = ::GetDC(NULL);
2499 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2500 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2502 // copy DIB data into the wxImage object
2504 unsigned char *ptdata = data;
2505 unsigned char *ptbits = lpBits;
2506 for( i=0; i<height; i++ )
2508 for( j=0; j<width; j++ )
2510 *(ptdata++) = *(ptbits+2);
2511 *(ptdata++) = *(ptbits+1);
2512 *(ptdata++) = *(ptbits );
2518 // similarly, set data according to the possible mask bitmap
2519 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2521 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2522 // memory DC created, color set, data copied, and memory DC deleted
2523 HDC memdc = ::CreateCompatibleDC( hdc );
2524 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2525 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2526 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2527 ::DeleteDC( memdc );
2528 // background color set to RGB(16,16,16) in consistent with wxGTK
2529 unsigned char r=16, g=16, b=16;
2532 for( i=0; i<height; i++ )
2534 for( j=0; j<width; j++ )
2548 SetMaskColour( r, g, b );
2555 // free allocated resources
2556 ::ReleaseDC(NULL, hdc);
2564 // A module to allow wxImage initialization/cleanup
2565 // without calling these functions from app.cpp or from
2566 // the user's application.
2568 class wxImageModule
: public wxModule
2570 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2573 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2574 void OnExit() { wxImage::CleanUpHandlers(); };
2577 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2580 //-----------------------------------------------------------------------------
2583 // Counts and returns the number of different colours. Optionally stops
2584 // when it exceeds 'stopafter' different colours. This is useful, for
2585 // example, to see if the image can be saved as 8-bit (256 colour or
2586 // less, in this case it would be invoked as CountColours(256)). Default
2587 // value for stopafter is -1 (don't care).
2589 unsigned long wxImage::CountColours( unsigned long stopafter
)
2594 unsigned char r
, g
, b
, *p
;
2595 unsigned long size
, nentries
, key
;
2598 size
= GetWidth() * GetHeight();
2601 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2606 key
= (r
<< 16) | (g
<< 8) | b
;
2608 hnode
= (wxHNode
*) h
.Get(key
);
2612 h
.Put(key
, (wxObject
*)(new wxHNode
));
2617 // delete all HNodes
2619 while ((node
= h
.Next()) != NULL
)
2620 delete (wxHNode
*)node
->GetData();
2627 // Computes the histogram of the image and fills a hash table, indexed
2628 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2629 // wxHNode contains an 'index' (useful to build a palette with the image
2630 // colours) and a 'value', which is the number of pixels in the image with
2633 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2635 unsigned char r
, g
, b
, *p
;
2636 unsigned long size
, nentries
, key
;
2640 size
= GetWidth() * GetHeight();
2643 for (unsigned long j
= 0; j
< size
; j
++)
2648 key
= (r
<< 16) | (g
<< 8) | b
;
2650 hnode
= (wxHNode
*) h
.Get(key
);
2656 hnode
= new wxHNode();
2657 hnode
->index
= nentries
++;
2660 h
.Put(key
, (wxObject
*)hnode
);