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
) const
157 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
159 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, wxT("invalid image size") );
161 image
.Create( width
, height
);
163 char unsigned *data
= image
.GetData();
165 wxCHECK_MSG( data
, image
, wxT("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 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
196 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
198 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight())
199 , image
, wxT("invalid subimage size") );
201 int subwidth
=rect
.GetWidth();
202 const int subheight
=rect
.GetHeight();
204 image
.Create( subwidth
, subheight
);
206 char unsigned *subdata
= image
.GetData(), *data
=GetData();
208 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
210 if (M_IMGDATA
->m_hasMask
)
211 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
213 const int subleft
=3*rect
.GetLeft();
214 const int width
=3*GetWidth();
217 data
+=rect
.GetTop()*width
+subleft
;
219 for (long j
= 0; j
< subheight
; ++j
)
221 memcpy( subdata
, data
, subwidth
);
229 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
231 wxCHECK_RET( Ok(), wxT("invalid image") );
233 int w
= M_IMGDATA
->m_width
;
234 int h
= M_IMGDATA
->m_height
;
236 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
238 long pos
= (y
* w
+ x
) * 3;
240 M_IMGDATA
->m_data
[ pos
] = r
;
241 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
242 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
245 unsigned char wxImage::GetRed( int x
, int y
)
247 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
249 int w
= M_IMGDATA
->m_width
;
250 int h
= M_IMGDATA
->m_height
;
252 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
254 long pos
= (y
* w
+ x
) * 3;
256 return M_IMGDATA
->m_data
[pos
];
259 unsigned char wxImage::GetGreen( int x
, int y
)
261 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
263 int w
= M_IMGDATA
->m_width
;
264 int h
= M_IMGDATA
->m_height
;
266 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
268 long pos
= (y
* w
+ x
) * 3;
270 return M_IMGDATA
->m_data
[pos
+1];
273 unsigned char wxImage::GetBlue( int x
, int y
)
275 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
277 int w
= M_IMGDATA
->m_width
;
278 int h
= M_IMGDATA
->m_height
;
280 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
282 long pos
= (y
* w
+ x
) * 3;
284 return M_IMGDATA
->m_data
[pos
+2];
287 bool wxImage::Ok() const
289 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
292 char unsigned *wxImage::GetData() const
294 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
296 return M_IMGDATA
->m_data
;
299 void wxImage::SetData( char unsigned *data
)
301 wxCHECK_RET( Ok(), wxT("invalid image") );
303 wxImageRefData
*newRefData
= new wxImageRefData();
305 newRefData
->m_width
= M_IMGDATA
->m_width
;
306 newRefData
->m_height
= M_IMGDATA
->m_height
;
307 newRefData
->m_data
= data
;
308 newRefData
->m_ok
= TRUE
;
309 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
310 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
311 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
312 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
316 m_refData
= newRefData
;
319 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
321 wxCHECK_RET( Ok(), wxT("invalid image") );
323 M_IMGDATA
->m_maskRed
= r
;
324 M_IMGDATA
->m_maskGreen
= g
;
325 M_IMGDATA
->m_maskBlue
= b
;
326 M_IMGDATA
->m_hasMask
= TRUE
;
329 unsigned char wxImage::GetMaskRed() const
331 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
333 return M_IMGDATA
->m_maskRed
;
336 unsigned char wxImage::GetMaskGreen() const
338 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
340 return M_IMGDATA
->m_maskGreen
;
343 unsigned char wxImage::GetMaskBlue() const
345 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
347 return M_IMGDATA
->m_maskBlue
;
350 void wxImage::SetMask( bool mask
)
352 wxCHECK_RET( Ok(), wxT("invalid image") );
354 M_IMGDATA
->m_hasMask
= mask
;
357 bool wxImage::HasMask() const
359 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
361 return M_IMGDATA
->m_hasMask
;
364 int wxImage::GetWidth() const
366 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
368 return M_IMGDATA
->m_width
;
371 int wxImage::GetHeight() const
373 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
375 return M_IMGDATA
->m_height
;
378 bool wxImage::LoadFile( const wxString
& filename
, long type
)
381 if (wxFileExists(filename
))
383 wxFileInputStream
stream(filename
);
384 return LoadFile(stream
, type
);
388 wxLogError( wxT("Can't load image from file '%s': file does not exist."), filename
.c_str() );
392 #else // !wxUSE_STREAMS
394 #endif // wxUSE_STREAMS
397 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
400 if (wxFileExists(filename
))
402 wxFileInputStream
stream(filename
);
403 return LoadFile(stream
, mimetype
);
407 wxLogError( wxT("Can't load image from file '%s': file does not exist."), filename
.c_str() );
411 #else // !wxUSE_STREAMS
413 #endif // wxUSE_STREAMS
416 bool wxImage::SaveFile( const wxString
& filename
, int type
)
419 wxFileOutputStream
stream(filename
);
421 if ( stream
.LastError() == wxStream_NOERROR
)
422 return SaveFile(stream
, type
);
424 #endif // wxUSE_STREAMS
428 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
431 wxFileOutputStream
stream(filename
);
433 if ( stream
.LastError() == wxStream_NOERROR
)
434 return SaveFile(stream
, mimetype
);
436 #endif // wxUSE_STREAMS
442 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
446 m_refData
= new wxImageRefData
;
448 wxImageHandler
*handler
;
450 if (type
==wxBITMAP_TYPE_ANY
)
452 wxList
&list
=GetHandlers();
454 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
456 handler
=(wxImageHandler
*)node
->GetData();
457 if (handler
->CanRead( stream
))
458 return handler
->LoadFile( this, stream
);
462 wxLogWarning( wxT("No handler found for this image.") );
466 handler
= FindHandler(type
);
470 wxLogWarning( wxT("No image handler for type %d defined."), type
);
475 return handler
->LoadFile( this, stream
);
478 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
482 m_refData
= new wxImageRefData
;
484 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
488 wxLogWarning( wxT("No image handler for type %s defined."), mimetype
.GetData() );
493 return handler
->LoadFile( this, stream
);
496 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
498 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
500 wxImageHandler
*handler
= FindHandler(type
);
504 wxLogWarning( wxT("No image handler for type %d defined."), type
);
509 return handler
->SaveFile( this, stream
);
512 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
514 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
516 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
520 wxLogWarning( wxT("No image handler for type %s defined."), mimetype
.GetData() );
525 return handler
->SaveFile( this, stream
);
527 #endif // wxUSE_STREAMS
529 void wxImage::AddHandler( wxImageHandler
*handler
)
531 // make sure that the memory will be freed at the program end
532 sm_handlers
.DeleteContents(TRUE
);
534 sm_handlers
.Append( handler
);
537 void wxImage::InsertHandler( wxImageHandler
*handler
)
539 // make sure that the memory will be freed at the program end
540 sm_handlers
.DeleteContents(TRUE
);
542 sm_handlers
.Insert( handler
);
545 bool wxImage::RemoveHandler( const wxString
& name
)
547 wxImageHandler
*handler
= FindHandler(name
);
550 sm_handlers
.DeleteObject(handler
);
557 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
559 wxNode
*node
= sm_handlers
.First();
562 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
563 if (handler
->GetName().Cmp(name
) == 0) return handler
;
567 return (wxImageHandler
*)NULL
;
570 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
572 wxNode
*node
= sm_handlers
.First();
575 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
576 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
577 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
581 return (wxImageHandler
*)NULL
;
584 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
586 wxNode
*node
= sm_handlers
.First();
589 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
590 if (handler
->GetType() == bitmapType
) return handler
;
596 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
598 wxNode
*node
= sm_handlers
.First();
601 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
602 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
608 void wxImage::InitStandardHandlers()
610 AddHandler( new wxBMPHandler
);
613 void wxImage::CleanUpHandlers()
615 wxNode
*node
= sm_handlers
.First();
618 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
619 wxNode
*next
= node
->Next();
626 //-----------------------------------------------------------------------------
628 //-----------------------------------------------------------------------------
630 #if !USE_SHARED_LIBRARIES
631 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler
,wxObject
)
635 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
640 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
645 bool wxImageHandler::CanRead( const wxString
& name
)
648 if (wxFileExists(name
))
650 wxFileInputStream
stream(name
);
651 return CanRead(stream
);
655 wxLogError( wxT("Can't check image format of file '%s': file does not exist."), name
.c_str() );
659 #else // !wxUSE_STREAMS
661 #endif // wxUSE_STREAMS
666 #endif // wxUSE_STREAMS
668 //-----------------------------------------------------------------------------
669 // MSW conversion routines
670 //-----------------------------------------------------------------------------
674 wxBitmap
wxImage::ConvertToBitmap() const
679 // sizeLimit is the MS upper limit for the DIB size
681 int sizeLimit
= 1024*768*3;
683 int sizeLimit
= 0x7fff ;
686 // width and height of the device-dependent bitmap
687 int width
= GetWidth();
688 int bmpHeight
= GetHeight();
690 // calc the number of bytes per scanline and padding
691 int bytePerLine
= width
*3;
692 int sizeDWORD
= sizeof( DWORD
);
693 int lineBoundary
= bytePerLine
% sizeDWORD
;
695 if( lineBoundary
> 0 )
697 padding
= sizeDWORD
- lineBoundary
;
698 bytePerLine
+= padding
;
700 // calc the number of DIBs and heights of DIBs
703 int height
= sizeLimit
/bytePerLine
;
704 if( height
>= bmpHeight
)
708 numDIB
= bmpHeight
/ height
;
709 hRemain
= bmpHeight
% height
;
710 if( hRemain
>0 ) numDIB
++;
713 // set bitmap parameters
715 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
716 bitmap
.SetWidth( width
);
717 bitmap
.SetHeight( bmpHeight
);
718 bitmap
.SetDepth( wxDisplayDepth() );
720 // create a DIB header
721 int headersize
= sizeof(BITMAPINFOHEADER
);
722 LPBITMAPINFO lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
723 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
724 // Fill in the DIB header
725 lpDIBh
->bmiHeader
.biSize
= headersize
;
726 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
727 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
728 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
729 // the general formula for biSizeImage:
730 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
731 lpDIBh
->bmiHeader
.biPlanes
= 1;
732 lpDIBh
->bmiHeader
.biBitCount
= 24;
733 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
734 lpDIBh
->bmiHeader
.biClrUsed
= 0;
735 // These seem not really needed for our purpose here.
736 lpDIBh
->bmiHeader
.biClrImportant
= 0;
737 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
738 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
739 // memory for DIB data
740 unsigned char *lpBits
;
741 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
744 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
749 // create and set the device-dependent bitmap
750 HDC hdc
= ::GetDC(NULL
);
751 HDC memdc
= ::CreateCompatibleDC( hdc
);
753 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
754 ::SelectObject( memdc
, hbitmap
);
756 // copy image data into DIB data and then into DDB (in a loop)
757 unsigned char *data
= GetData();
760 unsigned char *ptdata
= data
;
761 unsigned char *ptbits
;
763 for( n
=0; n
<numDIB
; n
++ )
765 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
767 // redefine height and size of the (possibly) last smaller DIB
768 // memory is not reallocated
770 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
771 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
775 for( j
=0; j
<height
; j
++ )
777 for( i
=0; i
<width
; i
++ )
779 *(ptbits
++) = *(ptdata
+2);
780 *(ptbits
++) = *(ptdata
+1);
781 *(ptbits
++) = *(ptdata
);
784 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
786 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
787 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
789 // if numDIB = 1, lines below can also be used
790 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
791 // The above line is equivalent to the following two lines.
792 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
793 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
794 // or the following lines
795 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
796 // HDC memdc = ::CreateCompatibleDC( hdc );
797 // ::SelectObject( memdc, hbitmap);
798 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
799 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
800 // ::SelectObject( memdc, 0 );
801 // ::DeleteDC( memdc );
803 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
805 // similarly, created an mono-bitmap for the possible mask
808 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
809 ::SelectObject( memdc
, hbitmap
);
810 if( numDIB
== 1 ) height
= bmpHeight
;
811 else height
= sizeLimit
/bytePerLine
;
812 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
813 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
815 unsigned char r
= GetMaskRed();
816 unsigned char g
= GetMaskGreen();
817 unsigned char b
= GetMaskBlue();
818 unsigned char zero
= 0, one
= 255;
820 for( n
=0; n
<numDIB
; n
++ )
822 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
824 // redefine height and size of the (possibly) last smaller DIB
825 // memory is not reallocated
827 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
828 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
831 for( int j
=0; j
<height
; j
++ )
833 for(i
=0; i
<width
; i
++ )
835 if( (*(ptdata
++)!=r
) | (*(ptdata
++)!=g
) | (*(ptdata
++)!=b
) )
848 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
850 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
851 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
854 // create a wxMask object
855 wxMask
*mask
= new wxMask();
856 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
857 bitmap
.SetMask( mask
);
858 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
859 /* The following can also be used but is slow to run
860 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
861 wxMask *mask = new wxMask( bitmap, colour );
862 bitmap.SetMask( mask );
866 // free allocated resources
867 ::SelectObject( memdc
, 0 );
869 ::ReleaseDC(NULL
, hdc
);
873 // check the wxBitmap object
874 if( bitmap
.GetHBITMAP() )
875 bitmap
.SetOk( TRUE
);
877 bitmap
.SetOk( FALSE
);
882 wxImage::wxImage( const wxBitmap
&bitmap
)
887 wxFAIL_MSG( wxT("invalid bitmap") );
891 // create an wxImage object
892 int width
= bitmap
.GetWidth();
893 int height
= bitmap
.GetHeight();
894 Create( width
, height
);
895 unsigned char *data
= GetData();
898 wxFAIL_MSG( wxT("could not allocate data for image") );
902 // calc the number of bytes per scanline and padding in the DIB
903 int bytePerLine
= width
*3;
904 int sizeDWORD
= sizeof( DWORD
);
905 int lineBoundary
= bytePerLine
% sizeDWORD
;
907 if( lineBoundary
> 0 )
909 padding
= sizeDWORD
- lineBoundary
;
910 bytePerLine
+= padding
;
913 // create a DIB header
914 int headersize
= sizeof(BITMAPINFOHEADER
);
915 LPBITMAPINFO lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
918 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
922 // Fill in the DIB header
923 lpDIBh
->bmiHeader
.biSize
= headersize
;
924 lpDIBh
->bmiHeader
.biWidth
= width
;
925 lpDIBh
->bmiHeader
.biHeight
= -height
;
926 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
927 lpDIBh
->bmiHeader
.biPlanes
= 1;
928 lpDIBh
->bmiHeader
.biBitCount
= 24;
929 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
930 lpDIBh
->bmiHeader
.biClrUsed
= 0;
931 // These seem not really needed for our purpose here.
932 lpDIBh
->bmiHeader
.biClrImportant
= 0;
933 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
934 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
935 // memory for DIB data
936 unsigned char *lpBits
;
937 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
940 wxFAIL_MSG( wxT("could not allocate data for DIB") );
946 // copy data from the device-dependent bitmap to the DIB
947 HDC hdc
= ::GetDC(NULL
);
949 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
950 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
952 // copy DIB data into the wxImage object
954 unsigned char *ptdata
= data
;
955 unsigned char *ptbits
= lpBits
;
956 for( i
=0; i
<height
; i
++ )
958 for( j
=0; j
<width
; j
++ )
960 *(ptdata
++) = *(ptbits
+2);
961 *(ptdata
++) = *(ptbits
+1);
962 *(ptdata
++) = *(ptbits
);
968 // similarly, set data according to the possible mask bitmap
969 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
971 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
972 // memory DC created, color set, data copied, and memory DC deleted
973 HDC memdc
= ::CreateCompatibleDC( hdc
);
974 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
975 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
976 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
978 // background color set to RGB(16,16,16) in consistent with wxGTK
979 unsigned char r
=16, g
=16, b
=16;
982 for( i
=0; i
<height
; i
++ )
984 for( j
=0; j
<width
; j
++ )
998 SetMaskColour( r
, g
, b
);
1005 // free allocated resources
1006 ::ReleaseDC(NULL
, hdc
);
1013 //-----------------------------------------------------------------------------
1014 // GTK conversion routines
1015 //-----------------------------------------------------------------------------
1019 #include "gtk/gtk.h"
1020 #include "gdk/gdk.h"
1021 #include "gdk/gdkx.h"
1023 #if (GTK_MINOR_VERSION > 0)
1024 #include "gdk/gdkrgb.h"
1027 wxBitmap
wxImage::ConvertToBitmap() const
1031 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1033 int width
= GetWidth();
1034 int height
= GetHeight();
1036 bitmap
.SetHeight( height
);
1037 bitmap
.SetWidth( width
);
1039 bitmap
.SetPixmap( gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, -1 ) );
1043 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1044 if (visual
== NULL
) visual
= gdk_visual_get_system();
1045 int bpp
= visual
->depth
;
1047 bitmap
.SetDepth( bpp
);
1049 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1050 if (bpp
< 8) bpp
= 8;
1052 #if (GTK_MINOR_VERSION > 0)
1054 if (!HasMask() && (bpp
> 8))
1056 static bool s_hasInitialized
= FALSE
;
1058 if (!s_hasInitialized
)
1061 s_hasInitialized
= TRUE
;
1064 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1066 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1070 GDK_RGB_DITHER_NONE
,
1081 // Create picture image
1083 GdkImage
*data_image
=
1084 gdk_image_new( GDK_IMAGE_FASTEST
, gdk_visual_get_system(), width
, height
);
1086 // Create mask image
1088 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1092 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1094 mask_image
= gdk_image_new_bitmap( gdk_visual_get_system(), mask_data
, width
, height
);
1096 wxMask
*mask
= new wxMask();
1097 mask
->m_bitmap
= gdk_pixmap_new( (GdkWindow
*)&gdk_root_parent
, width
, height
, 1 );
1099 bitmap
.SetMask( mask
);
1104 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1105 byte_order b_o
= RGB
;
1109 GdkVisual
*visual
= gdk_visual_get_system();
1110 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1111 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1112 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1113 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1114 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1115 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1118 int r_mask
= GetMaskRed();
1119 int g_mask
= GetMaskGreen();
1120 int b_mask
= GetMaskBlue();
1122 unsigned char* data
= GetData();
1125 for (int y
= 0; y
< height
; y
++)
1127 for (int x
= 0; x
< width
; x
++)
1129 int r
= data
[index
];
1131 int g
= data
[index
];
1133 int b
= data
[index
];
1138 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1139 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1141 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1146 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1147 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1149 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1157 if (wxTheApp
->m_colorCube
)
1159 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1163 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1164 GdkColor
*colors
= cmap
->colors
;
1165 int max
= 3 * (65536);
1167 for (int i
= 0; i
< cmap
->size
; i
++)
1169 int rdiff
= (r
<< 8) - colors
[i
].red
;
1170 int gdiff
= (g
<< 8) - colors
[i
].green
;
1171 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1172 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1173 if (sum
< max
) { pixel
= i
; max
= sum
; }
1177 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1183 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1184 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1189 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1190 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1199 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1200 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1201 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1202 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1203 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1204 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1206 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1215 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1217 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1219 gdk_image_destroy( data_image
);
1220 gdk_gc_unref( data_gc
);
1226 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1228 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1230 gdk_image_destroy( mask_image
);
1231 gdk_gc_unref( mask_gc
);
1237 wxImage::wxImage( const wxBitmap
&bitmap
)
1239 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1241 GdkImage
*gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1243 bitmap
.GetWidth(), bitmap
.GetHeight() );
1245 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1247 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1248 char unsigned *data
= GetData();
1252 gdk_image_destroy( gdk_image
);
1253 wxFAIL_MSG( wxT("couldn't create image") );
1257 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1258 if (bitmap
.GetMask())
1260 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1262 bitmap
.GetWidth(), bitmap
.GetHeight() );
1264 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1267 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1268 if (visual
== NULL
) visual
= gdk_window_get_visual( (GdkWindow
*) &gdk_root_parent
);
1269 int bpp
= visual
->depth
;
1270 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1272 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1275 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1277 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1279 wxInt32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1280 pixel
= wxINT32_SWAP_ON_BE( pixel
);
1283 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1284 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1285 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1286 } else if (bpp
== 15)
1288 data
[pos
] = (pixel
>> 7) & 0xf8;
1289 data
[pos
+1] = (pixel
>> 2) & 0xf8;
1290 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1291 } else if (bpp
== 16)
1293 data
[pos
] = (pixel
>> 8) & 0xf8;
1294 data
[pos
+1] = (pixel
>> 3) & 0xfc;
1295 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1298 data
[pos
] = (pixel
>> 16) & 0xff;
1299 data
[pos
+1] = (pixel
>> 8) & 0xff;
1300 data
[pos
+2] = pixel
& 0xff;
1305 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1306 if (mask_pixel
== 0)
1318 gdk_image_destroy( gdk_image
);
1319 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1324 //-----------------------------------------------------------------------------
1325 // Motif conversion routines
1326 //-----------------------------------------------------------------------------
1331 #include "wx/utils.h"
1334 wxBitmap
wxImage::ConvertToBitmap() const
1338 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1340 int width
= GetWidth();
1341 int height
= GetHeight();
1343 bitmap
.SetHeight( height
);
1344 bitmap
.SetWidth( width
);
1346 Display
*dpy
= (Display
*) wxGetDisplay();
1347 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1348 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1352 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1353 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
1355 bitmap
.Create( width
, height
, bpp
);
1360 GdkImage *mask_image = (GdkImage*) NULL;
1364 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1366 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1368 wxMask *mask = new wxMask();
1369 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1371 bitmap.SetMask( mask );
1375 // Retrieve depth info
1377 XVisualInfo vinfo_template
;
1380 vinfo_template
.visual
= vis
;
1381 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1382 vinfo_template
.depth
= bpp
;
1385 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1387 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
1391 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1392 if (bpp
< 8) bpp
= 8;
1396 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1397 byte_order b_o
= RGB
;
1401 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
1402 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
1403 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
1404 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
1405 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
1406 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
1410 int r_mask = GetMaskRed();
1411 int g_mask = GetMaskGreen();
1412 int b_mask = GetMaskBlue();
1418 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
1420 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
1421 XQueryColors( dpy
, cmap
, colors
, 256 );
1424 unsigned char* data
= GetData();
1427 for (int y
= 0; y
< height
; y
++)
1429 for (int x
= 0; x
< width
; x
++)
1431 int r
= data
[index
];
1433 int g
= data
[index
];
1435 int b
= data
[index
];
1441 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1442 gdk_image_put_pixel( mask_image, x, y, 1 );
1444 gdk_image_put_pixel( mask_image, x, y, 0 );
1454 if (wxTheApp->m_colorCube)
1456 pixel = wxTheApp->m_colorCube
1457 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1462 int max
= 3 * (65536);
1463 for (int i
= 0; i
< 256; i
++)
1465 int rdiff
= (r
<< 8) - colors
[i
].red
;
1466 int gdiff
= (g
<< 8) - colors
[i
].green
;
1467 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1468 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1469 if (sum
< max
) { pixel
= i
; max
= sum
; }
1474 XPutPixel( data_image
, x
, y
, pixel
);
1479 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1480 XPutPixel( data_image
, x
, y
, pixel
);
1485 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1486 XPutPixel( data_image
, x
, y
, pixel
);
1495 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1496 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1497 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1498 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1499 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1500 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1502 XPutPixel( data_image
, x
, y
, pixel
);
1512 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
1513 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
1514 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
1516 XDestroyImage( data_image
);
1524 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1526 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1528 gdk_image_destroy( mask_image );
1529 gdk_gc_unref( mask_gc );
1536 wxImage::wxImage( const wxBitmap
&bitmap
)
1538 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1540 Display
*dpy
= (Display
*) wxGetDisplay();
1541 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1542 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1544 XImage
*ximage
= XGetImage( dpy
,
1545 (Drawable
)bitmap
.GetPixmap(),
1547 bitmap
.GetWidth(), bitmap
.GetHeight(),
1548 AllPlanes
, ZPixmap
);
1550 wxCHECK_RET( ximage
, wxT("couldn't create image") );
1552 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1553 char unsigned *data
= GetData();
1557 XDestroyImage( ximage
);
1558 wxFAIL_MSG( wxT("couldn't create image") );
1563 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1564 if (bitmap.GetMask())
1566 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1568 bitmap.GetWidth(), bitmap.GetHeight() );
1570 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1574 // Retrieve depth info
1576 XVisualInfo vinfo_template
;
1579 vinfo_template
.visual
= vis
;
1580 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1581 vinfo_template
.depth
= bpp
;
1584 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1586 wxCHECK_RET( vi
, wxT("no visual") );
1588 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1595 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
1597 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
1598 XQueryColors( dpy
, cmap
, colors
, 256 );
1602 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1604 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1606 int pixel
= XGetPixel( ximage
, i
, j
);
1609 data
[pos
] = colors
[pixel
].red
>> 8;
1610 data
[pos
+1] = colors
[pixel
].green
>> 8;
1611 data
[pos
+2] = colors
[pixel
].blue
>> 8;
1612 } else if (bpp
== 15)
1614 data
[pos
] = (pixel
>> 7) & 0xf8;
1615 data
[pos
+1] = (pixel
>> 2) & 0xf8;
1616 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1617 } else if (bpp
== 16)
1619 data
[pos
] = (pixel
>> 8) & 0xf8;
1620 data
[pos
+1] = (pixel
>> 3) & 0xfc;
1621 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1624 data
[pos
] = (pixel
>> 16) & 0xff;
1625 data
[pos
+1] = (pixel
>> 8) & 0xff;
1626 data
[pos
+2] = pixel
& 0xff;
1632 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1633 if (mask_pixel == 0)
1646 XDestroyImage( ximage
);
1648 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1653 // A module to allow wxImage initialization/cleanup
1654 // without calling these functions from app.cpp or from
1655 // the user's application.
1657 class wxImageModule
: public wxModule
1659 DECLARE_DYNAMIC_CLASS(wxImageModule
)
1662 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
1663 void OnExit() { wxImage::CleanUpHandlers(); };
1666 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)