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
);
1951 GdkImage *mask_image = (GdkImage*) NULL;
1955 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1957 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1959 wxMask *mask = new wxMask();
1960 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1962 bitmap.SetMask( mask );
1966 // Retrieve depth info
1968 XVisualInfo vinfo_template
;
1971 vinfo_template
.visual
= vis
;
1972 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1973 vinfo_template
.depth
= bpp
;
1976 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1978 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
1982 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1983 if (bpp
< 8) bpp
= 8;
1987 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1988 byte_order b_o
= RGB
;
1992 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
1993 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
1994 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
1995 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
1996 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
1997 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2001 int r_mask = GetMaskRed();
2002 int g_mask = GetMaskGreen();
2003 int b_mask = GetMaskBlue();
2009 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2011 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2012 XQueryColors( dpy
, cmap
, colors
, 256 );
2015 wxSearchColor
scolor( 256, colors
);
2016 unsigned char* data
= GetData();
2019 for (int y
= 0; y
< height
; y
++)
2021 for (int x
= 0; x
< width
; x
++)
2023 int r
= data
[index
];
2025 int g
= data
[index
];
2027 int b
= data
[index
];
2033 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2034 gdk_image_put_pixel( mask_image, x, y, 1 );
2036 gdk_image_put_pixel( mask_image, x, y, 0 );
2044 #if 0 // Old, slower code
2047 if (wxTheApp->m_colorCube)
2049 pixel = wxTheApp->m_colorCube
2050 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2055 int max
= 3 * (65536);
2056 for (int i
= 0; i
< 256; i
++)
2058 int rdiff
= (r
<< 8) - colors
[i
].red
;
2059 int gdiff
= (g
<< 8) - colors
[i
].green
;
2060 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2061 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2062 if (sum
< max
) { pixel
= i
; max
= sum
; }
2069 // And this is all to get the 'right' color...
2070 int pixel
= scolor
.SearchColor( r
, g
, b
);
2071 XPutPixel( data_image
, x
, y
, pixel
);
2076 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2077 XPutPixel( data_image
, x
, y
, pixel
);
2082 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2083 XPutPixel( data_image
, x
, y
, pixel
);
2092 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2093 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2094 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2095 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2096 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2097 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2099 XPutPixel( data_image
, x
, y
, pixel
);
2109 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2110 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2111 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2113 XDestroyImage( data_image
);
2121 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
2123 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
2125 gdk_image_destroy( mask_image );
2126 gdk_gc_unref( mask_gc );
2133 wxImage::wxImage( const wxBitmap
&bitmap
)
2135 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2137 Display
*dpy
= (Display
*) wxGetDisplay();
2138 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2139 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2141 XImage
*ximage
= XGetImage( dpy
,
2142 (Drawable
)bitmap
.GetPixmap(),
2144 bitmap
.GetWidth(), bitmap
.GetHeight(),
2145 AllPlanes
, ZPixmap
);
2147 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2149 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2150 char unsigned *data
= GetData();
2154 XDestroyImage( ximage
);
2155 wxFAIL_MSG( wxT("couldn't create image") );
2160 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2161 if (bitmap.GetMask())
2163 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2165 bitmap.GetWidth(), bitmap.GetHeight() );
2167 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2171 // Retrieve depth info
2173 XVisualInfo vinfo_template
;
2176 vinfo_template
.visual
= vis
;
2177 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2178 vinfo_template
.depth
= bpp
;
2181 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2183 wxCHECK_RET( vi
, wxT("no visual") );
2185 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2192 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2194 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2195 XQueryColors( dpy
, cmap
, colors
, 256 );
2199 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2201 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2203 int pixel
= XGetPixel( ximage
, i
, j
);
2206 data
[pos
] = colors
[pixel
].red
>> 8;
2207 data
[pos
+1] = colors
[pixel
].green
>> 8;
2208 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2209 } else if (bpp
== 15)
2211 data
[pos
] = (pixel
>> 7) & 0xf8;
2212 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2213 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2214 } else if (bpp
== 16)
2216 data
[pos
] = (pixel
>> 8) & 0xf8;
2217 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2218 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2221 data
[pos
] = (pixel
>> 16) & 0xff;
2222 data
[pos
+1] = (pixel
>> 8) & 0xff;
2223 data
[pos
+2] = pixel
& 0xff;
2229 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2230 if (mask_pixel == 0)
2243 XDestroyImage( ximage
);
2245 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2251 // OS/2 Presentation manager conversion routings
2253 wxBitmap
wxImage::ConvertToBitmap() const
2256 return wxNullBitmap
;
2257 wxBitmap bitmap
; // remove
2260 int sizeLimit = 1024*768*3;
2262 // width and height of the device-dependent bitmap
2263 int width = GetWidth();
2264 int bmpHeight = GetHeight();
2266 // calc the number of bytes per scanline and padding
2267 int bytePerLine = width*3;
2268 int sizeDWORD = sizeof( DWORD );
2269 int lineBoundary = bytePerLine % sizeDWORD;
2271 if( lineBoundary > 0 )
2273 padding = sizeDWORD - lineBoundary;
2274 bytePerLine += padding;
2276 // calc the number of DIBs and heights of DIBs
2279 int height = sizeLimit/bytePerLine;
2280 if( height >= bmpHeight )
2284 numDIB = bmpHeight / height;
2285 hRemain = bmpHeight % height;
2286 if( hRemain >0 ) numDIB++;
2289 // set bitmap parameters
2291 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2292 bitmap.SetWidth( width );
2293 bitmap.SetHeight( bmpHeight );
2294 bitmap.SetDepth( wxDisplayDepth() );
2296 // create a DIB header
2297 int headersize = sizeof(BITMAPINFOHEADER);
2298 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2299 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2300 // Fill in the DIB header
2301 lpDIBh->bmiHeader.biSize = headersize;
2302 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2303 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2304 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2305 // the general formula for biSizeImage:
2306 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2307 lpDIBh->bmiHeader.biPlanes = 1;
2308 lpDIBh->bmiHeader.biBitCount = 24;
2309 lpDIBh->bmiHeader.biCompression = BI_RGB;
2310 lpDIBh->bmiHeader.biClrUsed = 0;
2311 // These seem not really needed for our purpose here.
2312 lpDIBh->bmiHeader.biClrImportant = 0;
2313 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2314 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2315 // memory for DIB data
2316 unsigned char *lpBits;
2317 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2320 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2325 // create and set the device-dependent bitmap
2326 HDC hdc = ::GetDC(NULL);
2327 HDC memdc = ::CreateCompatibleDC( hdc );
2329 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2330 ::SelectObject( memdc, hbitmap);
2332 // copy image data into DIB data and then into DDB (in a loop)
2333 unsigned char *data = GetData();
2336 unsigned char *ptdata = data;
2337 unsigned char *ptbits;
2339 for( n=0; n<numDIB; n++ )
2341 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2343 // redefine height and size of the (possibly) last smaller DIB
2344 // memory is not reallocated
2346 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2347 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2351 for( j=0; j<height; j++ )
2353 for( i=0; i<width; i++ )
2355 *(ptbits++) = *(ptdata+2);
2356 *(ptbits++) = *(ptdata+1);
2357 *(ptbits++) = *(ptdata );
2360 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2362 ::StretchDIBits( memdc, 0, origin, width, height,\
2363 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2365 // if numDIB = 1, lines below can also be used
2366 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2367 // The above line is equivalent to the following two lines.
2368 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2369 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2370 // or the following lines
2371 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2372 // HDC memdc = ::CreateCompatibleDC( hdc );
2373 // ::SelectObject( memdc, hbitmap);
2374 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2375 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2376 // ::SelectObject( memdc, 0 );
2377 // ::DeleteDC( memdc );
2379 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2381 // similarly, created an mono-bitmap for the possible mask
2384 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2385 ::SelectObject( memdc, hbitmap);
2386 if( numDIB == 1 ) height = bmpHeight;
2387 else height = sizeLimit/bytePerLine;
2388 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2389 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2391 unsigned char r = GetMaskRed();
2392 unsigned char g = GetMaskGreen();
2393 unsigned char b = GetMaskBlue();
2394 unsigned char zero = 0, one = 255;
2396 for( n=0; n<numDIB; n++ )
2398 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2400 // redefine height and size of the (possibly) last smaller DIB
2401 // memory is not reallocated
2403 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2404 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2407 for( int j=0; j<height; j++ )
2409 for(i=0; i<width; i++ )
2411 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2424 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2426 ::StretchDIBits( memdc, 0, origin, width, height,\
2427 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2430 // create a wxMask object
2431 wxMask *mask = new wxMask();
2432 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2433 bitmap.SetMask( mask );
2436 // free allocated resources
2437 ::SelectObject( memdc, 0 );
2438 ::DeleteDC( memdc );
2439 ::ReleaseDC(NULL, hdc);
2443 // check the wxBitmap object
2444 if( bitmap.GetHBITMAP() )
2445 bitmap.SetOk( TRUE );
2447 bitmap.SetOk( FALSE );
2452 wxImage::wxImage( const wxBitmap
&bitmap
)
2457 wxFAIL_MSG( wxT("invalid bitmap") );
2461 // create an wxImage object
2462 int width
= bitmap
.GetWidth();
2463 int height
= bitmap
.GetHeight();
2464 Create( width
, height
);
2465 unsigned char *data
= GetData();
2468 wxFAIL_MSG( wxT("could not allocate data for image") );
2472 // calc the number of bytes per scanline and padding in the DIB
2473 int bytePerLine
= width
*3;
2474 int sizeDWORD
= sizeof( DWORD
);
2475 int lineBoundary
= bytePerLine
% sizeDWORD
;
2477 if( lineBoundary
> 0 )
2479 padding
= sizeDWORD
- lineBoundary
;
2480 bytePerLine
+= padding
;
2484 // create a DIB header
2485 int headersize = sizeof(BITMAPINFOHEADER);
2486 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2489 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2493 // Fill in the DIB header
2494 lpDIBh->bmiHeader.biSize = headersize;
2495 lpDIBh->bmiHeader.biWidth = width;
2496 lpDIBh->bmiHeader.biHeight = -height;
2497 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2498 lpDIBh->bmiHeader.biPlanes = 1;
2499 lpDIBh->bmiHeader.biBitCount = 24;
2500 lpDIBh->bmiHeader.biCompression = BI_RGB;
2501 lpDIBh->bmiHeader.biClrUsed = 0;
2502 // These seem not really needed for our purpose here.
2503 lpDIBh->bmiHeader.biClrImportant = 0;
2504 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2505 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2506 // memory for DIB data
2507 unsigned char *lpBits;
2508 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2511 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2517 // copy data from the device-dependent bitmap to the DIB
2518 HDC hdc = ::GetDC(NULL);
2520 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2521 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2523 // copy DIB data into the wxImage object
2525 unsigned char *ptdata = data;
2526 unsigned char *ptbits = lpBits;
2527 for( i=0; i<height; i++ )
2529 for( j=0; j<width; j++ )
2531 *(ptdata++) = *(ptbits+2);
2532 *(ptdata++) = *(ptbits+1);
2533 *(ptdata++) = *(ptbits );
2539 // similarly, set data according to the possible mask bitmap
2540 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2542 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2543 // memory DC created, color set, data copied, and memory DC deleted
2544 HDC memdc = ::CreateCompatibleDC( hdc );
2545 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2546 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2547 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2548 ::DeleteDC( memdc );
2549 // background color set to RGB(16,16,16) in consistent with wxGTK
2550 unsigned char r=16, g=16, b=16;
2553 for( i=0; i<height; i++ )
2555 for( j=0; j<width; j++ )
2569 SetMaskColour( r, g, b );
2576 // free allocated resources
2577 ::ReleaseDC(NULL, hdc);
2585 // A module to allow wxImage initialization/cleanup
2586 // without calling these functions from app.cpp or from
2587 // the user's application.
2589 class wxImageModule
: public wxModule
2591 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2594 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2595 void OnExit() { wxImage::CleanUpHandlers(); };
2598 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2601 //-----------------------------------------------------------------------------
2604 // Counts and returns the number of different colours. Optionally stops
2605 // when it exceeds 'stopafter' different colours. This is useful, for
2606 // example, to see if the image can be saved as 8-bit (256 colour or
2607 // less, in this case it would be invoked as CountColours(256)). Default
2608 // value for stopafter is -1 (don't care).
2610 unsigned long wxImage::CountColours( unsigned long stopafter
)
2614 unsigned char r
, g
, b
, *p
;
2615 unsigned long size
, nentries
, key
;
2618 size
= GetWidth() * GetHeight();
2621 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2626 key
= (r
<< 16) | (g
<< 8) | b
;
2628 if (h
.Get(key
) == NULL
)
2640 // Computes the histogram of the image and fills a hash table, indexed
2641 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2642 // wxHNode contains an 'index' (useful to build a palette with the image
2643 // colours) and a 'value', which is the number of pixels in the image with
2646 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2648 unsigned char r
, g
, b
, *p
;
2649 unsigned long size
, nentries
, key
;
2653 size
= GetWidth() * GetHeight();
2656 for (unsigned long j
= 0; j
< size
; j
++)
2661 key
= (r
<< 16) | (g
<< 8) | b
;
2663 hnode
= (wxHNode
*) h
.Get(key
);
2669 hnode
= new wxHNode();
2670 hnode
->index
= nentries
++;
2673 h
.Put(key
, (wxObject
*)hnode
);
2681 * Rotation code by Carlos Moreno
2684 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2685 // does exactly the same thing. And I also got rid of wxRotationPixel
2686 // bacause of potential problems in architectures where alignment
2687 // is an issue, so I had to rewrite parts of the code.
2689 static const double gs_Epsilon
= 1e-10;
2691 static inline int wxCint (double x
)
2693 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
2697 // Auxiliary function to rotate a point (x,y) with respect to point p0
2698 // make it inline and use a straight return to facilitate optimization
2699 // also, the function receives the sine and cosine of the angle to avoid
2700 // repeating the time-consuming calls to these functions -- sin/cos can
2701 // be computed and stored in the calling function.
2703 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2705 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
2706 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
2709 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2711 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
2714 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
2717 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
2719 // Create pointer-based array to accelerate access to wxImage's data
2720 unsigned char ** data
= new unsigned char * [GetHeight()];
2722 data
[0] = GetData();
2724 for (i
= 1; i
< GetHeight(); i
++)
2725 data
[i
] = data
[i
- 1] + (3 * GetWidth());
2727 // precompute coefficients for rotation formula
2728 // (sine and cosine of the angle)
2729 const double cos_angle
= cos(angle
);
2730 const double sin_angle
= sin(angle
);
2732 // Create new Image to store the result
2733 // First, find rectangle that covers the rotated image; to do that,
2734 // rotate the four corners
2736 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
2738 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
2739 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
2740 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
2741 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
2743 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
2744 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
2745 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
2746 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
2748 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
2750 if (offset_after_rotation
!= NULL
)
2752 *offset_after_rotation
= wxPoint (x1
, y1
);
2755 // GRG: The rotated (destination) image is always accessed
2756 // sequentially, so there is no need for a pointer-based
2757 // array here (and in fact it would be slower).
2759 unsigned char * dst
= rotated
.GetData();
2761 // GRG: if the original image has a mask, use its RGB values
2762 // as the blank pixel, else, fall back to default (black).
2764 unsigned char blank_r
= 0;
2765 unsigned char blank_g
= 0;
2766 unsigned char blank_b
= 0;
2770 blank_r
= GetMaskRed();
2771 blank_g
= GetMaskGreen();
2772 blank_b
= GetMaskBlue();
2773 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
2776 // Now, for each point of the rotated image, find where it came from, by
2777 // performing an inverse rotation (a rotation of -angle) and getting the
2778 // pixel at those coordinates
2780 // GRG: I've taken the (interpolating) test out of the loops, so that
2781 // it is done only once, instead of repeating it for each pixel.
2786 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
2788 for (x
= 0; x
< rotated
.GetWidth(); x
++)
2790 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
2792 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
2793 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
2795 // interpolate using the 4 enclosing grid-points. Those
2796 // points can be obtained using floor and ceiling of the
2797 // exact coordinates of the point
2798 // C.M. 2000-02-17: when the point is near the border, special care is required.
2802 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
2804 x1
= wxCint(floor(src
.x
));
2805 x2
= wxCint(ceil(src
.x
));
2807 else // else means that x is near one of the borders (0 or width-1)
2809 x1
= x2
= wxCint (src
.x
);
2812 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
2814 y1
= wxCint(floor(src
.y
));
2815 y2
= wxCint(ceil(src
.y
));
2819 y1
= y2
= wxCint (src
.y
);
2822 // get four points and the distances (square of the distance,
2823 // for efficiency reasons) for the interpolation formula
2825 // GRG: Do not calculate the points until they are
2826 // really needed -- this way we can calculate
2827 // just one, instead of four, if d1, d2, d3
2828 // or d4 are < gs_Epsilon
2830 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
2831 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
2832 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
2833 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
2835 // Now interpolate as a weighted average of the four surrounding
2836 // points, where the weights are the distances to each of those points
2838 // If the point is exactly at one point of the grid of the source
2839 // image, then don't interpolate -- just assign the pixel
2841 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
2843 unsigned char *p
= data
[y1
] + (3 * x1
);
2848 else if (d2
< gs_Epsilon
)
2850 unsigned char *p
= data
[y1
] + (3 * x2
);
2855 else if (d3
< gs_Epsilon
)
2857 unsigned char *p
= data
[y2
] + (3 * x2
);
2862 else if (d4
< gs_Epsilon
)
2864 unsigned char *p
= data
[y2
] + (3 * x1
);
2871 // weights for the weighted average are proportional to the inverse of the distance
2872 unsigned char *v1
= data
[y1
] + (3 * x1
);
2873 unsigned char *v2
= data
[y1
] + (3 * x2
);
2874 unsigned char *v3
= data
[y2
] + (3 * x2
);
2875 unsigned char *v4
= data
[y2
] + (3 * x1
);
2877 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
2881 *(dst
++) = (unsigned char)
2882 ( (w1
* *(v1
++) + w2
* *(v2
++) +
2883 w3
* *(v3
++) + w4
* *(v4
++)) /
2884 (w1
+ w2
+ w3
+ w4
) );
2885 *(dst
++) = (unsigned char)
2886 ( (w1
* *(v1
++) + w2
* *(v2
++) +
2887 w3
* *(v3
++) + w4
* *(v4
++)) /
2888 (w1
+ w2
+ w3
+ w4
) );
2889 *(dst
++) = (unsigned char)
2890 ( (w1
* *(v1
++) + w2
* *(v2
++) +
2891 w3
* *(v3
++) + w4
* *(v4
++)) /
2892 (w1
+ w2
+ w3
+ w4
) );
2904 else // not interpolating
2906 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
2908 for (x
= 0; x
< rotated
.GetWidth(); x
++)
2910 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
2912 const int xs
= wxCint (src
.x
); // wxCint rounds to the
2913 const int ys
= wxCint (src
.y
); // closest integer
2915 if (0 <= xs
&& xs
< GetWidth() &&
2916 0 <= ys
&& ys
< GetHeight())
2918 unsigned char *p
= data
[ys
] + (3 * xs
);