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
55 unsigned char *m_data
;
57 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
61 wxImageRefData::wxImageRefData()
65 m_data
= (unsigned char*) NULL
;
73 wxImageRefData::~wxImageRefData()
75 if (m_data
) free( m_data
);
78 wxList
wxImage::sm_handlers
;
80 //-----------------------------------------------------------------------------
82 #define M_IMGDATA ((wxImageRefData *)m_refData)
84 #if !USE_SHARED_LIBRARIES
85 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
92 wxImage::wxImage( int width
, int height
)
94 Create( width
, height
);
97 wxImage::wxImage( const wxString
& name
, long type
)
99 LoadFile( name
, type
);
102 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
)
104 LoadFile( name
, mimetype
);
108 wxImage::wxImage( wxInputStream
& stream
, long type
)
110 LoadFile( stream
, type
);
113 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
)
115 LoadFile( stream
, mimetype
);
117 #endif // wxUSE_STREAMS
119 wxImage::wxImage( const wxImage
& image
)
124 wxImage::wxImage( const wxImage
* image
)
126 if (image
) Ref(*image
);
129 void wxImage::Create( int width
, int height
)
131 m_refData
= new wxImageRefData();
133 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
134 if (M_IMGDATA
->m_data
)
136 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
138 M_IMGDATA
->m_width
= width
;
139 M_IMGDATA
->m_height
= height
;
140 M_IMGDATA
->m_ok
= TRUE
;
148 void wxImage::Destroy()
153 wxImage
wxImage::Scale( int width
, int height
)
157 wxCHECK_MSG( Ok(), image
, _T("invalid image") );
159 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, _T("invalid image size") );
161 image
.Create( width
, height
);
163 char unsigned *data
= image
.GetData();
165 wxCHECK_MSG( data
, image
, _T("unable to create image") );
167 if (M_IMGDATA
->m_hasMask
)
168 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
170 long old_height
= M_IMGDATA
->m_height
;
171 long old_width
= M_IMGDATA
->m_width
;
173 char unsigned *source_data
= M_IMGDATA
->m_data
;
174 char unsigned *target_data
= data
;
176 for (long j
= 0; j
< height
; j
++)
178 long y_offset
= (j
* old_height
/ height
) * old_width
;
180 for (long i
= 0; i
< width
; i
++)
183 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
192 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
194 wxCHECK_RET( Ok(), _T("invalid image") );
196 int w
= M_IMGDATA
->m_width
;
197 int h
= M_IMGDATA
->m_height
;
199 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), _T("invalid image index") );
201 long pos
= (y
* w
+ x
) * 3;
203 M_IMGDATA
->m_data
[ pos
] = r
;
204 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
205 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
208 unsigned char wxImage::GetRed( int x
, int y
)
210 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
212 int w
= M_IMGDATA
->m_width
;
213 int h
= M_IMGDATA
->m_height
;
215 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, _T("invalid image index") );
217 long pos
= (y
* w
+ x
) * 3;
219 return M_IMGDATA
->m_data
[pos
];
222 unsigned char wxImage::GetGreen( int x
, int y
)
224 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
226 int w
= M_IMGDATA
->m_width
;
227 int h
= M_IMGDATA
->m_height
;
229 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, _T("invalid image index") );
231 long pos
= (y
* w
+ x
) * 3;
233 return M_IMGDATA
->m_data
[pos
+1];
236 unsigned char wxImage::GetBlue( int x
, int y
)
238 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
240 int w
= M_IMGDATA
->m_width
;
241 int h
= M_IMGDATA
->m_height
;
243 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, _T("invalid image index") );
245 long pos
= (y
* w
+ x
) * 3;
247 return M_IMGDATA
->m_data
[pos
+2];
250 bool wxImage::Ok() const
252 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
255 char unsigned *wxImage::GetData() const
257 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, _T("invalid image") );
259 return M_IMGDATA
->m_data
;
262 void wxImage::SetData( char unsigned *data
)
264 wxCHECK_RET( Ok(), _T("invalid image") );
266 memcpy(M_IMGDATA
->m_data
, data
, M_IMGDATA
->m_width
* M_IMGDATA
->m_height
* 3);
269 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
271 wxCHECK_RET( Ok(), _T("invalid image") );
273 M_IMGDATA
->m_maskRed
= r
;
274 M_IMGDATA
->m_maskGreen
= g
;
275 M_IMGDATA
->m_maskBlue
= b
;
276 M_IMGDATA
->m_hasMask
= TRUE
;
279 unsigned char wxImage::GetMaskRed() const
281 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
283 return M_IMGDATA
->m_maskRed
;
286 unsigned char wxImage::GetMaskGreen() const
288 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
290 return M_IMGDATA
->m_maskGreen
;
293 unsigned char wxImage::GetMaskBlue() const
295 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
297 return M_IMGDATA
->m_maskBlue
;
300 void wxImage::SetMask( bool mask
)
302 wxCHECK_RET( Ok(), _T("invalid image") );
304 M_IMGDATA
->m_hasMask
= mask
;
307 bool wxImage::HasMask() const
309 wxCHECK_MSG( Ok(), FALSE
, _T("invalid image") );
311 return M_IMGDATA
->m_hasMask
;
314 int wxImage::GetWidth() const
316 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
318 return M_IMGDATA
->m_width
;
321 int wxImage::GetHeight() const
323 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
325 return M_IMGDATA
->m_height
;
328 bool wxImage::LoadFile( const wxString
& filename
, long type
)
331 if (wxFileExists(filename
))
333 wxFileInputStream
stream(filename
);
334 return LoadFile(stream
, type
);
338 wxLogError( _T("Can't load image from file '%s': file does not exist."), filename
.c_str() );
342 #else // !wxUSE_STREAMS
344 #endif // wxUSE_STREAMS
347 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
350 if (wxFileExists(filename
))
352 wxFileInputStream
stream(filename
);
353 return LoadFile(stream
, mimetype
);
357 wxLogError( _T("Can't load image from file '%s': file does not exist."), filename
.c_str() );
361 #else // !wxUSE_STREAMS
363 #endif // wxUSE_STREAMS
366 bool wxImage::SaveFile( const wxString
& filename
, int type
)
369 wxFileOutputStream
stream(filename
);
371 if ( stream
.LastError() == wxStream_NOERROR
)
372 return SaveFile(stream
, type
);
374 #endif // wxUSE_STREAMS
378 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
381 wxFileOutputStream
stream(filename
);
383 if ( stream
.LastError() == wxStream_NOERROR
)
384 return SaveFile(stream
, mimetype
);
386 #endif // wxUSE_STREAMS
391 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
395 m_refData
= new wxImageRefData
;
397 wxImageHandler
*handler
= FindHandler(type
);
401 wxLogWarning( _T("No image handler for type %d defined."), type
);
406 return handler
->LoadFile( this, stream
);
409 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
413 m_refData
= new wxImageRefData
;
415 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
419 wxLogWarning( _T("No image handler for type %s defined."), mimetype
.GetData() );
424 return handler
->LoadFile( this, stream
);
427 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
429 wxCHECK_MSG( Ok(), FALSE
, _T("invalid image") );
431 wxImageHandler
*handler
= FindHandler(type
);
435 wxLogWarning( _T("No image handler for type %d defined."), type
);
440 return handler
->SaveFile( this, stream
);
443 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
445 wxCHECK_MSG( Ok(), FALSE
, _T("invalid image") );
447 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
451 wxLogWarning( _T("No image handler for type %s defined."), mimetype
.GetData() );
456 return handler
->SaveFile( this, stream
);
458 #endif // wxUSE_STREAMS
460 void wxImage::AddHandler( wxImageHandler
*handler
)
462 // make sure that the memory will be freed at the program end
463 sm_handlers
.DeleteContents(TRUE
);
465 sm_handlers
.Append( handler
);
468 void wxImage::InsertHandler( wxImageHandler
*handler
)
470 // make sure that the memory will be freed at the program end
471 sm_handlers
.DeleteContents(TRUE
);
473 sm_handlers
.Insert( handler
);
476 bool wxImage::RemoveHandler( const wxString
& name
)
478 wxImageHandler
*handler
= FindHandler(name
);
481 sm_handlers
.DeleteObject(handler
);
488 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
490 wxNode
*node
= sm_handlers
.First();
493 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
494 if (handler
->GetName().Cmp(name
) == 0) return handler
;
498 return (wxImageHandler
*)NULL
;
501 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
503 wxNode
*node
= sm_handlers
.First();
506 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
507 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
508 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
512 return (wxImageHandler
*)NULL
;
515 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
517 wxNode
*node
= sm_handlers
.First();
520 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
521 if (handler
->GetType() == bitmapType
) return handler
;
527 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
529 wxNode
*node
= sm_handlers
.First();
532 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
533 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
539 void wxImage::InitStandardHandlers()
541 AddHandler( new wxBMPHandler
);
544 void wxImage::CleanUpHandlers()
546 wxNode
*node
= sm_handlers
.First();
549 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
550 wxNode
*next
= node
->Next();
557 //-----------------------------------------------------------------------------
559 //-----------------------------------------------------------------------------
561 #if !USE_SHARED_LIBRARIES
562 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler
,wxObject
)
566 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
) )
571 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
) )
575 #endif // wxUSE_STREAMS
577 //-----------------------------------------------------------------------------
578 // MSW conversion routines
579 //-----------------------------------------------------------------------------
583 wxBitmap
wxImage::ConvertToBitmap() const
585 // sizeLimit is the MS upper limit for the DIB size
586 int sizeLimit
= 1024*768*3;
588 // width and height of the device-dependent bitmap
589 int width
= GetWidth();
590 int bmpHeight
= GetHeight();
592 // calc the number of bytes per scanline and padding
593 int bytePerLine
= width
*3;
594 int sizeDWORD
= sizeof( DWORD
);
595 div_t lineBoundary
= div( bytePerLine
, sizeDWORD
);
597 if( lineBoundary
.rem
> 0 )
599 padding
= sizeDWORD
- lineBoundary
.rem
;
600 bytePerLine
+= padding
;
602 // calc the number of DIBs and heights of DIBs
605 int height
= sizeLimit
/bytePerLine
;
606 if( height
>= bmpHeight
)
610 div_t result
= div( bmpHeight
, height
);
611 numDIB
= result
.quot
;
612 hRemain
= result
.rem
;
613 if( hRemain
>0 ) numDIB
++;
616 // set bitmap parameters
618 wxCHECK_MSG( Ok(), bitmap
, _T("invalid image") );
619 bitmap
.SetWidth( width
);
620 bitmap
.SetHeight( bmpHeight
);
621 bitmap
.SetDepth( wxDisplayDepth() );
623 // create a DIB header
624 int headersize
= sizeof(BITMAPINFOHEADER
);
625 LPBITMAPINFO lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
626 wxCHECK_MSG( lpDIBh
, bitmap
, _T("could not allocate memory for DIB header") );
627 // Fill in the DIB header
628 lpDIBh
->bmiHeader
.biSize
= headersize
;
629 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
630 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
631 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
632 // the general formula for biSizeImage:
633 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
634 lpDIBh
->bmiHeader
.biPlanes
= 1;
635 lpDIBh
->bmiHeader
.biBitCount
= 24;
636 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
637 lpDIBh
->bmiHeader
.biClrUsed
= 0;
638 // These seem not really needed for our purpose here.
639 lpDIBh
->bmiHeader
.biClrImportant
= 0;
640 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
641 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
642 // memory for DIB data
643 unsigned char *lpBits
;
644 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
647 wxFAIL_MSG( _T("could not allocate memory for DIB") );
652 // create and set the device-dependent bitmap
653 HDC hdc
= ::GetDC(NULL
);
654 HDC memdc
= ::CreateCompatibleDC( hdc
);
656 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
657 ::SelectObject( memdc
, hbitmap
);
659 // copy image data into DIB data and then into DDB (in a loop)
660 unsigned char *data
= GetData();
663 unsigned char *ptdata
= data
;
664 unsigned char *ptbits
;
666 for( n
=0; n
<numDIB
; n
++ )
668 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
670 // redefine height and size of the (possibly) last smaller DIB
671 // memory is not reallocated
673 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
674 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
678 for( j
=0; j
<height
; j
++ )
680 for( i
=0; i
<width
; i
++ )
682 *(ptbits
++) = *(ptdata
+2);
683 *(ptbits
++) = *(ptdata
+1);
684 *(ptbits
++) = *(ptdata
);
687 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
689 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
690 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
692 // if numDIB = 1, lines below can also be used
693 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
694 // The above line is equivalent to the following two lines.
695 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
696 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
697 // or the following lines
698 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
699 // HDC memdc = ::CreateCompatibleDC( hdc );
700 // ::SelectObject( memdc, hbitmap);
701 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
702 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
703 // ::SelectObject( memdc, 0 );
704 // ::DeleteDC( memdc );
706 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
708 // similarly, created an mono-bitmap for the possible mask
711 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
712 ::SelectObject( memdc
, hbitmap
);
713 if( numDIB
== 1 ) height
= bmpHeight
;
714 else height
= sizeLimit
/bytePerLine
;
715 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
716 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
718 unsigned char r
= GetMaskRed();
719 unsigned char g
= GetMaskGreen();
720 unsigned char b
= GetMaskBlue();
721 unsigned char zero
= 0, one
= 255;
723 for( n
=0; n
<numDIB
; n
++ )
725 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
727 // redefine height and size of the (possibly) last smaller DIB
728 // memory is not reallocated
730 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
731 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
734 for( int j
=0; j
<height
; j
++ )
736 for(i
=0; i
<width
; i
++ )
738 if( (*(ptdata
++)!=r
) | (*(ptdata
++)!=g
) | (*(ptdata
++)!=b
) )
751 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
753 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
754 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
757 // create a wxMask object
758 wxMask
*mask
= new wxMask();
759 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
760 bitmap
.SetMask( mask
);
761 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
762 /* The following can also be used but is slow to run
763 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
764 wxMask *mask = new wxMask( bitmap, colour );
765 bitmap.SetMask( mask );
769 // free allocated resources
770 ::SelectObject( memdc
, 0 );
772 ::ReleaseDC(NULL
, hdc
);
776 // check the wxBitmap object
777 if( bitmap
.GetHBITMAP() )
778 bitmap
.SetOk( TRUE
);
780 bitmap
.SetOk( FALSE
);
785 wxImage::wxImage( const wxBitmap
&bitmap
)
790 wxFAIL_MSG( _T("invalid bitmap") );
794 // create an wxImage object
795 int width
= bitmap
.GetWidth();
796 int height
= bitmap
.GetHeight();
797 Create( width
, height
);
798 unsigned char *data
= GetData();
801 wxFAIL_MSG( _T("could not allocate data for image") );
805 // calc the number of bytes per scanline and padding in the DIB
806 int bytePerLine
= width
*3;
807 int sizeDWORD
= sizeof( DWORD
);
808 div_t lineBoundary
= div( bytePerLine
, sizeDWORD
);
810 if( lineBoundary
.rem
> 0 )
812 padding
= sizeDWORD
- lineBoundary
.rem
;
813 bytePerLine
+= padding
;
816 // create a DIB header
817 int headersize
= sizeof(BITMAPINFOHEADER
);
818 LPBITMAPINFO lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
821 wxFAIL_MSG( _T("could not allocate data for DIB header") );
825 // Fill in the DIB header
826 lpDIBh
->bmiHeader
.biSize
= headersize
;
827 lpDIBh
->bmiHeader
.biWidth
= width
;
828 lpDIBh
->bmiHeader
.biHeight
= -height
;
829 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
830 lpDIBh
->bmiHeader
.biPlanes
= 1;
831 lpDIBh
->bmiHeader
.biBitCount
= 24;
832 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
833 lpDIBh
->bmiHeader
.biClrUsed
= 0;
834 // These seem not really needed for our purpose here.
835 lpDIBh
->bmiHeader
.biClrImportant
= 0;
836 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
837 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
838 // memory for DIB data
839 unsigned char *lpBits
;
840 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
843 wxFAIL_MSG( _T("could not allocate data for DIB") );
849 // copy data from the device-dependent bitmap to the DIB
850 HDC hdc
= ::GetDC(NULL
);
852 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
853 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
855 // copy DIB data into the wxImage object
857 unsigned char *ptdata
= data
;
858 unsigned char *ptbits
= lpBits
;
859 for( i
=0; i
<height
; i
++ )
861 for( j
=0; j
<width
; j
++ )
863 *(ptdata
++) = *(ptbits
+2);
864 *(ptdata
++) = *(ptbits
+1);
865 *(ptdata
++) = *(ptbits
);
871 // similarly, set data according to the possible mask bitmap
872 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
874 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
875 // memory DC created, color set, data copied, and memory DC deleted
876 HDC memdc
= ::CreateCompatibleDC( hdc
);
877 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
878 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
879 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
881 // background color set to RGB(16,16,16) in consistent with wxGTK
882 unsigned char r
=16, g
=16, b
=16;
885 for( i
=0; i
<height
; i
++ )
887 for( j
=0; j
<width
; j
++ )
901 SetMaskColour( r
, g
, b
);
908 // free allocated resources
909 ::ReleaseDC(NULL
, hdc
);
916 //-----------------------------------------------------------------------------
917 // GTK conversion routines
918 //-----------------------------------------------------------------------------
924 #include "gdk/gdkx.h"
926 #if (GTK_MINOR_VERSION > 0)
927 #include "gdk/gdkrgb.h"
930 wxBitmap
wxImage::ConvertToBitmap() const
934 wxCHECK_MSG( Ok(), bitmap
, _T("invalid image") );
936 int width
= GetWidth();
937 int height
= GetHeight();
939 bitmap
.SetHeight( height
);
940 bitmap
.SetWidth( width
);
942 bitmap
.SetPixmap( gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, -1 ) );
946 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
947 if (visual
== NULL
) visual
= gdk_window_get_visual( (GdkWindow
*) &gdk_root_parent
);
948 int bpp
= visual
->depth
;
950 bitmap
.SetDepth( bpp
);
952 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
953 if (bpp
< 8) bpp
= 8;
955 #if (GTK_MINOR_VERSION > 0)
957 if (!HasMask() && (bpp
> 8))
959 static bool s_hasInitialized
= FALSE
;
961 if (!s_hasInitialized
)
964 s_hasInitialized
= TRUE
;
967 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
969 gdk_draw_rgb_image( bitmap
.GetPixmap(),
984 // Create picture image
986 GdkImage
*data_image
=
987 gdk_image_new( GDK_IMAGE_FASTEST
, gdk_visual_get_system(), width
, height
);
991 GdkImage
*mask_image
= (GdkImage
*) NULL
;
995 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
997 mask_image
= gdk_image_new_bitmap( gdk_visual_get_system(), mask_data
, width
, height
);
999 wxMask
*mask
= new wxMask();
1000 mask
->m_bitmap
= gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 );
1002 bitmap
.SetMask( mask
);
1007 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1008 byte_order b_o
= RGB
;
1012 GdkVisual
*visual
= gdk_visual_get_system();
1013 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1014 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1015 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1016 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1017 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1018 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1021 int r_mask
= GetMaskRed();
1022 int g_mask
= GetMaskGreen();
1023 int b_mask
= GetMaskBlue();
1025 unsigned char* data
= GetData();
1028 for (int y
= 0; y
< height
; y
++)
1030 for (int x
= 0; x
< width
; x
++)
1032 int r
= data
[index
];
1034 int g
= data
[index
];
1036 int b
= data
[index
];
1041 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1042 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1044 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1049 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1050 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1052 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1060 if (wxTheApp
->m_colorCube
)
1062 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1066 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1067 GdkColor
*colors
= cmap
->colors
;
1068 int max
= 3 * (65536);
1070 for (int i
= 0; i
< cmap
->size
; i
++)
1072 int rdiff
= (r
<< 8) - colors
[i
].red
;
1073 int gdiff
= (g
<< 8) - colors
[i
].green
;
1074 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1075 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1076 if (sum
< max
) { pixel
= i
; max
= sum
; }
1080 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1086 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1087 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1092 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1093 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1102 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1103 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1104 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1105 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1106 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1107 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1109 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1118 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1120 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1122 gdk_image_destroy( data_image
);
1123 gdk_gc_unref( data_gc
);
1129 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1131 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1133 gdk_image_destroy( mask_image
);
1134 gdk_gc_unref( mask_gc
);
1140 wxImage::wxImage( const wxBitmap
&bitmap
)
1142 wxCHECK_RET( bitmap
.Ok(), _T("invalid bitmap") );
1144 GdkImage
*gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1146 bitmap
.GetWidth(), bitmap
.GetHeight() );
1148 wxCHECK_RET( gdk_image
, _T("couldn't create image") );
1150 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1151 char unsigned *data
= GetData();
1155 gdk_image_destroy( gdk_image
);
1156 wxFAIL_MSG( _T("couldn't create image") );
1160 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1161 if (bitmap
.GetMask())
1163 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1165 bitmap
.GetWidth(), bitmap
.GetHeight() );
1167 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1170 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1171 if (visual
== NULL
) visual
= gdk_window_get_visual( (GdkWindow
*) &gdk_root_parent
);
1172 int bpp
= visual
->depth
;
1173 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1175 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1178 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1180 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1182 int pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1185 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1186 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1187 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1188 } else if (bpp
== 15)
1190 data
[pos
] = (pixel
>> 7) & 0xf8;
1191 data
[pos
+1] = (pixel
>> 2) & 0xf8;
1192 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1193 } else if (bpp
== 16)
1195 data
[pos
] = (pixel
>> 8) & 0xf8;
1196 data
[pos
+1] = (pixel
>> 3) & 0xfc;
1197 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1200 data
[pos
] = (pixel
>> 16) & 0xff;
1201 data
[pos
+1] = (pixel
>> 8) & 0xff;
1202 data
[pos
+2] = pixel
& 0xff;
1207 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1208 if (mask_pixel
== 0)
1220 gdk_image_destroy( gdk_image
);
1221 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1226 //-----------------------------------------------------------------------------
1227 // Motif conversion routines
1228 //-----------------------------------------------------------------------------
1233 #include "wx/utils.h"
1236 wxBitmap
wxImage::ConvertToBitmap() const
1240 wxCHECK_MSG( Ok(), bitmap
, _T("invalid image") );
1242 int width
= GetWidth();
1243 int height
= GetHeight();
1245 bitmap
.SetHeight( height
);
1246 bitmap
.SetWidth( width
);
1248 Display
*dpy
= (Display
*) wxGetDisplay();
1249 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1250 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1254 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1255 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
1257 bitmap
.Create( width
, height
, bpp
);
1262 GdkImage *mask_image = (GdkImage*) NULL;
1266 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1268 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1270 wxMask *mask = new wxMask();
1271 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1273 bitmap.SetMask( mask );
1277 // Retrieve depth info
1279 XVisualInfo vinfo_template
;
1282 vinfo_template
.visual
= vis
;
1283 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1284 vinfo_template
.depth
= bpp
;
1287 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1289 wxCHECK_MSG( vi
, wxNullBitmap
, _T("no visual") );
1293 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1294 if (bpp
< 8) bpp
= 8;
1298 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1299 byte_order b_o
= RGB
;
1303 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
1304 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
1305 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
1306 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
1307 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
1308 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
1312 int r_mask = GetMaskRed();
1313 int g_mask = GetMaskGreen();
1314 int b_mask = GetMaskBlue();
1320 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
1322 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
1323 XQueryColors( dpy
, cmap
, colors
, 256 );
1326 unsigned char* data
= GetData();
1329 for (int y
= 0; y
< height
; y
++)
1331 for (int x
= 0; x
< width
; x
++)
1333 int r
= data
[index
];
1335 int g
= data
[index
];
1337 int b
= data
[index
];
1343 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1344 gdk_image_put_pixel( mask_image, x, y, 1 );
1346 gdk_image_put_pixel( mask_image, x, y, 0 );
1356 if (wxTheApp->m_colorCube)
1358 pixel = wxTheApp->m_colorCube
1359 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1364 int max
= 3 * (65536);
1365 for (int i
= 0; i
< 256; i
++)
1367 int rdiff
= (r
<< 8) - colors
[i
].red
;
1368 int gdiff
= (g
<< 8) - colors
[i
].green
;
1369 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1370 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1371 if (sum
< max
) { pixel
= i
; max
= sum
; }
1376 XPutPixel( data_image
, x
, y
, pixel
);
1381 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1382 XPutPixel( data_image
, x
, y
, pixel
);
1387 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1388 XPutPixel( data_image
, x
, y
, pixel
);
1397 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1398 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1399 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1400 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1401 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1402 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1404 XPutPixel( data_image
, x
, y
, pixel
);
1414 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
1415 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
1416 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
1418 XDestroyImage( data_image
);
1426 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1428 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1430 gdk_image_destroy( mask_image );
1431 gdk_gc_unref( mask_gc );
1438 wxImage::wxImage( const wxBitmap
&bitmap
)
1440 wxCHECK_RET( bitmap
.Ok(), _T("invalid bitmap") );
1442 Display
*dpy
= (Display
*) wxGetDisplay();
1443 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1444 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1446 XImage
*ximage
= XGetImage( dpy
,
1447 (Drawable
)bitmap
.GetPixmap(),
1449 bitmap
.GetWidth(), bitmap
.GetHeight(),
1450 AllPlanes
, ZPixmap
);
1452 wxCHECK_RET( ximage
, _T("couldn't create image") );
1454 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1455 char unsigned *data
= GetData();
1459 XDestroyImage( ximage
);
1460 wxFAIL_MSG( _T("couldn't create image") );
1465 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1466 if (bitmap.GetMask())
1468 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1470 bitmap.GetWidth(), bitmap.GetHeight() );
1472 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1476 // Retrieve depth info
1478 XVisualInfo vinfo_template
;
1481 vinfo_template
.visual
= vis
;
1482 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1483 vinfo_template
.depth
= bpp
;
1486 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1488 wxCHECK_MSG( vi
, wxNullBitmap
, _T("no visual") );
1490 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1497 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
1499 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
1500 XQueryColors( dpy
, cmap
, colors
, 256 );
1504 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1506 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1508 int pixel
= XGetPixel( ximage
, i
, j
);
1511 data
[pos
] = colors
[pixel
].red
>> 8;
1512 data
[pos
+1] = colors
[pixel
].green
>> 8;
1513 data
[pos
+2] = colors
[pixel
].blue
>> 8;
1514 } else if (bpp
== 15)
1516 data
[pos
] = (pixel
>> 7) & 0xf8;
1517 data
[pos
+1] = (pixel
>> 2) & 0xf8;
1518 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1519 } else if (bpp
== 16)
1521 data
[pos
] = (pixel
>> 8) & 0xf8;
1522 data
[pos
+1] = (pixel
>> 3) & 0xfc;
1523 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1526 data
[pos
] = (pixel
>> 16) & 0xff;
1527 data
[pos
+1] = (pixel
>> 8) & 0xff;
1528 data
[pos
+2] = pixel
& 0xff;
1534 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1535 if (mask_pixel == 0)
1548 XDestroyImage( ximage
);
1550 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1555 // A module to allow wxImage initialization/cleanup
1556 // without calling these functions from app.cpp or from
1557 // the user's application.
1559 class wxImageModule
: public wxModule
1561 DECLARE_DYNAMIC_CLASS(wxImageModule
)
1564 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
1565 void OnExit() { wxImage::CleanUpHandlers(); };
1568 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)