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
++)
1117 unsigned char lastr
= 0 ;
1118 unsigned char lastg
= 0 ;
1119 unsigned char lastb
= 0 ;
1120 RGBColor lastcolor
;
1123 for (int x
= 0; x
< width
; x
++)
1125 unsigned char r
= data
[index
++];
1126 unsigned char g
= data
[index
++];
1127 unsigned char b
= data
[index
++];
1129 if ( r
!= lastr
|| g
!= lastg
|| b
!= lastb
)
1131 lastcolor
.red
= ( lastr
<< 8 ) + lastr
;
1132 lastcolor
.green
= ( lastg
<< 8 ) + lastg
;
1133 lastcolor
.blue
= ( lastb
<< 8 ) + lastb
;
1134 RGBForeColor( &lastcolor
) ;
1141 lastcolor
.red
= ( lastr
<< 8 ) + lastr
;
1142 lastcolor
.green
= ( lastg
<< 8 ) + lastg
;
1143 lastcolor
.blue
= ( lastb
<< 8 ) + lastb
;
1144 RGBForeColor( &lastcolor
) ;
1145 LineTo( width
- 1 , y
) ;
1147 for (int x
= 0; x
< width
; x
++)
1149 unsigned char r
= data
[index
++];
1150 unsigned char g
= data
[index
++];
1151 unsigned char b
= data
[index
++];
1153 color
.red
= ( r
<< 8 ) + r
;
1154 color
.green
= ( g
<< 8 ) + g
;
1155 color
.blue
= ( b
<< 8 ) + b
;
1156 SetCPixel( x
, y
, &color
) ;
1161 SetGWorld( origPort
, origDevice
) ;
1167 wxImage::wxImage( const wxBitmap
&bitmap
)
1172 wxFAIL_MSG( "invalid bitmap" );
1176 // create an wxImage object
1177 int width
= bitmap
.GetWidth();
1178 int height
= bitmap
.GetHeight();
1179 Create( width
, height
);
1181 unsigned char *data = GetData();
1184 wxFAIL_MSG( "could not allocate data for image" );
1188 // calc the number of bytes per scanline and padding in the DIB
1189 int bytePerLine = width*3;
1190 int sizeDWORD = sizeof( DWORD );
1191 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1193 if( lineBoundary.rem > 0 )
1195 padding = sizeDWORD - lineBoundary.rem;
1196 bytePerLine += padding;
1199 // create a DIB header
1200 int headersize = sizeof(BITMAPINFOHEADER);
1201 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1204 wxFAIL_MSG( "could not allocate data for DIB header" );
1208 // Fill in the DIB header
1209 lpDIBh->bmiHeader.biSize = headersize;
1210 lpDIBh->bmiHeader.biWidth = width;
1211 lpDIBh->bmiHeader.biHeight = -height;
1212 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1213 lpDIBh->bmiHeader.biPlanes = 1;
1214 lpDIBh->bmiHeader.biBitCount = 24;
1215 lpDIBh->bmiHeader.biCompression = BI_RGB;
1216 lpDIBh->bmiHeader.biClrUsed = 0;
1217 // These seem not really needed for our purpose here.
1218 lpDIBh->bmiHeader.biClrImportant = 0;
1219 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1220 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1221 // memory for DIB data
1222 unsigned char *lpBits;
1223 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1226 wxFAIL_MSG( "could not allocate data for DIB" );
1232 // copy data from the device-dependent bitmap to the DIB
1233 HDC hdc = ::GetDC(NULL);
1235 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1236 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1238 // copy DIB data into the wxImage object
1240 unsigned char *ptdata = data;
1241 unsigned char *ptbits = lpBits;
1242 for( i=0; i<height; i++ )
1244 for( j=0; j<width; j++ )
1246 *(ptdata++) = *(ptbits+2);
1247 *(ptdata++) = *(ptbits+1);
1248 *(ptdata++) = *(ptbits );
1254 // similarly, set data according to the possible mask bitmap
1255 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1257 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1258 // memory DC created, color set, data copied, and memory DC deleted
1259 HDC memdc = ::CreateCompatibleDC( hdc );
1260 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1261 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1262 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1263 ::DeleteDC( memdc );
1264 // background color set to RGB(16,16,16) in consistent with wxGTK
1265 unsigned char r=16, g=16, b=16;
1268 for( i=0; i<height; i++ )
1270 for( j=0; j<width; j++ )
1284 SetMaskColour( r, g, b );
1291 // free allocated resources
1292 ::ReleaseDC(NULL, hdc);
1300 //-----------------------------------------------------------------------------
1301 // GTK conversion routines
1302 //-----------------------------------------------------------------------------
1306 #include <gtk/gtk.h>
1307 #include <gdk/gdk.h>
1308 #include <gdk/gdkx.h>
1310 #if (GTK_MINOR_VERSION > 0)
1311 #include <gdk/gdkrgb.h>
1314 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1318 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1320 int width
= GetWidth();
1321 int height
= GetHeight();
1323 bitmap
.SetHeight( height
);
1324 bitmap
.SetWidth( width
);
1326 bitmap
.SetBitmap( gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 ) );
1328 bitmap
.SetDepth( 1 );
1330 // Create picture image
1332 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1334 GdkImage
*data_image
=
1335 gdk_image_new_bitmap( gdk_visual_get_system(), data_data
, width
, height
);
1337 // Create mask image
1339 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1343 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1345 mask_image
= gdk_image_new_bitmap( gdk_visual_get_system(), mask_data
, width
, height
);
1347 wxMask
*mask
= new wxMask();
1348 mask
->m_bitmap
= gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 );
1350 bitmap
.SetMask( mask
);
1353 int r_mask
= GetMaskRed();
1354 int g_mask
= GetMaskGreen();
1355 int b_mask
= GetMaskBlue();
1357 unsigned char* data
= GetData();
1360 for (int y
= 0; y
< height
; y
++)
1362 for (int x
= 0; x
< width
; x
++)
1364 int r
= data
[index
];
1366 int g
= data
[index
];
1368 int b
= data
[index
];
1373 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1374 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1376 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1379 if ((r
== red
) && (b
== blue
) && (g
== green
))
1380 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1382 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1389 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1391 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1393 gdk_image_destroy( data_image
);
1394 gdk_gc_unref( data_gc
);
1400 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1402 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1404 gdk_image_destroy( mask_image
);
1405 gdk_gc_unref( mask_gc
);
1412 wxBitmap
wxImage::ConvertToBitmap() const
1416 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1418 int width
= GetWidth();
1419 int height
= GetHeight();
1421 bitmap
.SetHeight( height
);
1422 bitmap
.SetWidth( width
);
1424 bitmap
.SetPixmap( gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, -1 ) );
1428 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1429 if (visual
== NULL
) visual
= gdk_visual_get_system();
1430 int bpp
= visual
->depth
;
1432 bitmap
.SetDepth( bpp
);
1434 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1435 if (bpp
< 8) bpp
= 8;
1437 #if (GTK_MINOR_VERSION > 0)
1439 if (!HasMask() && (bpp
> 8))
1441 static bool s_hasInitialized
= FALSE
;
1443 if (!s_hasInitialized
)
1446 s_hasInitialized
= TRUE
;
1449 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1451 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1455 GDK_RGB_DITHER_NONE
,
1466 // Create picture image
1468 GdkImage
*data_image
=
1469 gdk_image_new( GDK_IMAGE_FASTEST
, gdk_visual_get_system(), width
, height
);
1471 // Create mask image
1473 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1477 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1479 mask_image
= gdk_image_new_bitmap( gdk_visual_get_system(), mask_data
, width
, height
);
1481 wxMask
*mask
= new wxMask();
1482 mask
->m_bitmap
= gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 );
1484 bitmap
.SetMask( mask
);
1489 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1490 byte_order b_o
= RGB
;
1494 GdkVisual
*visual
= gdk_visual_get_system();
1495 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1496 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1497 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1498 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1499 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1500 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1503 int r_mask
= GetMaskRed();
1504 int g_mask
= GetMaskGreen();
1505 int b_mask
= GetMaskBlue();
1507 unsigned char* data
= GetData();
1510 for (int y
= 0; y
< height
; y
++)
1512 for (int x
= 0; x
< width
; x
++)
1514 int r
= data
[index
];
1516 int g
= data
[index
];
1518 int b
= data
[index
];
1523 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1524 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1526 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1534 if (wxTheApp
->m_colorCube
)
1536 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1540 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1541 GdkColor
*colors
= cmap
->colors
;
1542 int max
= 3 * (65536);
1544 for (int i
= 0; i
< cmap
->size
; i
++)
1546 int rdiff
= (r
<< 8) - colors
[i
].red
;
1547 int gdiff
= (g
<< 8) - colors
[i
].green
;
1548 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1549 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1550 if (sum
< max
) { pixel
= i
; max
= sum
; }
1554 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1560 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1561 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1566 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1567 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1576 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1577 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1578 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1579 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1580 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1581 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1583 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1592 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1594 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1596 gdk_image_destroy( data_image
);
1597 gdk_gc_unref( data_gc
);
1603 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1605 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1607 gdk_image_destroy( mask_image
);
1608 gdk_gc_unref( mask_gc
);
1614 wxImage::wxImage( const wxBitmap
&bitmap
)
1616 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1618 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1619 if (bitmap
.GetPixmap())
1621 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1623 bitmap
.GetWidth(), bitmap
.GetHeight() );
1625 if (bitmap
.GetBitmap())
1627 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1629 bitmap
.GetWidth(), bitmap
.GetHeight() );
1632 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1635 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1637 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1638 char unsigned *data
= GetData();
1642 gdk_image_destroy( gdk_image
);
1643 wxFAIL_MSG( wxT("couldn't create image") );
1647 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1648 if (bitmap
.GetMask())
1650 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1652 bitmap
.GetWidth(), bitmap
.GetHeight() );
1654 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1658 if (bitmap
.GetPixmap())
1660 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1662 if (visual
== NULL
) visual
= gdk_window_get_visual( (GdkWindow
*) &gdk_root_parent
);
1663 bpp
= visual
->depth
;
1664 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1666 if (bitmap
.GetBitmap())
1671 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1674 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1676 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1678 wxInt32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1693 } else if (bpp
<= 8)
1695 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1696 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1697 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1698 } else if (bpp
== 15)
1700 #if (wxBYTE_ORDER == wxBIG_ENDIAN)
1703 data
[pos
] = (pixel
>> 7) & 0xf8;
1704 data
[pos
+1] = (pixel
>> 2) & 0xf8;
1705 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1706 } else if (bpp
== 16)
1708 #if (wxBYTE_ORDER == wxBIG_ENDIAN)
1711 data
[pos
] = (pixel
>> 8) & 0xf8;
1712 data
[pos
+1] = (pixel
>> 3) & 0xfc;
1713 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1716 #if (wxBYTE_ORDER == wxBIG_ENDIAN)
1717 data
[pos
] = (pixel
) & 0xff; // Red
1718 data
[pos
+1] = (pixel
>> 8) & 0xff; // Green
1719 data
[pos
+2] = (pixel
>> 16) & 0xff; // Blue
1721 data
[pos
] = (pixel
>> 16) & 0xff;
1722 data
[pos
+1] = (pixel
>> 8) & 0xff;
1723 data
[pos
+2] = pixel
& 0xff;
1729 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1730 if (mask_pixel
== 0)
1742 gdk_image_destroy( gdk_image
);
1743 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1748 //-----------------------------------------------------------------------------
1749 // Motif conversion routines
1750 //-----------------------------------------------------------------------------
1754 #pragma message disable nosimpint
1758 #pragma message enable nosimpint
1760 #include "wx/utils.h"
1765 Date: Wed, 05 Jan 2000 11:45:40 +0100
1766 From: Frits Boel <boel@niob.knaw.nl>
1767 To: julian.smart@ukonline.co.uk
1768 Subject: Patch for Motif ConvertToBitmap
1772 I've been working on a wxWin application for image processing. From the
1773 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1774 till I looked in the source code of image.cpp. I saw that converting a
1775 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1776 to the 256 colors of the palet. A very time-consuming piece of code!
1778 Because I wanted a faster application, I've made a 'patch' for this. In
1779 short: every pixel of the image is compared to a sorted list with
1780 colors. If the color is found in the list, the palette entry is
1781 returned; if the color is not found, the color palette is searched and
1782 then the palette entry is returned and the color added to the sorted
1785 Maybe there is another method for this, namely changing the palette
1786 itself (if the colors are known, as is the case with tiffs with a
1787 colormap). I did not look at this, maybe someone else did?
1789 The code of the patch is attached, have a look on it, and maybe you will
1790 ship it with the next release of wxMotif?
1795 Software engineer at Hubrecht Laboratory, The Netherlands.
1802 wxSearchColor( void );
1803 wxSearchColor( int size
, XColor
*colors
);
1804 ~wxSearchColor( void );
1806 int SearchColor( int r
, int g
, int b
);
1808 int AddColor( unsigned int value
, int pos
);
1812 unsigned int *color
;
1819 wxSearchColor::wxSearchColor( void )
1822 this->colors
= (XColor
*) NULL
;
1823 this->color
= (unsigned int *) NULL
;
1824 this->entry
= (int*) NULL
;
1830 wxSearchColor::wxSearchColor( int size
, XColor
*colors
)
1834 this->colors
= colors
;
1835 this->color
= new unsigned int[size
];
1836 this->entry
= new int [size
];
1838 for (i
= 0; i
< this->size
; i
++ ) {
1839 this->entry
[i
] = -1;
1842 this->bottom
= this->top
= ( size
>> 1 );
1845 wxSearchColor::~wxSearchColor( void )
1847 if ( this->color
) delete this->color
;
1848 if ( this->entry
) delete this->entry
;
1851 int wxSearchColor::SearchColor( int r
, int g
, int b
)
1853 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
1854 int begin
= this->bottom
;
1855 int end
= this->top
;
1858 while ( begin
<= end
) {
1860 middle
= ( begin
+ end
) >> 1;
1862 if ( value
== this->color
[middle
] ) {
1863 return( this->entry
[middle
] );
1864 } else if ( value
< this->color
[middle
] ) {
1872 return AddColor( value
, middle
);
1875 int wxSearchColor::AddColor( unsigned int value
, int pos
)
1879 int max
= 3 * (65536);
1880 for ( i
= 0; i
< 256; i
++ ) {
1881 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
1882 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
1883 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
1884 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1885 if (sum
< max
) { pixel
= i
; max
= sum
; }
1888 if ( this->entry
[pos
] < 0 ) {
1889 this->color
[pos
] = value
;
1890 this->entry
[pos
] = pixel
;
1891 } else if ( value
< this->color
[pos
] ) {
1893 if ( this->bottom
> 0 ) {
1894 for ( i
= this->bottom
; i
< pos
; i
++ ) {
1895 this->color
[i
-1] = this->color
[i
];
1896 this->entry
[i
-1] = this->entry
[i
];
1899 this->color
[pos
-1] = value
;
1900 this->entry
[pos
-1] = pixel
;
1901 } else if ( this->top
< this->size
-1 ) {
1902 for ( i
= this->top
; i
>= pos
; i
-- ) {
1903 this->color
[i
+1] = this->color
[i
];
1904 this->entry
[i
+1] = this->entry
[i
];
1907 this->color
[pos
] = value
;
1908 this->entry
[pos
] = pixel
;
1913 if ( this->top
< this->size
-1 ) {
1914 for ( i
= this->top
; i
> pos
; i
-- ) {
1915 this->color
[i
+1] = this->color
[i
];
1916 this->entry
[i
+1] = this->entry
[i
];
1919 this->color
[pos
+1] = value
;
1920 this->entry
[pos
+1] = pixel
;
1921 } else if ( this->bottom
> 0 ) {
1922 for ( i
= this->bottom
; i
< pos
; i
++ ) {
1923 this->color
[i
-1] = this->color
[i
];
1924 this->entry
[i
-1] = this->entry
[i
];
1927 this->color
[pos
] = value
;
1928 this->entry
[pos
] = pixel
;
1936 wxBitmap
wxImage::ConvertToBitmap() const
1940 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1942 int width
= GetWidth();
1943 int height
= GetHeight();
1945 bitmap
.SetHeight( height
);
1946 bitmap
.SetWidth( width
);
1948 Display
*dpy
= (Display
*) wxGetDisplay();
1949 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1950 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1954 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1955 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
1957 bitmap
.Create( width
, height
, bpp
);
1962 GdkImage *mask_image = (GdkImage*) NULL;
1966 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1968 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1970 wxMask *mask = new wxMask();
1971 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1973 bitmap.SetMask( mask );
1977 // Retrieve depth info
1979 XVisualInfo vinfo_template
;
1982 vinfo_template
.visual
= vis
;
1983 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1984 vinfo_template
.depth
= bpp
;
1987 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1989 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
1993 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1994 if (bpp
< 8) bpp
= 8;
1998 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1999 byte_order b_o
= RGB
;
2003 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2004 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2005 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2006 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2007 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2008 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2012 int r_mask = GetMaskRed();
2013 int g_mask = GetMaskGreen();
2014 int b_mask = GetMaskBlue();
2020 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2022 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2023 XQueryColors( dpy
, cmap
, colors
, 256 );
2026 wxSearchColor
scolor( 256, colors
);
2027 unsigned char* data
= GetData();
2030 for (int y
= 0; y
< height
; y
++)
2032 for (int x
= 0; x
< width
; x
++)
2034 int r
= data
[index
];
2036 int g
= data
[index
];
2038 int b
= data
[index
];
2044 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2045 gdk_image_put_pixel( mask_image, x, y, 1 );
2047 gdk_image_put_pixel( mask_image, x, y, 0 );
2055 #if 0 // Old, slower code
2058 if (wxTheApp->m_colorCube)
2060 pixel = wxTheApp->m_colorCube
2061 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2066 int max
= 3 * (65536);
2067 for (int i
= 0; i
< 256; i
++)
2069 int rdiff
= (r
<< 8) - colors
[i
].red
;
2070 int gdiff
= (g
<< 8) - colors
[i
].green
;
2071 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2072 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2073 if (sum
< max
) { pixel
= i
; max
= sum
; }
2080 // And this is all to get the 'right' color...
2081 int pixel
= scolor
.SearchColor( r
, g
, b
);
2082 XPutPixel( data_image
, x
, y
, pixel
);
2087 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2088 XPutPixel( data_image
, x
, y
, pixel
);
2093 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2094 XPutPixel( data_image
, x
, y
, pixel
);
2103 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2104 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2105 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2106 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2107 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2108 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2110 XPutPixel( data_image
, x
, y
, pixel
);
2120 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2121 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2122 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2124 XDestroyImage( data_image
);
2132 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
2134 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
2136 gdk_image_destroy( mask_image );
2137 gdk_gc_unref( mask_gc );
2144 wxImage::wxImage( const wxBitmap
&bitmap
)
2146 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2148 Display
*dpy
= (Display
*) wxGetDisplay();
2149 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2150 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2152 XImage
*ximage
= XGetImage( dpy
,
2153 (Drawable
)bitmap
.GetPixmap(),
2155 bitmap
.GetWidth(), bitmap
.GetHeight(),
2156 AllPlanes
, ZPixmap
);
2158 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2160 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2161 char unsigned *data
= GetData();
2165 XDestroyImage( ximage
);
2166 wxFAIL_MSG( wxT("couldn't create image") );
2171 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2172 if (bitmap.GetMask())
2174 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2176 bitmap.GetWidth(), bitmap.GetHeight() );
2178 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2182 // Retrieve depth info
2184 XVisualInfo vinfo_template
;
2187 vinfo_template
.visual
= vis
;
2188 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2189 vinfo_template
.depth
= bpp
;
2192 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2194 wxCHECK_RET( vi
, wxT("no visual") );
2196 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2203 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2205 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2206 XQueryColors( dpy
, cmap
, colors
, 256 );
2210 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2212 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2214 int pixel
= XGetPixel( ximage
, i
, j
);
2217 data
[pos
] = colors
[pixel
].red
>> 8;
2218 data
[pos
+1] = colors
[pixel
].green
>> 8;
2219 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2220 } else if (bpp
== 15)
2222 data
[pos
] = (pixel
>> 7) & 0xf8;
2223 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2224 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2225 } else if (bpp
== 16)
2227 data
[pos
] = (pixel
>> 8) & 0xf8;
2228 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2229 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2232 data
[pos
] = (pixel
>> 16) & 0xff;
2233 data
[pos
+1] = (pixel
>> 8) & 0xff;
2234 data
[pos
+2] = pixel
& 0xff;
2240 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2241 if (mask_pixel == 0)
2254 XDestroyImage( ximage
);
2256 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2262 // OS/2 Presentation manager conversion routings
2264 wxBitmap
wxImage::ConvertToBitmap() const
2267 return wxNullBitmap
;
2268 wxBitmap bitmap
; // remove
2271 int sizeLimit = 1024*768*3;
2273 // width and height of the device-dependent bitmap
2274 int width = GetWidth();
2275 int bmpHeight = GetHeight();
2277 // calc the number of bytes per scanline and padding
2278 int bytePerLine = width*3;
2279 int sizeDWORD = sizeof( DWORD );
2280 int lineBoundary = bytePerLine % sizeDWORD;
2282 if( lineBoundary > 0 )
2284 padding = sizeDWORD - lineBoundary;
2285 bytePerLine += padding;
2287 // calc the number of DIBs and heights of DIBs
2290 int height = sizeLimit/bytePerLine;
2291 if( height >= bmpHeight )
2295 numDIB = bmpHeight / height;
2296 hRemain = bmpHeight % height;
2297 if( hRemain >0 ) numDIB++;
2300 // set bitmap parameters
2302 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2303 bitmap.SetWidth( width );
2304 bitmap.SetHeight( bmpHeight );
2305 bitmap.SetDepth( wxDisplayDepth() );
2307 // create a DIB header
2308 int headersize = sizeof(BITMAPINFOHEADER);
2309 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2310 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2311 // Fill in the DIB header
2312 lpDIBh->bmiHeader.biSize = headersize;
2313 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2314 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2315 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2316 // the general formula for biSizeImage:
2317 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2318 lpDIBh->bmiHeader.biPlanes = 1;
2319 lpDIBh->bmiHeader.biBitCount = 24;
2320 lpDIBh->bmiHeader.biCompression = BI_RGB;
2321 lpDIBh->bmiHeader.biClrUsed = 0;
2322 // These seem not really needed for our purpose here.
2323 lpDIBh->bmiHeader.biClrImportant = 0;
2324 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2325 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2326 // memory for DIB data
2327 unsigned char *lpBits;
2328 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2331 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2336 // create and set the device-dependent bitmap
2337 HDC hdc = ::GetDC(NULL);
2338 HDC memdc = ::CreateCompatibleDC( hdc );
2340 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2341 ::SelectObject( memdc, hbitmap);
2343 // copy image data into DIB data and then into DDB (in a loop)
2344 unsigned char *data = GetData();
2347 unsigned char *ptdata = data;
2348 unsigned char *ptbits;
2350 for( n=0; n<numDIB; n++ )
2352 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2354 // redefine height and size of the (possibly) last smaller DIB
2355 // memory is not reallocated
2357 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2358 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2362 for( j=0; j<height; j++ )
2364 for( i=0; i<width; i++ )
2366 *(ptbits++) = *(ptdata+2);
2367 *(ptbits++) = *(ptdata+1);
2368 *(ptbits++) = *(ptdata );
2371 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2373 ::StretchDIBits( memdc, 0, origin, width, height,\
2374 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2376 // if numDIB = 1, lines below can also be used
2377 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2378 // The above line is equivalent to the following two lines.
2379 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2380 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2381 // or the following lines
2382 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2383 // HDC memdc = ::CreateCompatibleDC( hdc );
2384 // ::SelectObject( memdc, hbitmap);
2385 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2386 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2387 // ::SelectObject( memdc, 0 );
2388 // ::DeleteDC( memdc );
2390 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2392 // similarly, created an mono-bitmap for the possible mask
2395 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2396 ::SelectObject( memdc, hbitmap);
2397 if( numDIB == 1 ) height = bmpHeight;
2398 else height = sizeLimit/bytePerLine;
2399 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2400 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2402 unsigned char r = GetMaskRed();
2403 unsigned char g = GetMaskGreen();
2404 unsigned char b = GetMaskBlue();
2405 unsigned char zero = 0, one = 255;
2407 for( n=0; n<numDIB; n++ )
2409 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2411 // redefine height and size of the (possibly) last smaller DIB
2412 // memory is not reallocated
2414 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2415 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2418 for( int j=0; j<height; j++ )
2420 for(i=0; i<width; i++ )
2422 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2435 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2437 ::StretchDIBits( memdc, 0, origin, width, height,\
2438 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2441 // create a wxMask object
2442 wxMask *mask = new wxMask();
2443 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2444 bitmap.SetMask( mask );
2447 // free allocated resources
2448 ::SelectObject( memdc, 0 );
2449 ::DeleteDC( memdc );
2450 ::ReleaseDC(NULL, hdc);
2454 // check the wxBitmap object
2455 if( bitmap.GetHBITMAP() )
2456 bitmap.SetOk( TRUE );
2458 bitmap.SetOk( FALSE );
2463 wxImage::wxImage( const wxBitmap
&bitmap
)
2468 wxFAIL_MSG( wxT("invalid bitmap") );
2472 // create an wxImage object
2473 int width
= bitmap
.GetWidth();
2474 int height
= bitmap
.GetHeight();
2475 Create( width
, height
);
2476 unsigned char *data
= GetData();
2479 wxFAIL_MSG( wxT("could not allocate data for image") );
2483 // calc the number of bytes per scanline and padding in the DIB
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
;
2495 // create a DIB header
2496 int headersize = sizeof(BITMAPINFOHEADER);
2497 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2500 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2504 // Fill in the DIB header
2505 lpDIBh->bmiHeader.biSize = headersize;
2506 lpDIBh->bmiHeader.biWidth = width;
2507 lpDIBh->bmiHeader.biHeight = -height;
2508 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2509 lpDIBh->bmiHeader.biPlanes = 1;
2510 lpDIBh->bmiHeader.biBitCount = 24;
2511 lpDIBh->bmiHeader.biCompression = BI_RGB;
2512 lpDIBh->bmiHeader.biClrUsed = 0;
2513 // These seem not really needed for our purpose here.
2514 lpDIBh->bmiHeader.biClrImportant = 0;
2515 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2516 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2517 // memory for DIB data
2518 unsigned char *lpBits;
2519 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2522 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2528 // copy data from the device-dependent bitmap to the DIB
2529 HDC hdc = ::GetDC(NULL);
2531 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2532 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2534 // copy DIB data into the wxImage object
2536 unsigned char *ptdata = data;
2537 unsigned char *ptbits = lpBits;
2538 for( i=0; i<height; i++ )
2540 for( j=0; j<width; j++ )
2542 *(ptdata++) = *(ptbits+2);
2543 *(ptdata++) = *(ptbits+1);
2544 *(ptdata++) = *(ptbits );
2550 // similarly, set data according to the possible mask bitmap
2551 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2553 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2554 // memory DC created, color set, data copied, and memory DC deleted
2555 HDC memdc = ::CreateCompatibleDC( hdc );
2556 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2557 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2558 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2559 ::DeleteDC( memdc );
2560 // background color set to RGB(16,16,16) in consistent with wxGTK
2561 unsigned char r=16, g=16, b=16;
2564 for( i=0; i<height; i++ )
2566 for( j=0; j<width; j++ )
2580 SetMaskColour( r, g, b );
2587 // free allocated resources
2588 ::ReleaseDC(NULL, hdc);
2596 // A module to allow wxImage initialization/cleanup
2597 // without calling these functions from app.cpp or from
2598 // the user's application.
2600 class wxImageModule
: public wxModule
2602 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2605 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2606 void OnExit() { wxImage::CleanUpHandlers(); };
2609 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2612 //-----------------------------------------------------------------------------
2615 // Counts and returns the number of different colours. Optionally stops
2616 // when it exceeds 'stopafter' different colours. This is useful, for
2617 // example, to see if the image can be saved as 8-bit (256 colour or
2618 // less, in this case it would be invoked as CountColours(256)). Default
2619 // value for stopafter is -1 (don't care).
2621 unsigned long wxImage::CountColours( unsigned long stopafter
)
2626 unsigned char r
, g
, b
, *p
;
2627 unsigned long size
, nentries
, key
;
2630 size
= GetWidth() * GetHeight();
2633 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2638 key
= (r
<< 16) | (g
<< 8) | b
;
2640 hnode
= (wxHNode
*) h
.Get(key
);
2644 h
.Put(key
, (wxObject
*)(new wxHNode
));
2649 // delete all HNodes
2651 while ((node
= h
.Next()) != NULL
)
2652 delete (wxHNode
*)node
->GetData();
2659 // Computes the histogram of the image and fills a hash table, indexed
2660 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2661 // wxHNode contains an 'index' (useful to build a palette with the image
2662 // colours) and a 'value', which is the number of pixels in the image with
2665 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2667 unsigned char r
, g
, b
, *p
;
2668 unsigned long size
, nentries
, key
;
2672 size
= GetWidth() * GetHeight();
2675 for (unsigned long j
= 0; j
< size
; j
++)
2680 key
= (r
<< 16) | (g
<< 8) | b
;
2682 hnode
= (wxHNode
*) h
.Get(key
);
2688 hnode
= new wxHNode();
2689 hnode
->index
= nentries
++;
2692 h
.Put(key
, (wxObject
*)hnode
);