1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "image.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
22 #include "wx/bitmap.h"
26 #include "wx/filefn.h"
27 #include "wx/wfstream.h"
29 #include "wx/module.h"
40 #include "wx/msw/private.h"
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
47 class wxImageRefData
: public wxObjectRefData
55 unsigned char *m_data
;
57 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
61 wxImageRefData::wxImageRefData()
65 m_data
= (unsigned char*) NULL
;
73 wxImageRefData::~wxImageRefData()
79 wxList
wxImage::sm_handlers
;
81 //-----------------------------------------------------------------------------
83 #define M_IMGDATA ((wxImageRefData *)m_refData)
85 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
91 wxImage::wxImage( int width
, int height
)
93 Create( width
, height
);
96 wxImage::wxImage( const wxString
& name
, long type
)
98 LoadFile( name
, type
);
101 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
)
103 LoadFile( name
, mimetype
);
107 wxImage::wxImage( wxInputStream
& stream
, long type
)
109 LoadFile( stream
, type
);
112 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
)
114 LoadFile( stream
, mimetype
);
116 #endif // wxUSE_STREAMS
118 wxImage::wxImage( const wxImage
& image
)
123 wxImage::wxImage( const wxImage
* image
)
125 if (image
) Ref(*image
);
128 void wxImage::Create( int width
, int height
)
132 m_refData
= new wxImageRefData();
134 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
135 if (M_IMGDATA
->m_data
)
137 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
139 M_IMGDATA
->m_width
= width
;
140 M_IMGDATA
->m_height
= height
;
141 M_IMGDATA
->m_ok
= TRUE
;
149 void wxImage::Destroy()
154 wxImage
wxImage::Scale( int width
, int height
) const
158 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
160 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, wxT("invalid image size") );
162 image
.Create( width
, height
);
164 char unsigned *data
= image
.GetData();
166 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
168 if (M_IMGDATA
->m_hasMask
)
169 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
171 long old_height
= M_IMGDATA
->m_height
;
172 long old_width
= M_IMGDATA
->m_width
;
174 char unsigned *source_data
= M_IMGDATA
->m_data
;
175 char unsigned *target_data
= data
;
177 for (long j
= 0; j
< height
; j
++)
179 long y_offset
= (j
* old_height
/ height
) * old_width
;
181 for (long i
= 0; i
< width
; i
++)
184 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
193 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
197 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
199 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()),
200 image
, wxT("invalid subimage size") );
202 int subwidth
=rect
.GetWidth();
203 const int subheight
=rect
.GetHeight();
205 image
.Create( subwidth
, subheight
);
207 char unsigned *subdata
= image
.GetData(), *data
=GetData();
209 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
211 if (M_IMGDATA
->m_hasMask
)
212 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
214 const int subleft
=3*rect
.GetLeft();
215 const int width
=3*GetWidth();
218 data
+=rect
.GetTop()*width
+subleft
;
220 for (long j
= 0; j
< subheight
; ++j
)
222 memcpy( subdata
, data
, subwidth
);
230 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
231 unsigned char r2
, unsigned char g2
, unsigned char b2
)
233 wxCHECK_RET( Ok(), wxT("invalid image") );
235 char unsigned *data
= GetData();
237 const int w
= GetWidth();
238 const int h
= GetHeight();
240 for (int j
= 0; j
< h
; j
++)
241 for (int i
= 0; i
< w
; i
++)
243 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
253 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
255 wxCHECK_RET( Ok(), wxT("invalid image") );
257 int w
= M_IMGDATA
->m_width
;
258 int h
= M_IMGDATA
->m_height
;
260 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
262 long pos
= (y
* w
+ x
) * 3;
264 M_IMGDATA
->m_data
[ pos
] = r
;
265 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
266 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
269 unsigned char wxImage::GetRed( int x
, int y
)
271 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
273 int w
= M_IMGDATA
->m_width
;
274 int h
= M_IMGDATA
->m_height
;
276 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
278 long pos
= (y
* w
+ x
) * 3;
280 return M_IMGDATA
->m_data
[pos
];
283 unsigned char wxImage::GetGreen( int x
, int y
)
285 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
287 int w
= M_IMGDATA
->m_width
;
288 int h
= M_IMGDATA
->m_height
;
290 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
292 long pos
= (y
* w
+ x
) * 3;
294 return M_IMGDATA
->m_data
[pos
+1];
297 unsigned char wxImage::GetBlue( int x
, int y
)
299 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
301 int w
= M_IMGDATA
->m_width
;
302 int h
= M_IMGDATA
->m_height
;
304 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
306 long pos
= (y
* w
+ x
) * 3;
308 return M_IMGDATA
->m_data
[pos
+2];
311 bool wxImage::Ok() const
313 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
316 char unsigned *wxImage::GetData() const
318 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
320 return M_IMGDATA
->m_data
;
323 void wxImage::SetData( char unsigned *data
)
325 wxCHECK_RET( Ok(), wxT("invalid image") );
327 wxImageRefData
*newRefData
= new wxImageRefData();
329 newRefData
->m_width
= M_IMGDATA
->m_width
;
330 newRefData
->m_height
= M_IMGDATA
->m_height
;
331 newRefData
->m_data
= data
;
332 newRefData
->m_ok
= TRUE
;
333 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
334 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
335 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
336 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
340 m_refData
= newRefData
;
343 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
345 wxCHECK_RET( Ok(), wxT("invalid image") );
347 M_IMGDATA
->m_maskRed
= r
;
348 M_IMGDATA
->m_maskGreen
= g
;
349 M_IMGDATA
->m_maskBlue
= b
;
350 M_IMGDATA
->m_hasMask
= TRUE
;
353 unsigned char wxImage::GetMaskRed() const
355 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
357 return M_IMGDATA
->m_maskRed
;
360 unsigned char wxImage::GetMaskGreen() const
362 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
364 return M_IMGDATA
->m_maskGreen
;
367 unsigned char wxImage::GetMaskBlue() const
369 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
371 return M_IMGDATA
->m_maskBlue
;
374 void wxImage::SetMask( bool mask
)
376 wxCHECK_RET( Ok(), wxT("invalid image") );
378 M_IMGDATA
->m_hasMask
= mask
;
381 bool wxImage::HasMask() const
383 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
385 return M_IMGDATA
->m_hasMask
;
388 int wxImage::GetWidth() const
390 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
392 return M_IMGDATA
->m_width
;
395 int wxImage::GetHeight() const
397 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
399 return M_IMGDATA
->m_height
;
402 bool wxImage::LoadFile( const wxString
& filename
, long type
)
405 if (wxFileExists(filename
))
407 wxFileInputStream
stream(filename
);
408 wxBufferedInputStream
bstream( stream
);
409 return LoadFile(bstream
, type
);
413 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
417 #else // !wxUSE_STREAMS
419 #endif // wxUSE_STREAMS
422 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
425 if (wxFileExists(filename
))
427 wxFileInputStream
stream(filename
);
428 wxBufferedInputStream
bstream( stream
);
429 return LoadFile(bstream
, mimetype
);
433 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
437 #else // !wxUSE_STREAMS
439 #endif // wxUSE_STREAMS
442 bool wxImage::SaveFile( const wxString
& filename
, int type
)
445 wxFileOutputStream
stream(filename
);
447 if ( stream
.LastError() == wxStream_NOERROR
)
449 wxBufferedOutputStream
bstream( stream
);
450 return SaveFile(bstream
, type
);
453 #endif // wxUSE_STREAMS
457 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
460 wxFileOutputStream
stream(filename
);
462 if ( stream
.LastError() == wxStream_NOERROR
)
464 wxBufferedOutputStream
bstream( stream
);
465 return SaveFile(bstream
, mimetype
);
468 #endif // wxUSE_STREAMS
472 bool wxImage::CanRead( const wxString
&name
)
475 wxFileInputStream
stream(name
);
476 return CanRead(stream
);
484 bool wxImage::CanRead( wxInputStream
&stream
)
486 wxList
&list
=GetHandlers();
488 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
490 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
491 if (handler
->CanRead( stream
))
498 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
502 m_refData
= new wxImageRefData
;
504 wxImageHandler
*handler
;
506 if (type
==wxBITMAP_TYPE_ANY
)
508 wxList
&list
=GetHandlers();
510 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
512 handler
=(wxImageHandler
*)node
->GetData();
513 if (handler
->CanRead( stream
))
514 return handler
->LoadFile( this, stream
);
518 wxLogWarning( _("No handler found for image type.") );
522 handler
= FindHandler(type
);
526 wxLogWarning( _("No image handler for type %d defined."), type
);
531 return handler
->LoadFile( this, stream
);
534 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
538 m_refData
= new wxImageRefData
;
540 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
544 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
549 return handler
->LoadFile( this, stream
);
552 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
554 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
556 wxImageHandler
*handler
= FindHandler(type
);
560 wxLogWarning( _("No image handler for type %d defined."), type
);
565 return handler
->SaveFile( this, stream
);
568 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
570 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
572 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
576 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
581 return handler
->SaveFile( this, stream
);
583 #endif // wxUSE_STREAMS
585 void wxImage::AddHandler( wxImageHandler
*handler
)
587 // make sure that the memory will be freed at the program end
588 sm_handlers
.DeleteContents(TRUE
);
590 sm_handlers
.Append( handler
);
593 void wxImage::InsertHandler( wxImageHandler
*handler
)
595 // make sure that the memory will be freed at the program end
596 sm_handlers
.DeleteContents(TRUE
);
598 sm_handlers
.Insert( handler
);
601 bool wxImage::RemoveHandler( const wxString
& name
)
603 wxImageHandler
*handler
= FindHandler(name
);
606 sm_handlers
.DeleteObject(handler
);
613 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
615 wxNode
*node
= sm_handlers
.First();
618 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
619 if (handler
->GetName().Cmp(name
) == 0) return handler
;
623 return (wxImageHandler
*)NULL
;
626 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
628 wxNode
*node
= sm_handlers
.First();
631 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
632 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
633 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
637 return (wxImageHandler
*)NULL
;
640 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
642 wxNode
*node
= sm_handlers
.First();
645 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
646 if (handler
->GetType() == bitmapType
) return handler
;
652 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
654 wxNode
*node
= sm_handlers
.First();
657 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
658 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
664 void wxImage::InitStandardHandlers()
666 AddHandler( new wxBMPHandler
);
669 void wxImage::CleanUpHandlers()
671 wxNode
*node
= sm_handlers
.First();
674 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
675 wxNode
*next
= node
->Next();
682 //-----------------------------------------------------------------------------
684 //-----------------------------------------------------------------------------
686 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
689 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
694 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
699 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
704 bool wxImageHandler::CanRead( const wxString
& name
)
706 if (wxFileExists(name
))
708 wxFileInputStream
stream(name
);
709 return CanRead(stream
);
713 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
720 #endif // wxUSE_STREAMS
722 //-----------------------------------------------------------------------------
723 // MSW conversion routines
724 //-----------------------------------------------------------------------------
728 wxBitmap
wxImage::ConvertToBitmap() const
733 // sizeLimit is the MS upper limit for the DIB size
735 int sizeLimit
= 1024*768*3;
737 int sizeLimit
= 0x7fff ;
740 // width and height of the device-dependent bitmap
741 int width
= GetWidth();
742 int bmpHeight
= GetHeight();
744 // calc the number of bytes per scanline and padding
745 int bytePerLine
= width
*3;
746 int sizeDWORD
= sizeof( DWORD
);
747 int lineBoundary
= bytePerLine
% sizeDWORD
;
749 if( lineBoundary
> 0 )
751 padding
= sizeDWORD
- lineBoundary
;
752 bytePerLine
+= padding
;
754 // calc the number of DIBs and heights of DIBs
757 int height
= sizeLimit
/bytePerLine
;
758 if( height
>= bmpHeight
)
762 numDIB
= bmpHeight
/ height
;
763 hRemain
= bmpHeight
% height
;
764 if( hRemain
>0 ) numDIB
++;
767 // set bitmap parameters
769 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
770 bitmap
.SetWidth( width
);
771 bitmap
.SetHeight( bmpHeight
);
772 bitmap
.SetDepth( wxDisplayDepth() );
774 // create a DIB header
775 int headersize
= sizeof(BITMAPINFOHEADER
);
776 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
777 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
778 // Fill in the DIB header
779 lpDIBh
->bmiHeader
.biSize
= headersize
;
780 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
781 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
782 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
783 // the general formula for biSizeImage:
784 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
785 lpDIBh
->bmiHeader
.biPlanes
= 1;
786 lpDIBh
->bmiHeader
.biBitCount
= 24;
787 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
788 lpDIBh
->bmiHeader
.biClrUsed
= 0;
789 // These seem not really needed for our purpose here.
790 lpDIBh
->bmiHeader
.biClrImportant
= 0;
791 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
792 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
793 // memory for DIB data
794 unsigned char *lpBits
;
795 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
798 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
803 // create and set the device-dependent bitmap
804 HDC hdc
= ::GetDC(NULL
);
805 HDC memdc
= ::CreateCompatibleDC( hdc
);
807 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
808 ::SelectObject( memdc
, hbitmap
);
810 // copy image data into DIB data and then into DDB (in a loop)
811 unsigned char *data
= GetData();
814 unsigned char *ptdata
= data
;
815 unsigned char *ptbits
;
817 for( n
=0; n
<numDIB
; n
++ )
819 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
821 // redefine height and size of the (possibly) last smaller DIB
822 // memory is not reallocated
824 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
825 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
829 for( j
=0; j
<height
; j
++ )
831 for( i
=0; i
<width
; i
++ )
833 *(ptbits
++) = *(ptdata
+2);
834 *(ptbits
++) = *(ptdata
+1);
835 *(ptbits
++) = *(ptdata
);
838 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
840 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
841 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
843 // if numDIB = 1, lines below can also be used
844 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
845 // The above line is equivalent to the following two lines.
846 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
847 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
848 // or the following lines
849 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
850 // HDC memdc = ::CreateCompatibleDC( hdc );
851 // ::SelectObject( memdc, hbitmap);
852 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
853 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
854 // ::SelectObject( memdc, 0 );
855 // ::DeleteDC( memdc );
857 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
859 // similarly, created an mono-bitmap for the possible mask
862 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
863 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
864 if( numDIB
== 1 ) height
= bmpHeight
;
865 else height
= sizeLimit
/bytePerLine
;
866 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
867 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
869 unsigned char r
= GetMaskRed();
870 unsigned char g
= GetMaskGreen();
871 unsigned char b
= GetMaskBlue();
872 unsigned char zero
= 0, one
= 255;
874 for( n
=0; n
<numDIB
; n
++ )
876 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
878 // redefine height and size of the (possibly) last smaller DIB
879 // memory is not reallocated
881 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
882 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
885 for( int j
=0; j
<height
; j
++ )
887 for(i
=0; i
<width
; i
++ )
889 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
890 unsigned char cr
= (*(ptdata
++)) ;
891 unsigned char cg
= (*(ptdata
++)) ;
892 unsigned char cb
= (*(ptdata
++)) ;
894 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
907 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
909 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
910 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
913 // create a wxMask object
914 wxMask
*mask
= new wxMask();
915 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
916 bitmap
.SetMask( mask
);
917 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
918 /* The following can also be used but is slow to run
919 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
920 wxMask *mask = new wxMask( bitmap, colour );
921 bitmap.SetMask( mask );
924 ::SelectObject( memdc
, hbmpOld
);
927 // free allocated resources
929 ::ReleaseDC(NULL
, hdc
);
933 #if WXWIN_COMPATIBILITY_2
934 // check the wxBitmap object
935 bitmap
.GetBitmapData()->SetOk();
936 #endif // WXWIN_COMPATIBILITY_2
941 wxImage::wxImage( const wxBitmap
&bitmap
)
946 wxFAIL_MSG( wxT("invalid bitmap") );
950 // create an wxImage object
951 int width
= bitmap
.GetWidth();
952 int height
= bitmap
.GetHeight();
953 Create( width
, height
);
954 unsigned char *data
= GetData();
957 wxFAIL_MSG( wxT("could not allocate data for image") );
961 // calc the number of bytes per scanline and padding in the DIB
962 int bytePerLine
= width
*3;
963 int sizeDWORD
= sizeof( DWORD
);
964 int lineBoundary
= bytePerLine
% sizeDWORD
;
966 if( lineBoundary
> 0 )
968 padding
= sizeDWORD
- lineBoundary
;
969 bytePerLine
+= padding
;
972 // create a DIB header
973 int headersize
= sizeof(BITMAPINFOHEADER
);
974 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
977 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
981 // Fill in the DIB header
982 lpDIBh
->bmiHeader
.biSize
= headersize
;
983 lpDIBh
->bmiHeader
.biWidth
= width
;
984 lpDIBh
->bmiHeader
.biHeight
= -height
;
985 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
986 lpDIBh
->bmiHeader
.biPlanes
= 1;
987 lpDIBh
->bmiHeader
.biBitCount
= 24;
988 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
989 lpDIBh
->bmiHeader
.biClrUsed
= 0;
990 // These seem not really needed for our purpose here.
991 lpDIBh
->bmiHeader
.biClrImportant
= 0;
992 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
993 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
994 // memory for DIB data
995 unsigned char *lpBits
;
996 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
999 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1005 // copy data from the device-dependent bitmap to the DIB
1006 HDC hdc
= ::GetDC(NULL
);
1008 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1009 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1011 // copy DIB data into the wxImage object
1013 unsigned char *ptdata
= data
;
1014 unsigned char *ptbits
= lpBits
;
1015 for( i
=0; i
<height
; i
++ )
1017 for( j
=0; j
<width
; j
++ )
1019 *(ptdata
++) = *(ptbits
+2);
1020 *(ptdata
++) = *(ptbits
+1);
1021 *(ptdata
++) = *(ptbits
);
1027 // similarly, set data according to the possible mask bitmap
1028 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1030 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1031 // memory DC created, color set, data copied, and memory DC deleted
1032 HDC memdc
= ::CreateCompatibleDC( hdc
);
1033 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1034 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1035 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1036 ::DeleteDC( memdc
);
1037 // background color set to RGB(16,16,16) in consistent with wxGTK
1038 unsigned char r
=16, g
=16, b
=16;
1041 for( i
=0; i
<height
; i
++ )
1043 for( j
=0; j
<width
; j
++ )
1057 SetMaskColour( r
, g
, b
);
1064 // free allocated resources
1065 ::ReleaseDC(NULL
, hdc
);
1074 #include <PictUtils.h>
1076 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1077 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1078 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1079 extern GWorldPtr
wxMacCreateGWorld( int height
, int width
, int depth
) ;
1080 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1082 wxBitmap
wxImage::ConvertToBitmap() const
1084 // width and height of the device-dependent bitmap
1085 int width
= GetWidth();
1086 int height
= GetHeight();
1090 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1097 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1099 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1101 wxMask *mask = new wxMask();
1102 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1104 bitmap.SetMask( mask );
1110 int r_mask
= GetMaskRed();
1111 int g_mask
= GetMaskGreen();
1112 int b_mask
= GetMaskBlue();
1115 GDHandle origDevice
;
1117 GetGWorld( &origPort
, &origDevice
) ;
1118 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1120 register unsigned char* data
= GetData();
1123 for (int y
= 0; y
< height
; y
++)
1125 for (int x
= 0; x
< width
; x
++)
1127 unsigned char r
= data
[index
++];
1128 unsigned char g
= data
[index
++];
1129 unsigned char b
= data
[index
++];
1131 color
.red
= ( r
<< 8 ) + r
;
1132 color
.green
= ( g
<< 8 ) + g
;
1133 color
.blue
= ( b
<< 8 ) + b
;
1134 SetCPixel( x
, y
, &color
) ;
1138 SetGWorld( origPort
, origDevice
) ;
1142 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1143 wxMask
*mask
= new wxMask( bitmap
, colour
);
1144 bitmap
.SetMask( mask
);
1150 wxImage::wxImage( const wxBitmap
&bitmap
)
1155 wxFAIL_MSG( "invalid bitmap" );
1159 // create an wxImage object
1160 int width
= bitmap
.GetWidth();
1161 int height
= bitmap
.GetHeight();
1162 Create( width
, height
);
1164 unsigned char *data = GetData();
1167 wxFAIL_MSG( "could not allocate data for image" );
1171 // calc the number of bytes per scanline and padding in the DIB
1172 int bytePerLine = width*3;
1173 int sizeDWORD = sizeof( DWORD );
1174 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1176 if( lineBoundary.rem > 0 )
1178 padding = sizeDWORD - lineBoundary.rem;
1179 bytePerLine += padding;
1182 // create a DIB header
1183 int headersize = sizeof(BITMAPINFOHEADER);
1184 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1187 wxFAIL_MSG( "could not allocate data for DIB header" );
1191 // Fill in the DIB header
1192 lpDIBh->bmiHeader.biSize = headersize;
1193 lpDIBh->bmiHeader.biWidth = width;
1194 lpDIBh->bmiHeader.biHeight = -height;
1195 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1196 lpDIBh->bmiHeader.biPlanes = 1;
1197 lpDIBh->bmiHeader.biBitCount = 24;
1198 lpDIBh->bmiHeader.biCompression = BI_RGB;
1199 lpDIBh->bmiHeader.biClrUsed = 0;
1200 // These seem not really needed for our purpose here.
1201 lpDIBh->bmiHeader.biClrImportant = 0;
1202 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1203 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1204 // memory for DIB data
1205 unsigned char *lpBits;
1206 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1209 wxFAIL_MSG( "could not allocate data for DIB" );
1215 // copy data from the device-dependent bitmap to the DIB
1216 HDC hdc = ::GetDC(NULL);
1218 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1219 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1221 // copy DIB data into the wxImage object
1223 unsigned char *ptdata = data;
1224 unsigned char *ptbits = lpBits;
1225 for( i=0; i<height; i++ )
1227 for( j=0; j<width; j++ )
1229 *(ptdata++) = *(ptbits+2);
1230 *(ptdata++) = *(ptbits+1);
1231 *(ptdata++) = *(ptbits );
1237 // similarly, set data according to the possible mask bitmap
1238 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1240 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1241 // memory DC created, color set, data copied, and memory DC deleted
1242 HDC memdc = ::CreateCompatibleDC( hdc );
1243 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1244 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1245 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1246 ::DeleteDC( memdc );
1247 // background color set to RGB(16,16,16) in consistent with wxGTK
1248 unsigned char r=16, g=16, b=16;
1251 for( i=0; i<height; i++ )
1253 for( j=0; j<width; j++ )
1267 SetMaskColour( r, g, b );
1274 // free allocated resources
1275 ::ReleaseDC(NULL, hdc);
1283 //-----------------------------------------------------------------------------
1284 // GTK conversion routines
1285 //-----------------------------------------------------------------------------
1289 #include <gtk/gtk.h>
1290 #include <gdk/gdk.h>
1291 #include <gdk/gdkx.h>
1293 #if (GTK_MINOR_VERSION > 0)
1294 #include <gdk/gdkrgb.h>
1297 extern GtkWidget
*wxRootWindow
;
1299 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1303 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1305 int width
= GetWidth();
1306 int height
= GetHeight();
1308 bitmap
.SetHeight( height
);
1309 bitmap
.SetWidth( width
);
1311 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1313 bitmap
.SetDepth( 1 );
1315 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1318 // Create picture image
1320 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1322 GdkImage
*data_image
=
1323 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1325 // Create mask image
1327 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1331 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1333 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1335 wxMask
*mask
= new wxMask();
1336 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1338 bitmap
.SetMask( mask
);
1341 int r_mask
= GetMaskRed();
1342 int g_mask
= GetMaskGreen();
1343 int b_mask
= GetMaskBlue();
1345 unsigned char* data
= GetData();
1348 for (int y
= 0; y
< height
; y
++)
1350 for (int x
= 0; x
< width
; x
++)
1352 int r
= data
[index
];
1354 int g
= data
[index
];
1356 int b
= data
[index
];
1361 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1362 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1364 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1367 if ((r
== red
) && (b
== blue
) && (g
== green
))
1368 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1370 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1377 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1379 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1381 gdk_image_destroy( data_image
);
1382 gdk_gc_unref( data_gc
);
1388 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1390 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1392 gdk_image_destroy( mask_image
);
1393 gdk_gc_unref( mask_gc
);
1400 wxBitmap
wxImage::ConvertToBitmap() const
1404 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1406 int width
= GetWidth();
1407 int height
= GetHeight();
1409 bitmap
.SetHeight( height
);
1410 bitmap
.SetWidth( width
);
1412 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1416 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1419 int bpp
= visual
->depth
;
1421 bitmap
.SetDepth( bpp
);
1423 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1424 if (bpp
< 8) bpp
= 8;
1426 #if (GTK_MINOR_VERSION > 0)
1428 if (!HasMask() && (bpp
> 8))
1430 static bool s_hasInitialized
= FALSE
;
1432 if (!s_hasInitialized
)
1435 s_hasInitialized
= TRUE
;
1438 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1440 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1444 GDK_RGB_DITHER_NONE
,
1455 // Create picture image
1457 GdkImage
*data_image
=
1458 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1460 // Create mask image
1462 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1466 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1468 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1470 wxMask
*mask
= new wxMask();
1471 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1473 bitmap
.SetMask( mask
);
1478 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1479 byte_order b_o
= RGB
;
1483 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1484 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1485 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1486 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1487 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1488 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1491 int r_mask
= GetMaskRed();
1492 int g_mask
= GetMaskGreen();
1493 int b_mask
= GetMaskBlue();
1495 unsigned char* data
= GetData();
1498 for (int y
= 0; y
< height
; y
++)
1500 for (int x
= 0; x
< width
; x
++)
1502 int r
= data
[index
];
1504 int g
= data
[index
];
1506 int b
= data
[index
];
1511 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1512 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1514 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1522 if (wxTheApp
->m_colorCube
)
1524 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1528 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1529 GdkColor
*colors
= cmap
->colors
;
1530 int max
= 3 * (65536);
1532 for (int i
= 0; i
< cmap
->size
; i
++)
1534 int rdiff
= (r
<< 8) - colors
[i
].red
;
1535 int gdiff
= (g
<< 8) - colors
[i
].green
;
1536 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1537 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1538 if (sum
< max
) { pixel
= i
; max
= sum
; }
1542 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1548 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1549 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1554 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1555 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1564 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1565 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1566 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1567 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1568 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1569 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1571 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1580 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1582 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1584 gdk_image_destroy( data_image
);
1585 gdk_gc_unref( data_gc
);
1591 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1593 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1595 gdk_image_destroy( mask_image
);
1596 gdk_gc_unref( mask_gc
);
1602 wxImage::wxImage( const wxBitmap
&bitmap
)
1604 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1606 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1607 if (bitmap
.GetPixmap())
1609 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1611 bitmap
.GetWidth(), bitmap
.GetHeight() );
1613 if (bitmap
.GetBitmap())
1615 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1617 bitmap
.GetWidth(), bitmap
.GetHeight() );
1620 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1623 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1625 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1626 char unsigned *data
= GetData();
1630 gdk_image_destroy( gdk_image
);
1631 wxFAIL_MSG( wxT("couldn't create image") );
1635 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1636 if (bitmap
.GetMask())
1638 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1640 bitmap
.GetWidth(), bitmap
.GetHeight() );
1642 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1646 int red_shift_right
= 0;
1647 int green_shift_right
= 0;
1648 int blue_shift_right
= 0;
1649 int red_shift_left
= 0;
1650 int green_shift_left
= 0;
1651 int blue_shift_left
= 0;
1652 bool use_shift
= FALSE
;
1654 if (bitmap
.GetPixmap())
1656 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1658 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1659 bpp
= visual
->depth
;
1660 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1661 red_shift_right
= visual
->red_shift
;
1662 red_shift_left
= 8-visual
->red_prec
;
1663 green_shift_right
= visual
->green_shift
;
1664 green_shift_left
= 8-visual
->green_prec
;
1665 blue_shift_right
= visual
->blue_shift
;
1666 blue_shift_left
= 8-visual
->blue_prec
;
1668 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
1670 if (bitmap
.GetBitmap())
1676 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1679 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1681 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1683 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1701 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
1702 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
1703 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
1705 else if (cmap
->colors
)
1707 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1708 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1709 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1713 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1718 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1719 if (mask_pixel
== 0)
1731 gdk_image_destroy( gdk_image
);
1732 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1737 //-----------------------------------------------------------------------------
1738 // Motif conversion routines
1739 //-----------------------------------------------------------------------------
1743 #pragma message disable nosimpint
1747 #pragma message enable nosimpint
1749 #include "wx/utils.h"
1754 Date: Wed, 05 Jan 2000 11:45:40 +0100
1755 From: Frits Boel <boel@niob.knaw.nl>
1756 To: julian.smart@ukonline.co.uk
1757 Subject: Patch for Motif ConvertToBitmap
1761 I've been working on a wxWin application for image processing. From the
1762 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1763 till I looked in the source code of image.cpp. I saw that converting a
1764 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1765 to the 256 colors of the palet. A very time-consuming piece of code!
1767 Because I wanted a faster application, I've made a 'patch' for this. In
1768 short: every pixel of the image is compared to a sorted list with
1769 colors. If the color is found in the list, the palette entry is
1770 returned; if the color is not found, the color palette is searched and
1771 then the palette entry is returned and the color added to the sorted
1774 Maybe there is another method for this, namely changing the palette
1775 itself (if the colors are known, as is the case with tiffs with a
1776 colormap). I did not look at this, maybe someone else did?
1778 The code of the patch is attached, have a look on it, and maybe you will
1779 ship it with the next release of wxMotif?
1784 Software engineer at Hubrecht Laboratory, The Netherlands.
1791 wxSearchColor( void );
1792 wxSearchColor( int size
, XColor
*colors
);
1793 ~wxSearchColor( void );
1795 int SearchColor( int r
, int g
, int b
);
1797 int AddColor( unsigned int value
, int pos
);
1801 unsigned int *color
;
1808 wxSearchColor::wxSearchColor( void )
1811 colors
= (XColor
*) NULL
;
1812 color
= (unsigned int *) NULL
;
1813 entry
= (int*) NULL
;
1819 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
1824 color
= new unsigned int[size
];
1825 entry
= new int [size
];
1827 for (i
= 0; i
< size
; i
++ ) {
1831 bottom
= top
= ( size
>> 1 );
1834 wxSearchColor::~wxSearchColor( void )
1836 if ( color
) delete color
;
1837 if ( entry
) delete entry
;
1840 int wxSearchColor::SearchColor( int r
, int g
, int b
)
1842 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
1847 while ( begin
<= end
) {
1849 middle
= ( begin
+ end
) >> 1;
1851 if ( value
== color
[middle
] ) {
1852 return( entry
[middle
] );
1853 } else if ( value
< color
[middle
] ) {
1861 return AddColor( value
, middle
);
1864 int wxSearchColor::AddColor( unsigned int value
, int pos
)
1868 int max
= 3 * (65536);
1869 for ( i
= 0; i
< 256; i
++ ) {
1870 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
1871 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
1872 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
1873 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1874 if (sum
< max
) { pixel
= i
; max
= sum
; }
1877 if ( entry
[pos
] < 0 ) {
1880 } else if ( value
< color
[pos
] ) {
1883 for ( i
= bottom
; i
< pos
; i
++ ) {
1884 color
[i
-1] = color
[i
];
1885 entry
[i
-1] = entry
[i
];
1888 color
[pos
-1] = value
;
1889 entry
[pos
-1] = pixel
;
1890 } else if ( top
< size
-1 ) {
1891 for ( i
= top
; i
>= pos
; i
-- ) {
1892 color
[i
+1] = color
[i
];
1893 entry
[i
+1] = entry
[i
];
1902 if ( top
< size
-1 ) {
1903 for ( i
= top
; i
> pos
; i
-- ) {
1904 color
[i
+1] = color
[i
];
1905 entry
[i
+1] = entry
[i
];
1908 color
[pos
+1] = value
;
1909 entry
[pos
+1] = pixel
;
1910 } else if ( bottom
> 0 ) {
1911 for ( i
= bottom
; i
< pos
; i
++ ) {
1912 color
[i
-1] = color
[i
];
1913 entry
[i
-1] = entry
[i
];
1925 wxBitmap
wxImage::ConvertToBitmap() const
1929 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1931 int width
= GetWidth();
1932 int height
= GetHeight();
1934 bitmap
.SetHeight( height
);
1935 bitmap
.SetWidth( width
);
1937 Display
*dpy
= (Display
*) wxGetDisplay();
1938 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1939 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1943 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1944 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
1946 bitmap
.Create( width
, height
, bpp
);
1950 XImage
*mask_image
= (XImage
*) NULL
;
1953 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1954 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
1957 // Retrieve depth info
1959 XVisualInfo vinfo_template
;
1962 vinfo_template
.visual
= vis
;
1963 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1964 vinfo_template
.depth
= bpp
;
1967 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1969 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
1973 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1974 if (bpp
< 8) bpp
= 8;
1978 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1979 byte_order b_o
= RGB
;
1983 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
1984 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
1985 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
1986 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
1987 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
1988 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
1991 int r_mask
= GetMaskRed();
1992 int g_mask
= GetMaskGreen();
1993 int b_mask
= GetMaskBlue();
1998 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2000 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2001 XQueryColors( dpy
, cmap
, colors
, 256 );
2004 wxSearchColor
scolor( 256, colors
);
2005 unsigned char* data
= GetData();
2007 bool hasMask
= HasMask();
2010 for (int y
= 0; y
< height
; y
++)
2012 for (int x
= 0; x
< width
; x
++)
2014 int r
= data
[index
];
2016 int g
= data
[index
];
2018 int b
= data
[index
];
2023 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2024 XPutPixel( mask_image
, x
, y
, 0 );
2026 XPutPixel( mask_image
, x
, y
, 1 );
2033 #if 0 // Old, slower code
2036 if (wxTheApp->m_colorCube)
2038 pixel = wxTheApp->m_colorCube
2039 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2044 int max
= 3 * (65536);
2045 for (int i
= 0; i
< 256; i
++)
2047 int rdiff
= (r
<< 8) - colors
[i
].red
;
2048 int gdiff
= (g
<< 8) - colors
[i
].green
;
2049 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2050 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2051 if (sum
< max
) { pixel
= i
; max
= sum
; }
2058 // And this is all to get the 'right' color...
2059 int pixel
= scolor
.SearchColor( r
, g
, b
);
2060 XPutPixel( data_image
, x
, y
, pixel
);
2065 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2066 XPutPixel( data_image
, x
, y
, pixel
);
2071 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2072 XPutPixel( data_image
, x
, y
, pixel
);
2081 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2082 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2083 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2084 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2085 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2086 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2088 XPutPixel( data_image
, x
, y
, pixel
);
2098 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2099 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2100 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2102 XDestroyImage( data_image
);
2108 wxBitmap
maskBitmap(width
, height
, 1);
2110 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2111 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2113 XDestroyImage( mask_image
);
2114 XFreeGC( dpy
, gcMask
);
2116 wxMask
* mask
= new wxMask
;
2117 mask
->SetPixmap(maskBitmap
.GetPixmap());
2119 bitmap
.SetMask(mask
);
2121 maskBitmap
.SetPixmapNull();
2127 wxImage::wxImage( const wxBitmap
&bitmap
)
2129 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2131 Display
*dpy
= (Display
*) wxGetDisplay();
2132 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2133 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2135 XImage
*ximage
= XGetImage( dpy
,
2136 (Drawable
)bitmap
.GetPixmap(),
2138 bitmap
.GetWidth(), bitmap
.GetHeight(),
2139 AllPlanes
, ZPixmap
);
2141 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2143 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2144 char unsigned *data
= GetData();
2148 XDestroyImage( ximage
);
2149 wxFAIL_MSG( wxT("couldn't create image") );
2154 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2155 if (bitmap.GetMask())
2157 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2159 bitmap.GetWidth(), bitmap.GetHeight() );
2161 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2165 // Retrieve depth info
2167 XVisualInfo vinfo_template
;
2170 vinfo_template
.visual
= vis
;
2171 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2172 vinfo_template
.depth
= bpp
;
2175 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2177 wxCHECK_RET( vi
, wxT("no visual") );
2179 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2186 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2188 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2189 XQueryColors( dpy
, cmap
, colors
, 256 );
2193 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2195 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2197 int pixel
= XGetPixel( ximage
, i
, j
);
2200 data
[pos
] = colors
[pixel
].red
>> 8;
2201 data
[pos
+1] = colors
[pixel
].green
>> 8;
2202 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2203 } else if (bpp
== 15)
2205 data
[pos
] = (pixel
>> 7) & 0xf8;
2206 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2207 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2208 } else if (bpp
== 16)
2210 data
[pos
] = (pixel
>> 8) & 0xf8;
2211 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2212 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2215 data
[pos
] = (pixel
>> 16) & 0xff;
2216 data
[pos
+1] = (pixel
>> 8) & 0xff;
2217 data
[pos
+2] = pixel
& 0xff;
2223 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2224 if (mask_pixel == 0)
2237 XDestroyImage( ximage
);
2239 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2245 // OS/2 Presentation manager conversion routings
2247 wxBitmap
wxImage::ConvertToBitmap() const
2250 return wxNullBitmap
;
2251 wxBitmap bitmap
; // remove
2254 int sizeLimit = 1024*768*3;
2256 // width and height of the device-dependent bitmap
2257 int width = GetWidth();
2258 int bmpHeight = GetHeight();
2260 // calc the number of bytes per scanline and padding
2261 int bytePerLine = width*3;
2262 int sizeDWORD = sizeof( DWORD );
2263 int lineBoundary = bytePerLine % sizeDWORD;
2265 if( lineBoundary > 0 )
2267 padding = sizeDWORD - lineBoundary;
2268 bytePerLine += padding;
2270 // calc the number of DIBs and heights of DIBs
2273 int height = sizeLimit/bytePerLine;
2274 if( height >= bmpHeight )
2278 numDIB = bmpHeight / height;
2279 hRemain = bmpHeight % height;
2280 if( hRemain >0 ) numDIB++;
2283 // set bitmap parameters
2285 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2286 bitmap.SetWidth( width );
2287 bitmap.SetHeight( bmpHeight );
2288 bitmap.SetDepth( wxDisplayDepth() );
2290 // create a DIB header
2291 int headersize = sizeof(BITMAPINFOHEADER);
2292 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2293 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2294 // Fill in the DIB header
2295 lpDIBh->bmiHeader.biSize = headersize;
2296 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2297 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2298 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2299 // the general formula for biSizeImage:
2300 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2301 lpDIBh->bmiHeader.biPlanes = 1;
2302 lpDIBh->bmiHeader.biBitCount = 24;
2303 lpDIBh->bmiHeader.biCompression = BI_RGB;
2304 lpDIBh->bmiHeader.biClrUsed = 0;
2305 // These seem not really needed for our purpose here.
2306 lpDIBh->bmiHeader.biClrImportant = 0;
2307 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2308 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2309 // memory for DIB data
2310 unsigned char *lpBits;
2311 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2314 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2319 // create and set the device-dependent bitmap
2320 HDC hdc = ::GetDC(NULL);
2321 HDC memdc = ::CreateCompatibleDC( hdc );
2323 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2324 ::SelectObject( memdc, hbitmap);
2326 // copy image data into DIB data and then into DDB (in a loop)
2327 unsigned char *data = GetData();
2330 unsigned char *ptdata = data;
2331 unsigned char *ptbits;
2333 for( n=0; n<numDIB; n++ )
2335 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2337 // redefine height and size of the (possibly) last smaller DIB
2338 // memory is not reallocated
2340 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2341 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2345 for( j=0; j<height; j++ )
2347 for( i=0; i<width; i++ )
2349 *(ptbits++) = *(ptdata+2);
2350 *(ptbits++) = *(ptdata+1);
2351 *(ptbits++) = *(ptdata );
2354 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2356 ::StretchDIBits( memdc, 0, origin, width, height,\
2357 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2359 // if numDIB = 1, lines below can also be used
2360 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2361 // The above line is equivalent to the following two lines.
2362 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2363 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2364 // or the following lines
2365 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2366 // HDC memdc = ::CreateCompatibleDC( hdc );
2367 // ::SelectObject( memdc, hbitmap);
2368 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2369 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2370 // ::SelectObject( memdc, 0 );
2371 // ::DeleteDC( memdc );
2373 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2375 // similarly, created an mono-bitmap for the possible mask
2378 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2379 ::SelectObject( memdc, hbitmap);
2380 if( numDIB == 1 ) height = bmpHeight;
2381 else height = sizeLimit/bytePerLine;
2382 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2383 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2385 unsigned char r = GetMaskRed();
2386 unsigned char g = GetMaskGreen();
2387 unsigned char b = GetMaskBlue();
2388 unsigned char zero = 0, one = 255;
2390 for( n=0; n<numDIB; n++ )
2392 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2394 // redefine height and size of the (possibly) last smaller DIB
2395 // memory is not reallocated
2397 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2398 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2401 for( int j=0; j<height; j++ )
2403 for(i=0; i<width; i++ )
2405 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2418 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2420 ::StretchDIBits( memdc, 0, origin, width, height,\
2421 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2424 // create a wxMask object
2425 wxMask *mask = new wxMask();
2426 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2427 bitmap.SetMask( mask );
2430 // free allocated resources
2431 ::SelectObject( memdc, 0 );
2432 ::DeleteDC( memdc );
2433 ::ReleaseDC(NULL, hdc);
2437 // check the wxBitmap object
2438 if( bitmap.GetHBITMAP() )
2439 bitmap.SetOk( TRUE );
2441 bitmap.SetOk( FALSE );
2446 wxImage::wxImage( const wxBitmap
&bitmap
)
2451 wxFAIL_MSG( wxT("invalid bitmap") );
2455 // create an wxImage object
2456 int width
= bitmap
.GetWidth();
2457 int height
= bitmap
.GetHeight();
2458 Create( width
, height
);
2459 unsigned char *data
= GetData();
2462 wxFAIL_MSG( wxT("could not allocate data for image") );
2466 // calc the number of bytes per scanline and padding in the DIB
2467 int bytePerLine
= width
*3;
2468 int sizeDWORD
= sizeof( DWORD
);
2469 int lineBoundary
= bytePerLine
% sizeDWORD
;
2471 if( lineBoundary
> 0 )
2473 padding
= sizeDWORD
- lineBoundary
;
2474 bytePerLine
+= padding
;
2478 // create a DIB header
2479 int headersize = sizeof(BITMAPINFOHEADER);
2480 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2483 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2487 // Fill in the DIB header
2488 lpDIBh->bmiHeader.biSize = headersize;
2489 lpDIBh->bmiHeader.biWidth = width;
2490 lpDIBh->bmiHeader.biHeight = -height;
2491 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2492 lpDIBh->bmiHeader.biPlanes = 1;
2493 lpDIBh->bmiHeader.biBitCount = 24;
2494 lpDIBh->bmiHeader.biCompression = BI_RGB;
2495 lpDIBh->bmiHeader.biClrUsed = 0;
2496 // These seem not really needed for our purpose here.
2497 lpDIBh->bmiHeader.biClrImportant = 0;
2498 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2499 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2500 // memory for DIB data
2501 unsigned char *lpBits;
2502 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2505 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2511 // copy data from the device-dependent bitmap to the DIB
2512 HDC hdc = ::GetDC(NULL);
2514 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2515 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2517 // copy DIB data into the wxImage object
2519 unsigned char *ptdata = data;
2520 unsigned char *ptbits = lpBits;
2521 for( i=0; i<height; i++ )
2523 for( j=0; j<width; j++ )
2525 *(ptdata++) = *(ptbits+2);
2526 *(ptdata++) = *(ptbits+1);
2527 *(ptdata++) = *(ptbits );
2533 // similarly, set data according to the possible mask bitmap
2534 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2536 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2537 // memory DC created, color set, data copied, and memory DC deleted
2538 HDC memdc = ::CreateCompatibleDC( hdc );
2539 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2540 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2541 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2542 ::DeleteDC( memdc );
2543 // background color set to RGB(16,16,16) in consistent with wxGTK
2544 unsigned char r=16, g=16, b=16;
2547 for( i=0; i<height; i++ )
2549 for( j=0; j<width; j++ )
2563 SetMaskColour( r, g, b );
2570 // free allocated resources
2571 ::ReleaseDC(NULL, hdc);
2579 // A module to allow wxImage initialization/cleanup
2580 // without calling these functions from app.cpp or from
2581 // the user's application.
2583 class wxImageModule
: public wxModule
2585 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2588 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2589 void OnExit() { wxImage::CleanUpHandlers(); };
2592 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2595 //-----------------------------------------------------------------------------
2598 // Counts and returns the number of different colours. Optionally stops
2599 // when it exceeds 'stopafter' different colours. This is useful, for
2600 // example, to see if the image can be saved as 8-bit (256 colour or
2601 // less, in this case it would be invoked as CountColours(256)). Default
2602 // value for stopafter is -1 (don't care).
2604 unsigned long wxImage::CountColours( unsigned long stopafter
)
2608 unsigned char r
, g
, b
, *p
;
2609 unsigned long size
, nentries
, key
;
2612 size
= GetWidth() * GetHeight();
2615 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2620 key
= (r
<< 16) | (g
<< 8) | b
;
2622 if (h
.Get(key
) == NULL
)
2634 // Computes the histogram of the image and fills a hash table, indexed
2635 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2636 // wxHNode contains an 'index' (useful to build a palette with the image
2637 // colours) and a 'value', which is the number of pixels in the image with
2640 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2642 unsigned char r
, g
, b
, *p
;
2643 unsigned long size
, nentries
, key
;
2647 size
= GetWidth() * GetHeight();
2650 for (unsigned long j
= 0; j
< size
; j
++)
2655 key
= (r
<< 16) | (g
<< 8) | b
;
2657 hnode
= (wxHNode
*) h
.Get(key
);
2663 hnode
= new wxHNode();
2664 hnode
->index
= nentries
++;
2667 h
.Put(key
, (wxObject
*)hnode
);
2675 * Rotation code by Carlos Moreno
2678 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2679 // does exactly the same thing. And I also got rid of wxRotationPixel
2680 // bacause of potential problems in architectures where alignment
2681 // is an issue, so I had to rewrite parts of the code.
2683 static const double gs_Epsilon
= 1e-10;
2685 static inline int wxCint (double x
)
2687 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
2691 // Auxiliary function to rotate a point (x,y) with respect to point p0
2692 // make it inline and use a straight return to facilitate optimization
2693 // also, the function receives the sine and cosine of the angle to avoid
2694 // repeating the time-consuming calls to these functions -- sin/cos can
2695 // be computed and stored in the calling function.
2697 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2699 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
2700 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
2703 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2705 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
2708 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
2711 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
2713 // Create pointer-based array to accelerate access to wxImage's data
2714 unsigned char ** data
= new unsigned char * [GetHeight()];
2716 data
[0] = GetData();
2718 for (i
= 1; i
< GetHeight(); i
++)
2719 data
[i
] = data
[i
- 1] + (3 * GetWidth());
2721 // precompute coefficients for rotation formula
2722 // (sine and cosine of the angle)
2723 const double cos_angle
= cos(angle
);
2724 const double sin_angle
= sin(angle
);
2726 // Create new Image to store the result
2727 // First, find rectangle that covers the rotated image; to do that,
2728 // rotate the four corners
2730 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
2732 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
2733 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
2734 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
2735 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
2737 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
2738 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
2739 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
2740 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
2742 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
2744 if (offset_after_rotation
!= NULL
)
2746 *offset_after_rotation
= wxPoint (x1
, y1
);
2749 // GRG: The rotated (destination) image is always accessed
2750 // sequentially, so there is no need for a pointer-based
2751 // array here (and in fact it would be slower).
2753 unsigned char * dst
= rotated
.GetData();
2755 // GRG: if the original image has a mask, use its RGB values
2756 // as the blank pixel, else, fall back to default (black).
2758 unsigned char blank_r
= 0;
2759 unsigned char blank_g
= 0;
2760 unsigned char blank_b
= 0;
2764 blank_r
= GetMaskRed();
2765 blank_g
= GetMaskGreen();
2766 blank_b
= GetMaskBlue();
2767 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
2770 // Now, for each point of the rotated image, find where it came from, by
2771 // performing an inverse rotation (a rotation of -angle) and getting the
2772 // pixel at those coordinates
2774 // GRG: I've taken the (interpolating) test out of the loops, so that
2775 // it is done only once, instead of repeating it for each pixel.
2780 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
2782 for (x
= 0; x
< rotated
.GetWidth(); x
++)
2784 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
2786 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
2787 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
2789 // interpolate using the 4 enclosing grid-points. Those
2790 // points can be obtained using floor and ceiling of the
2791 // exact coordinates of the point
2792 // C.M. 2000-02-17: when the point is near the border, special care is required.
2796 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
2798 x1
= wxCint(floor(src
.x
));
2799 x2
= wxCint(ceil(src
.x
));
2801 else // else means that x is near one of the borders (0 or width-1)
2803 x1
= x2
= wxCint (src
.x
);
2806 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
2808 y1
= wxCint(floor(src
.y
));
2809 y2
= wxCint(ceil(src
.y
));
2813 y1
= y2
= wxCint (src
.y
);
2816 // get four points and the distances (square of the distance,
2817 // for efficiency reasons) for the interpolation formula
2819 // GRG: Do not calculate the points until they are
2820 // really needed -- this way we can calculate
2821 // just one, instead of four, if d1, d2, d3
2822 // or d4 are < gs_Epsilon
2824 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
2825 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
2826 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
2827 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
2829 // Now interpolate as a weighted average of the four surrounding
2830 // points, where the weights are the distances to each of those points
2832 // If the point is exactly at one point of the grid of the source
2833 // image, then don't interpolate -- just assign the pixel
2835 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
2837 unsigned char *p
= data
[y1
] + (3 * x1
);
2842 else if (d2
< gs_Epsilon
)
2844 unsigned char *p
= data
[y1
] + (3 * x2
);
2849 else if (d3
< gs_Epsilon
)
2851 unsigned char *p
= data
[y2
] + (3 * x2
);
2856 else if (d4
< gs_Epsilon
)
2858 unsigned char *p
= data
[y2
] + (3 * x1
);
2865 // weights for the weighted average are proportional to the inverse of the distance
2866 unsigned char *v1
= data
[y1
] + (3 * x1
);
2867 unsigned char *v2
= data
[y1
] + (3 * x2
);
2868 unsigned char *v3
= data
[y2
] + (3 * x2
);
2869 unsigned char *v4
= data
[y2
] + (3 * x1
);
2871 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
2875 *(dst
++) = (unsigned char)
2876 ( (w1
* *(v1
++) + w2
* *(v2
++) +
2877 w3
* *(v3
++) + w4
* *(v4
++)) /
2878 (w1
+ w2
+ w3
+ w4
) );
2879 *(dst
++) = (unsigned char)
2880 ( (w1
* *(v1
++) + w2
* *(v2
++) +
2881 w3
* *(v3
++) + w4
* *(v4
++)) /
2882 (w1
+ w2
+ w3
+ w4
) );
2883 *(dst
++) = (unsigned char)
2884 ( (w1
* *(v1
++) + w2
* *(v2
++) +
2885 w3
* *(v3
++) + w4
* *(v4
++)) /
2886 (w1
+ w2
+ w3
+ w4
) );
2898 else // not interpolating
2900 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
2902 for (x
= 0; x
< rotated
.GetWidth(); x
++)
2904 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
2906 const int xs
= wxCint (src
.x
); // wxCint rounds to the
2907 const int ys
= wxCint (src
.y
); // closest integer
2909 if (0 <= xs
&& xs
< GetWidth() &&
2910 0 <= ys
&& ys
< GetHeight())
2912 unsigned char *p
= data
[ys
] + (3 * xs
);