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
)
130 m_refData
= new wxImageRefData();
132 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
133 if (M_IMGDATA
->m_data
)
135 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
137 M_IMGDATA
->m_width
= width
;
138 M_IMGDATA
->m_height
= height
;
139 M_IMGDATA
->m_ok
= TRUE
;
147 void wxImage::Destroy()
152 wxImage
wxImage::Scale( int width
, int height
) const
156 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
158 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, wxT("invalid image size") );
160 image
.Create( width
, height
);
162 char unsigned *data
= image
.GetData();
164 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
166 if (M_IMGDATA
->m_hasMask
)
167 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
169 long old_height
= M_IMGDATA
->m_height
;
170 long old_width
= M_IMGDATA
->m_width
;
172 char unsigned *source_data
= M_IMGDATA
->m_data
;
173 char unsigned *target_data
= data
;
175 for (long j
= 0; j
< height
; j
++)
177 long y_offset
= (j
* old_height
/ height
) * old_width
;
179 for (long i
= 0; i
< width
; i
++)
182 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
191 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
195 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
197 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()),
198 image
, wxT("invalid subimage size") );
200 int subwidth
=rect
.GetWidth();
201 const int subheight
=rect
.GetHeight();
203 image
.Create( subwidth
, subheight
);
205 char unsigned *subdata
= image
.GetData(), *data
=GetData();
207 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
209 if (M_IMGDATA
->m_hasMask
)
210 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
212 const int subleft
=3*rect
.GetLeft();
213 const int width
=3*GetWidth();
216 data
+=rect
.GetTop()*width
+subleft
;
218 for (long j
= 0; j
< subheight
; ++j
)
220 memcpy( subdata
, data
, subwidth
);
228 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
229 unsigned char r2
, unsigned char g2
, unsigned char b2
)
231 wxCHECK_RET( Ok(), wxT("invalid image") );
233 char unsigned *data
= GetData();
235 const int w
= GetWidth();
236 const int h
= GetHeight();
238 for (int j
= 0; j
< h
; j
++)
239 for (int i
= 0; i
< w
; i
++)
241 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
251 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
253 wxCHECK_RET( Ok(), wxT("invalid image") );
255 int w
= M_IMGDATA
->m_width
;
256 int h
= M_IMGDATA
->m_height
;
258 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
260 long pos
= (y
* w
+ x
) * 3;
262 M_IMGDATA
->m_data
[ pos
] = r
;
263 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
264 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
267 unsigned char wxImage::GetRed( int x
, int y
)
269 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
271 int w
= M_IMGDATA
->m_width
;
272 int h
= M_IMGDATA
->m_height
;
274 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
276 long pos
= (y
* w
+ x
) * 3;
278 return M_IMGDATA
->m_data
[pos
];
281 unsigned char wxImage::GetGreen( int x
, int y
)
283 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
285 int w
= M_IMGDATA
->m_width
;
286 int h
= M_IMGDATA
->m_height
;
288 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
290 long pos
= (y
* w
+ x
) * 3;
292 return M_IMGDATA
->m_data
[pos
+1];
295 unsigned char wxImage::GetBlue( int x
, int y
)
297 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
299 int w
= M_IMGDATA
->m_width
;
300 int h
= M_IMGDATA
->m_height
;
302 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
304 long pos
= (y
* w
+ x
) * 3;
306 return M_IMGDATA
->m_data
[pos
+2];
309 bool wxImage::Ok() const
311 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
314 char unsigned *wxImage::GetData() const
316 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
318 return M_IMGDATA
->m_data
;
321 void wxImage::SetData( char unsigned *data
)
323 wxCHECK_RET( Ok(), wxT("invalid image") );
325 wxImageRefData
*newRefData
= new wxImageRefData();
327 newRefData
->m_width
= M_IMGDATA
->m_width
;
328 newRefData
->m_height
= M_IMGDATA
->m_height
;
329 newRefData
->m_data
= data
;
330 newRefData
->m_ok
= TRUE
;
331 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
332 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
333 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
334 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
338 m_refData
= newRefData
;
341 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
343 wxCHECK_RET( Ok(), wxT("invalid image") );
345 M_IMGDATA
->m_maskRed
= r
;
346 M_IMGDATA
->m_maskGreen
= g
;
347 M_IMGDATA
->m_maskBlue
= b
;
348 M_IMGDATA
->m_hasMask
= TRUE
;
351 unsigned char wxImage::GetMaskRed() const
353 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
355 return M_IMGDATA
->m_maskRed
;
358 unsigned char wxImage::GetMaskGreen() const
360 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
362 return M_IMGDATA
->m_maskGreen
;
365 unsigned char wxImage::GetMaskBlue() const
367 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
369 return M_IMGDATA
->m_maskBlue
;
372 void wxImage::SetMask( bool mask
)
374 wxCHECK_RET( Ok(), wxT("invalid image") );
376 M_IMGDATA
->m_hasMask
= mask
;
379 bool wxImage::HasMask() const
381 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
383 return M_IMGDATA
->m_hasMask
;
386 int wxImage::GetWidth() const
388 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
390 return M_IMGDATA
->m_width
;
393 int wxImage::GetHeight() const
395 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
397 return M_IMGDATA
->m_height
;
400 bool wxImage::LoadFile( const wxString
& filename
, long type
)
403 if (wxFileExists(filename
))
405 wxFileInputStream
stream(filename
);
406 wxBufferedInputStream
bstream( stream
);
407 return LoadFile(bstream
, type
);
411 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
415 #else // !wxUSE_STREAMS
417 #endif // wxUSE_STREAMS
420 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
423 if (wxFileExists(filename
))
425 wxFileInputStream
stream(filename
);
426 wxBufferedInputStream
bstream( stream
);
427 return LoadFile(bstream
, mimetype
);
431 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
435 #else // !wxUSE_STREAMS
437 #endif // wxUSE_STREAMS
440 bool wxImage::SaveFile( const wxString
& filename
, int type
)
443 wxFileOutputStream
stream(filename
);
445 if ( stream
.LastError() == wxStream_NOERROR
)
447 wxBufferedOutputStream
bstream( stream
);
448 return SaveFile(bstream
, type
);
451 #endif // wxUSE_STREAMS
455 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
458 wxFileOutputStream
stream(filename
);
460 if ( stream
.LastError() == wxStream_NOERROR
)
462 wxBufferedOutputStream
bstream( stream
);
463 return SaveFile(bstream
, mimetype
);
466 #endif // wxUSE_STREAMS
470 bool wxImage::CanRead( const wxString
&name
)
473 wxFileInputStream
stream(name
);
474 return CanRead(stream
);
482 bool wxImage::CanRead( wxInputStream
&stream
)
484 wxList
&list
=GetHandlers();
486 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
488 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
489 if (handler
->CanRead( stream
))
496 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
500 m_refData
= new wxImageRefData
;
502 wxImageHandler
*handler
;
504 if (type
==wxBITMAP_TYPE_ANY
)
506 wxList
&list
=GetHandlers();
508 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
510 handler
=(wxImageHandler
*)node
->GetData();
511 if (handler
->CanRead( stream
))
512 return handler
->LoadFile( this, stream
);
516 wxLogWarning( _("No handler found for image type.") );
520 handler
= FindHandler(type
);
524 wxLogWarning( _("No image handler for type %d defined."), type
);
529 return handler
->LoadFile( this, stream
);
532 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
536 m_refData
= new wxImageRefData
;
538 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
542 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
547 return handler
->LoadFile( this, stream
);
550 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
552 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
554 wxImageHandler
*handler
= FindHandler(type
);
558 wxLogWarning( _("No image handler for type %d defined."), type
);
563 return handler
->SaveFile( this, stream
);
566 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
568 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
570 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
574 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
579 return handler
->SaveFile( this, stream
);
581 #endif // wxUSE_STREAMS
583 void wxImage::AddHandler( wxImageHandler
*handler
)
585 // make sure that the memory will be freed at the program end
586 sm_handlers
.DeleteContents(TRUE
);
588 sm_handlers
.Append( handler
);
591 void wxImage::InsertHandler( wxImageHandler
*handler
)
593 // make sure that the memory will be freed at the program end
594 sm_handlers
.DeleteContents(TRUE
);
596 sm_handlers
.Insert( handler
);
599 bool wxImage::RemoveHandler( const wxString
& name
)
601 wxImageHandler
*handler
= FindHandler(name
);
604 sm_handlers
.DeleteObject(handler
);
611 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
613 wxNode
*node
= sm_handlers
.First();
616 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
617 if (handler
->GetName().Cmp(name
) == 0) return handler
;
621 return (wxImageHandler
*)NULL
;
624 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
626 wxNode
*node
= sm_handlers
.First();
629 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
630 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
631 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
635 return (wxImageHandler
*)NULL
;
638 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
640 wxNode
*node
= sm_handlers
.First();
643 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
644 if (handler
->GetType() == bitmapType
) return handler
;
650 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
652 wxNode
*node
= sm_handlers
.First();
655 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
656 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
662 void wxImage::InitStandardHandlers()
664 AddHandler( new wxBMPHandler
);
667 void wxImage::CleanUpHandlers()
669 wxNode
*node
= sm_handlers
.First();
672 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
673 wxNode
*next
= node
->Next();
680 //-----------------------------------------------------------------------------
682 //-----------------------------------------------------------------------------
684 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
687 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
692 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
697 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
702 bool wxImageHandler::CanRead( const wxString
& name
)
704 if (wxFileExists(name
))
706 wxFileInputStream
stream(name
);
707 return CanRead(stream
);
711 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
718 #endif // wxUSE_STREAMS
720 //-----------------------------------------------------------------------------
721 // MSW conversion routines
722 //-----------------------------------------------------------------------------
726 wxBitmap
wxImage::ConvertToBitmap() const
731 // sizeLimit is the MS upper limit for the DIB size
733 int sizeLimit
= 1024*768*3;
735 int sizeLimit
= 0x7fff ;
738 // width and height of the device-dependent bitmap
739 int width
= GetWidth();
740 int bmpHeight
= GetHeight();
742 // calc the number of bytes per scanline and padding
743 int bytePerLine
= width
*3;
744 int sizeDWORD
= sizeof( DWORD
);
745 int lineBoundary
= bytePerLine
% sizeDWORD
;
747 if( lineBoundary
> 0 )
749 padding
= sizeDWORD
- lineBoundary
;
750 bytePerLine
+= padding
;
752 // calc the number of DIBs and heights of DIBs
755 int height
= sizeLimit
/bytePerLine
;
756 if( height
>= bmpHeight
)
760 numDIB
= bmpHeight
/ height
;
761 hRemain
= bmpHeight
% height
;
762 if( hRemain
>0 ) numDIB
++;
765 // set bitmap parameters
767 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
768 bitmap
.SetWidth( width
);
769 bitmap
.SetHeight( bmpHeight
);
770 bitmap
.SetDepth( wxDisplayDepth() );
772 // create a DIB header
773 int headersize
= sizeof(BITMAPINFOHEADER
);
774 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
775 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
776 // Fill in the DIB header
777 lpDIBh
->bmiHeader
.biSize
= headersize
;
778 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
779 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
780 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
781 // the general formula for biSizeImage:
782 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
783 lpDIBh
->bmiHeader
.biPlanes
= 1;
784 lpDIBh
->bmiHeader
.biBitCount
= 24;
785 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
786 lpDIBh
->bmiHeader
.biClrUsed
= 0;
787 // These seem not really needed for our purpose here.
788 lpDIBh
->bmiHeader
.biClrImportant
= 0;
789 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
790 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
791 // memory for DIB data
792 unsigned char *lpBits
;
793 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
796 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
801 // create and set the device-dependent bitmap
802 HDC hdc
= ::GetDC(NULL
);
803 HDC memdc
= ::CreateCompatibleDC( hdc
);
805 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
806 ::SelectObject( memdc
, hbitmap
);
808 // copy image data into DIB data and then into DDB (in a loop)
809 unsigned char *data
= GetData();
812 unsigned char *ptdata
= data
;
813 unsigned char *ptbits
;
815 for( n
=0; n
<numDIB
; n
++ )
817 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
819 // redefine height and size of the (possibly) last smaller DIB
820 // memory is not reallocated
822 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
823 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
827 for( j
=0; j
<height
; j
++ )
829 for( i
=0; i
<width
; i
++ )
831 *(ptbits
++) = *(ptdata
+2);
832 *(ptbits
++) = *(ptdata
+1);
833 *(ptbits
++) = *(ptdata
);
836 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
838 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
839 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
841 // if numDIB = 1, lines below can also be used
842 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
843 // The above line is equivalent to the following two lines.
844 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
845 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
846 // or the following lines
847 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
848 // HDC memdc = ::CreateCompatibleDC( hdc );
849 // ::SelectObject( memdc, hbitmap);
850 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
851 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
852 // ::SelectObject( memdc, 0 );
853 // ::DeleteDC( memdc );
855 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
857 // similarly, created an mono-bitmap for the possible mask
860 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
861 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
862 if( numDIB
== 1 ) height
= bmpHeight
;
863 else height
= sizeLimit
/bytePerLine
;
864 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
865 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
867 unsigned char r
= GetMaskRed();
868 unsigned char g
= GetMaskGreen();
869 unsigned char b
= GetMaskBlue();
870 unsigned char zero
= 0, one
= 255;
872 for( n
=0; n
<numDIB
; n
++ )
874 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
876 // redefine height and size of the (possibly) last smaller DIB
877 // memory is not reallocated
879 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
880 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
883 for( int j
=0; j
<height
; j
++ )
885 for(i
=0; i
<width
; i
++ )
887 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
888 unsigned char cr
= (*(ptdata
++)) ;
889 unsigned char cg
= (*(ptdata
++)) ;
890 unsigned char cb
= (*(ptdata
++)) ;
892 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
905 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
907 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
908 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
911 // create a wxMask object
912 wxMask
*mask
= new wxMask();
913 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
914 bitmap
.SetMask( mask
);
915 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
916 /* The following can also be used but is slow to run
917 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
918 wxMask *mask = new wxMask( bitmap, colour );
919 bitmap.SetMask( mask );
922 ::SelectObject( memdc
, hbmpOld
);
925 // free allocated resources
927 ::ReleaseDC(NULL
, hdc
);
931 #if WXWIN_COMPATIBILITY_2
932 // check the wxBitmap object
933 bitmap
.GetBitmapData()->SetOk();
934 #endif // WXWIN_COMPATIBILITY_2
939 wxImage::wxImage( const wxBitmap
&bitmap
)
944 wxFAIL_MSG( wxT("invalid bitmap") );
948 // create an wxImage object
949 int width
= bitmap
.GetWidth();
950 int height
= bitmap
.GetHeight();
951 Create( width
, height
);
952 unsigned char *data
= GetData();
955 wxFAIL_MSG( wxT("could not allocate data for image") );
959 // calc the number of bytes per scanline and padding in the DIB
960 int bytePerLine
= width
*3;
961 int sizeDWORD
= sizeof( DWORD
);
962 int lineBoundary
= bytePerLine
% sizeDWORD
;
964 if( lineBoundary
> 0 )
966 padding
= sizeDWORD
- lineBoundary
;
967 bytePerLine
+= padding
;
970 // create a DIB header
971 int headersize
= sizeof(BITMAPINFOHEADER
);
972 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
975 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
979 // Fill in the DIB header
980 lpDIBh
->bmiHeader
.biSize
= headersize
;
981 lpDIBh
->bmiHeader
.biWidth
= width
;
982 lpDIBh
->bmiHeader
.biHeight
= -height
;
983 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
984 lpDIBh
->bmiHeader
.biPlanes
= 1;
985 lpDIBh
->bmiHeader
.biBitCount
= 24;
986 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
987 lpDIBh
->bmiHeader
.biClrUsed
= 0;
988 // These seem not really needed for our purpose here.
989 lpDIBh
->bmiHeader
.biClrImportant
= 0;
990 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
991 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
992 // memory for DIB data
993 unsigned char *lpBits
;
994 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
997 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1003 // copy data from the device-dependent bitmap to the DIB
1004 HDC hdc
= ::GetDC(NULL
);
1006 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1007 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1009 // copy DIB data into the wxImage object
1011 unsigned char *ptdata
= data
;
1012 unsigned char *ptbits
= lpBits
;
1013 for( i
=0; i
<height
; i
++ )
1015 for( j
=0; j
<width
; j
++ )
1017 *(ptdata
++) = *(ptbits
+2);
1018 *(ptdata
++) = *(ptbits
+1);
1019 *(ptdata
++) = *(ptbits
);
1025 // similarly, set data according to the possible mask bitmap
1026 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1028 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1029 // memory DC created, color set, data copied, and memory DC deleted
1030 HDC memdc
= ::CreateCompatibleDC( hdc
);
1031 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1032 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1033 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1034 ::DeleteDC( memdc
);
1035 // background color set to RGB(16,16,16) in consistent with wxGTK
1036 unsigned char r
=16, g
=16, b
=16;
1039 for( i
=0; i
<height
; i
++ )
1041 for( j
=0; j
<width
; j
++ )
1055 SetMaskColour( r
, g
, b
);
1062 // free allocated resources
1063 ::ReleaseDC(NULL
, hdc
);
1072 #include <PictUtils.h>
1074 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1075 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1076 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1077 extern GWorldPtr
wxMacCreateGWorld( int height
, int width
, int depth
) ;
1078 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1080 wxBitmap
wxImage::ConvertToBitmap() const
1082 // width and height of the device-dependent bitmap
1083 int width
= GetWidth();
1084 int height
= GetHeight();
1088 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1095 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1097 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1099 wxMask *mask = new wxMask();
1100 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1102 bitmap.SetMask( mask );
1108 int r_mask
= GetMaskRed();
1109 int g_mask
= GetMaskGreen();
1110 int b_mask
= GetMaskBlue();
1113 GDHandle origDevice
;
1115 GetGWorld( &origPort
, &origDevice
) ;
1116 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1118 register unsigned char* data
= GetData();
1121 for (int y
= 0; y
< height
; y
++)
1123 for (int x
= 0; x
< width
; x
++)
1125 unsigned char r
= data
[index
++];
1126 unsigned char g
= data
[index
++];
1127 unsigned char b
= data
[index
++];
1129 color
.red
= ( r
<< 8 ) + r
;
1130 color
.green
= ( g
<< 8 ) + g
;
1131 color
.blue
= ( b
<< 8 ) + b
;
1132 SetCPixel( x
, y
, &color
) ;
1136 SetGWorld( origPort
, origDevice
) ;
1140 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1141 wxMask
*mask
= new wxMask( bitmap
, colour
);
1142 bitmap
.SetMask( mask
);
1148 wxImage::wxImage( const wxBitmap
&bitmap
)
1153 wxFAIL_MSG( "invalid bitmap" );
1157 // create an wxImage object
1158 int width
= bitmap
.GetWidth();
1159 int height
= bitmap
.GetHeight();
1160 Create( width
, height
);
1162 unsigned char *data = GetData();
1165 wxFAIL_MSG( "could not allocate data for image" );
1169 // calc the number of bytes per scanline and padding in the DIB
1170 int bytePerLine = width*3;
1171 int sizeDWORD = sizeof( DWORD );
1172 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1174 if( lineBoundary.rem > 0 )
1176 padding = sizeDWORD - lineBoundary.rem;
1177 bytePerLine += padding;
1180 // create a DIB header
1181 int headersize = sizeof(BITMAPINFOHEADER);
1182 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1185 wxFAIL_MSG( "could not allocate data for DIB header" );
1189 // Fill in the DIB header
1190 lpDIBh->bmiHeader.biSize = headersize;
1191 lpDIBh->bmiHeader.biWidth = width;
1192 lpDIBh->bmiHeader.biHeight = -height;
1193 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1194 lpDIBh->bmiHeader.biPlanes = 1;
1195 lpDIBh->bmiHeader.biBitCount = 24;
1196 lpDIBh->bmiHeader.biCompression = BI_RGB;
1197 lpDIBh->bmiHeader.biClrUsed = 0;
1198 // These seem not really needed for our purpose here.
1199 lpDIBh->bmiHeader.biClrImportant = 0;
1200 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1201 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1202 // memory for DIB data
1203 unsigned char *lpBits;
1204 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1207 wxFAIL_MSG( "could not allocate data for DIB" );
1213 // copy data from the device-dependent bitmap to the DIB
1214 HDC hdc = ::GetDC(NULL);
1216 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1217 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1219 // copy DIB data into the wxImage object
1221 unsigned char *ptdata = data;
1222 unsigned char *ptbits = lpBits;
1223 for( i=0; i<height; i++ )
1225 for( j=0; j<width; j++ )
1227 *(ptdata++) = *(ptbits+2);
1228 *(ptdata++) = *(ptbits+1);
1229 *(ptdata++) = *(ptbits );
1235 // similarly, set data according to the possible mask bitmap
1236 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1238 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1239 // memory DC created, color set, data copied, and memory DC deleted
1240 HDC memdc = ::CreateCompatibleDC( hdc );
1241 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1242 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1243 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1244 ::DeleteDC( memdc );
1245 // background color set to RGB(16,16,16) in consistent with wxGTK
1246 unsigned char r=16, g=16, b=16;
1249 for( i=0; i<height; i++ )
1251 for( j=0; j<width; j++ )
1265 SetMaskColour( r, g, b );
1272 // free allocated resources
1273 ::ReleaseDC(NULL, hdc);
1281 //-----------------------------------------------------------------------------
1282 // GTK conversion routines
1283 //-----------------------------------------------------------------------------
1287 #include <gtk/gtk.h>
1288 #include <gdk/gdk.h>
1289 #include <gdk/gdkx.h>
1291 #if (GTK_MINOR_VERSION > 0)
1292 #include <gdk/gdkrgb.h>
1295 extern GtkWidget
*wxRootWindow
;
1297 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1301 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1303 int width
= GetWidth();
1304 int height
= GetHeight();
1306 bitmap
.SetHeight( height
);
1307 bitmap
.SetWidth( width
);
1309 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1311 bitmap
.SetDepth( 1 );
1313 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1316 // Create picture image
1318 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1320 GdkImage
*data_image
=
1321 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1323 // Create mask image
1325 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1329 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1331 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1333 wxMask
*mask
= new wxMask();
1334 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1336 bitmap
.SetMask( mask
);
1339 int r_mask
= GetMaskRed();
1340 int g_mask
= GetMaskGreen();
1341 int b_mask
= GetMaskBlue();
1343 unsigned char* data
= GetData();
1346 for (int y
= 0; y
< height
; y
++)
1348 for (int x
= 0; x
< width
; x
++)
1350 int r
= data
[index
];
1352 int g
= data
[index
];
1354 int b
= data
[index
];
1359 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1360 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1362 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1365 if ((r
== red
) && (b
== blue
) && (g
== green
))
1366 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1368 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1375 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1377 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1379 gdk_image_destroy( data_image
);
1380 gdk_gc_unref( data_gc
);
1386 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1388 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1390 gdk_image_destroy( mask_image
);
1391 gdk_gc_unref( mask_gc
);
1398 wxBitmap
wxImage::ConvertToBitmap() const
1402 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1404 int width
= GetWidth();
1405 int height
= GetHeight();
1407 bitmap
.SetHeight( height
);
1408 bitmap
.SetWidth( width
);
1410 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1414 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1417 int bpp
= visual
->depth
;
1419 bitmap
.SetDepth( bpp
);
1421 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1422 if (bpp
< 8) bpp
= 8;
1424 #if (GTK_MINOR_VERSION > 0)
1426 if (!HasMask() && (bpp
> 8))
1428 static bool s_hasInitialized
= FALSE
;
1430 if (!s_hasInitialized
)
1433 s_hasInitialized
= TRUE
;
1436 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1438 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1442 GDK_RGB_DITHER_NONE
,
1453 // Create picture image
1455 GdkImage
*data_image
=
1456 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1458 // Create mask image
1460 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1464 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1466 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1468 wxMask
*mask
= new wxMask();
1469 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1471 bitmap
.SetMask( mask
);
1476 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1477 byte_order b_o
= RGB
;
1481 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1482 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1483 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1484 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1485 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1486 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1489 int r_mask
= GetMaskRed();
1490 int g_mask
= GetMaskGreen();
1491 int b_mask
= GetMaskBlue();
1493 unsigned char* data
= GetData();
1496 for (int y
= 0; y
< height
; y
++)
1498 for (int x
= 0; x
< width
; x
++)
1500 int r
= data
[index
];
1502 int g
= data
[index
];
1504 int b
= data
[index
];
1509 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1510 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1512 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1520 if (wxTheApp
->m_colorCube
)
1522 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1526 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1527 GdkColor
*colors
= cmap
->colors
;
1528 int max
= 3 * (65536);
1530 for (int i
= 0; i
< cmap
->size
; i
++)
1532 int rdiff
= (r
<< 8) - colors
[i
].red
;
1533 int gdiff
= (g
<< 8) - colors
[i
].green
;
1534 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1535 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1536 if (sum
< max
) { pixel
= i
; max
= sum
; }
1540 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1546 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1547 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1552 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1553 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1562 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1563 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1564 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1565 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1566 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1567 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1569 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1578 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1580 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1582 gdk_image_destroy( data_image
);
1583 gdk_gc_unref( data_gc
);
1589 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1591 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1593 gdk_image_destroy( mask_image
);
1594 gdk_gc_unref( mask_gc
);
1600 wxImage::wxImage( const wxBitmap
&bitmap
)
1602 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1604 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1605 if (bitmap
.GetPixmap())
1607 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1609 bitmap
.GetWidth(), bitmap
.GetHeight() );
1611 if (bitmap
.GetBitmap())
1613 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1615 bitmap
.GetWidth(), bitmap
.GetHeight() );
1618 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1621 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1623 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1624 char unsigned *data
= GetData();
1628 gdk_image_destroy( gdk_image
);
1629 wxFAIL_MSG( wxT("couldn't create image") );
1633 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1634 if (bitmap
.GetMask())
1636 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1638 bitmap
.GetWidth(), bitmap
.GetHeight() );
1640 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1644 int red_shift_right
= 0;
1645 int green_shift_right
= 0;
1646 int blue_shift_right
= 0;
1647 int red_shift_left
= 0;
1648 int green_shift_left
= 0;
1649 int blue_shift_left
= 0;
1650 bool use_shift
= FALSE
;
1652 if (bitmap
.GetPixmap())
1654 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1656 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1657 bpp
= visual
->depth
;
1658 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1659 red_shift_right
= visual
->red_shift
;
1660 red_shift_left
= 8-visual
->red_prec
;
1661 green_shift_right
= visual
->green_shift
;
1662 green_shift_left
= 8-visual
->green_prec
;
1663 blue_shift_right
= visual
->blue_shift
;
1664 blue_shift_left
= 8-visual
->blue_prec
;
1666 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
1668 if (bitmap
.GetBitmap())
1674 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1677 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1679 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1681 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1699 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
1700 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
1701 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
1703 else if (cmap
->colors
)
1705 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1706 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1707 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1711 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1716 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1717 if (mask_pixel
== 0)
1729 gdk_image_destroy( gdk_image
);
1730 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1735 //-----------------------------------------------------------------------------
1736 // Motif conversion routines
1737 //-----------------------------------------------------------------------------
1741 #pragma message disable nosimpint
1745 #pragma message enable nosimpint
1747 #include "wx/utils.h"
1752 Date: Wed, 05 Jan 2000 11:45:40 +0100
1753 From: Frits Boel <boel@niob.knaw.nl>
1754 To: julian.smart@ukonline.co.uk
1755 Subject: Patch for Motif ConvertToBitmap
1759 I've been working on a wxWin application for image processing. From the
1760 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1761 till I looked in the source code of image.cpp. I saw that converting a
1762 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1763 to the 256 colors of the palet. A very time-consuming piece of code!
1765 Because I wanted a faster application, I've made a 'patch' for this. In
1766 short: every pixel of the image is compared to a sorted list with
1767 colors. If the color is found in the list, the palette entry is
1768 returned; if the color is not found, the color palette is searched and
1769 then the palette entry is returned and the color added to the sorted
1772 Maybe there is another method for this, namely changing the palette
1773 itself (if the colors are known, as is the case with tiffs with a
1774 colormap). I did not look at this, maybe someone else did?
1776 The code of the patch is attached, have a look on it, and maybe you will
1777 ship it with the next release of wxMotif?
1782 Software engineer at Hubrecht Laboratory, The Netherlands.
1789 wxSearchColor( void );
1790 wxSearchColor( int size
, XColor
*colors
);
1791 ~wxSearchColor( void );
1793 int SearchColor( int r
, int g
, int b
);
1795 int AddColor( unsigned int value
, int pos
);
1799 unsigned int *color
;
1806 wxSearchColor::wxSearchColor( void )
1809 colors
= (XColor
*) NULL
;
1810 color
= (unsigned int *) NULL
;
1811 entry
= (int*) NULL
;
1817 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
1822 color
= new unsigned int[size
];
1823 entry
= new int [size
];
1825 for (i
= 0; i
< size
; i
++ ) {
1829 bottom
= top
= ( size
>> 1 );
1832 wxSearchColor::~wxSearchColor( void )
1834 if ( color
) delete color
;
1835 if ( entry
) delete entry
;
1838 int wxSearchColor::SearchColor( int r
, int g
, int b
)
1840 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
1845 while ( begin
<= end
) {
1847 middle
= ( begin
+ end
) >> 1;
1849 if ( value
== color
[middle
] ) {
1850 return( entry
[middle
] );
1851 } else if ( value
< color
[middle
] ) {
1859 return AddColor( value
, middle
);
1862 int wxSearchColor::AddColor( unsigned int value
, int pos
)
1866 int max
= 3 * (65536);
1867 for ( i
= 0; i
< 256; i
++ ) {
1868 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
1869 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
1870 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
1871 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1872 if (sum
< max
) { pixel
= i
; max
= sum
; }
1875 if ( entry
[pos
] < 0 ) {
1878 } else if ( value
< color
[pos
] ) {
1881 for ( i
= bottom
; i
< pos
; i
++ ) {
1882 color
[i
-1] = color
[i
];
1883 entry
[i
-1] = entry
[i
];
1886 color
[pos
-1] = value
;
1887 entry
[pos
-1] = pixel
;
1888 } else if ( top
< size
-1 ) {
1889 for ( i
= top
; i
>= pos
; i
-- ) {
1890 color
[i
+1] = color
[i
];
1891 entry
[i
+1] = entry
[i
];
1900 if ( top
< size
-1 ) {
1901 for ( i
= top
; i
> pos
; i
-- ) {
1902 color
[i
+1] = color
[i
];
1903 entry
[i
+1] = entry
[i
];
1906 color
[pos
+1] = value
;
1907 entry
[pos
+1] = pixel
;
1908 } else if ( bottom
> 0 ) {
1909 for ( i
= bottom
; i
< pos
; i
++ ) {
1910 color
[i
-1] = color
[i
];
1911 entry
[i
-1] = entry
[i
];
1923 wxBitmap
wxImage::ConvertToBitmap() const
1927 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1929 int width
= GetWidth();
1930 int height
= GetHeight();
1932 bitmap
.SetHeight( height
);
1933 bitmap
.SetWidth( width
);
1935 Display
*dpy
= (Display
*) wxGetDisplay();
1936 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1937 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1941 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1942 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
1944 bitmap
.Create( width
, height
, bpp
);
1949 GdkImage *mask_image = (GdkImage*) NULL;
1953 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1955 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1957 wxMask *mask = new wxMask();
1958 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1960 bitmap.SetMask( mask );
1964 // Retrieve depth info
1966 XVisualInfo vinfo_template
;
1969 vinfo_template
.visual
= vis
;
1970 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1971 vinfo_template
.depth
= bpp
;
1974 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1976 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
1980 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1981 if (bpp
< 8) bpp
= 8;
1985 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1986 byte_order b_o
= RGB
;
1990 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
1991 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
1992 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
1993 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
1994 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
1995 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
1999 int r_mask = GetMaskRed();
2000 int g_mask = GetMaskGreen();
2001 int b_mask = GetMaskBlue();
2007 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2009 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2010 XQueryColors( dpy
, cmap
, colors
, 256 );
2013 wxSearchColor
scolor( 256, colors
);
2014 unsigned char* data
= GetData();
2017 for (int y
= 0; y
< height
; y
++)
2019 for (int x
= 0; x
< width
; x
++)
2021 int r
= data
[index
];
2023 int g
= data
[index
];
2025 int b
= data
[index
];
2031 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2032 gdk_image_put_pixel( mask_image, x, y, 1 );
2034 gdk_image_put_pixel( mask_image, x, y, 0 );
2042 #if 0 // Old, slower code
2045 if (wxTheApp->m_colorCube)
2047 pixel = wxTheApp->m_colorCube
2048 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2053 int max
= 3 * (65536);
2054 for (int i
= 0; i
< 256; i
++)
2056 int rdiff
= (r
<< 8) - colors
[i
].red
;
2057 int gdiff
= (g
<< 8) - colors
[i
].green
;
2058 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2059 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2060 if (sum
< max
) { pixel
= i
; max
= sum
; }
2067 // And this is all to get the 'right' color...
2068 int pixel
= scolor
.SearchColor( r
, g
, b
);
2069 XPutPixel( data_image
, x
, y
, pixel
);
2074 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2075 XPutPixel( data_image
, x
, y
, pixel
);
2080 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2081 XPutPixel( data_image
, x
, y
, pixel
);
2090 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2091 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2092 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2093 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2094 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2095 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2097 XPutPixel( data_image
, x
, y
, pixel
);
2107 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2108 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2109 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2111 XDestroyImage( data_image
);
2119 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
2121 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
2123 gdk_image_destroy( mask_image );
2124 gdk_gc_unref( mask_gc );
2131 wxImage::wxImage( const wxBitmap
&bitmap
)
2133 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2135 Display
*dpy
= (Display
*) wxGetDisplay();
2136 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2137 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2139 XImage
*ximage
= XGetImage( dpy
,
2140 (Drawable
)bitmap
.GetPixmap(),
2142 bitmap
.GetWidth(), bitmap
.GetHeight(),
2143 AllPlanes
, ZPixmap
);
2145 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2147 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2148 char unsigned *data
= GetData();
2152 XDestroyImage( ximage
);
2153 wxFAIL_MSG( wxT("couldn't create image") );
2158 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2159 if (bitmap.GetMask())
2161 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2163 bitmap.GetWidth(), bitmap.GetHeight() );
2165 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2169 // Retrieve depth info
2171 XVisualInfo vinfo_template
;
2174 vinfo_template
.visual
= vis
;
2175 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2176 vinfo_template
.depth
= bpp
;
2179 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2181 wxCHECK_RET( vi
, wxT("no visual") );
2183 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2190 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2192 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2193 XQueryColors( dpy
, cmap
, colors
, 256 );
2197 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2199 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2201 int pixel
= XGetPixel( ximage
, i
, j
);
2204 data
[pos
] = colors
[pixel
].red
>> 8;
2205 data
[pos
+1] = colors
[pixel
].green
>> 8;
2206 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2207 } else if (bpp
== 15)
2209 data
[pos
] = (pixel
>> 7) & 0xf8;
2210 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2211 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2212 } else if (bpp
== 16)
2214 data
[pos
] = (pixel
>> 8) & 0xf8;
2215 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2216 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2219 data
[pos
] = (pixel
>> 16) & 0xff;
2220 data
[pos
+1] = (pixel
>> 8) & 0xff;
2221 data
[pos
+2] = pixel
& 0xff;
2227 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2228 if (mask_pixel == 0)
2241 XDestroyImage( ximage
);
2243 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2249 // OS/2 Presentation manager conversion routings
2251 wxBitmap
wxImage::ConvertToBitmap() const
2254 return wxNullBitmap
;
2255 wxBitmap bitmap
; // remove
2258 int sizeLimit = 1024*768*3;
2260 // width and height of the device-dependent bitmap
2261 int width = GetWidth();
2262 int bmpHeight = GetHeight();
2264 // calc the number of bytes per scanline and padding
2265 int bytePerLine = width*3;
2266 int sizeDWORD = sizeof( DWORD );
2267 int lineBoundary = bytePerLine % sizeDWORD;
2269 if( lineBoundary > 0 )
2271 padding = sizeDWORD - lineBoundary;
2272 bytePerLine += padding;
2274 // calc the number of DIBs and heights of DIBs
2277 int height = sizeLimit/bytePerLine;
2278 if( height >= bmpHeight )
2282 numDIB = bmpHeight / height;
2283 hRemain = bmpHeight % height;
2284 if( hRemain >0 ) numDIB++;
2287 // set bitmap parameters
2289 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2290 bitmap.SetWidth( width );
2291 bitmap.SetHeight( bmpHeight );
2292 bitmap.SetDepth( wxDisplayDepth() );
2294 // create a DIB header
2295 int headersize = sizeof(BITMAPINFOHEADER);
2296 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2297 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2298 // Fill in the DIB header
2299 lpDIBh->bmiHeader.biSize = headersize;
2300 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2301 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2302 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2303 // the general formula for biSizeImage:
2304 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2305 lpDIBh->bmiHeader.biPlanes = 1;
2306 lpDIBh->bmiHeader.biBitCount = 24;
2307 lpDIBh->bmiHeader.biCompression = BI_RGB;
2308 lpDIBh->bmiHeader.biClrUsed = 0;
2309 // These seem not really needed for our purpose here.
2310 lpDIBh->bmiHeader.biClrImportant = 0;
2311 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2312 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2313 // memory for DIB data
2314 unsigned char *lpBits;
2315 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2318 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2323 // create and set the device-dependent bitmap
2324 HDC hdc = ::GetDC(NULL);
2325 HDC memdc = ::CreateCompatibleDC( hdc );
2327 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2328 ::SelectObject( memdc, hbitmap);
2330 // copy image data into DIB data and then into DDB (in a loop)
2331 unsigned char *data = GetData();
2334 unsigned char *ptdata = data;
2335 unsigned char *ptbits;
2337 for( n=0; n<numDIB; n++ )
2339 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2341 // redefine height and size of the (possibly) last smaller DIB
2342 // memory is not reallocated
2344 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2345 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2349 for( j=0; j<height; j++ )
2351 for( i=0; i<width; i++ )
2353 *(ptbits++) = *(ptdata+2);
2354 *(ptbits++) = *(ptdata+1);
2355 *(ptbits++) = *(ptdata );
2358 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2360 ::StretchDIBits( memdc, 0, origin, width, height,\
2361 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2363 // if numDIB = 1, lines below can also be used
2364 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2365 // The above line is equivalent to the following two lines.
2366 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2367 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2368 // or the following lines
2369 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2370 // HDC memdc = ::CreateCompatibleDC( hdc );
2371 // ::SelectObject( memdc, hbitmap);
2372 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2373 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2374 // ::SelectObject( memdc, 0 );
2375 // ::DeleteDC( memdc );
2377 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2379 // similarly, created an mono-bitmap for the possible mask
2382 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2383 ::SelectObject( memdc, hbitmap);
2384 if( numDIB == 1 ) height = bmpHeight;
2385 else height = sizeLimit/bytePerLine;
2386 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2387 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2389 unsigned char r = GetMaskRed();
2390 unsigned char g = GetMaskGreen();
2391 unsigned char b = GetMaskBlue();
2392 unsigned char zero = 0, one = 255;
2394 for( n=0; n<numDIB; n++ )
2396 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2398 // redefine height and size of the (possibly) last smaller DIB
2399 // memory is not reallocated
2401 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2402 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2405 for( int j=0; j<height; j++ )
2407 for(i=0; i<width; i++ )
2409 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2422 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2424 ::StretchDIBits( memdc, 0, origin, width, height,\
2425 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2428 // create a wxMask object
2429 wxMask *mask = new wxMask();
2430 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2431 bitmap.SetMask( mask );
2434 // free allocated resources
2435 ::SelectObject( memdc, 0 );
2436 ::DeleteDC( memdc );
2437 ::ReleaseDC(NULL, hdc);
2441 // check the wxBitmap object
2442 if( bitmap.GetHBITMAP() )
2443 bitmap.SetOk( TRUE );
2445 bitmap.SetOk( FALSE );
2450 wxImage::wxImage( const wxBitmap
&bitmap
)
2455 wxFAIL_MSG( wxT("invalid bitmap") );
2459 // create an wxImage object
2460 int width
= bitmap
.GetWidth();
2461 int height
= bitmap
.GetHeight();
2462 Create( width
, height
);
2463 unsigned char *data
= GetData();
2466 wxFAIL_MSG( wxT("could not allocate data for image") );
2470 // calc the number of bytes per scanline and padding in the DIB
2471 int bytePerLine
= width
*3;
2472 int sizeDWORD
= sizeof( DWORD
);
2473 int lineBoundary
= bytePerLine
% sizeDWORD
;
2475 if( lineBoundary
> 0 )
2477 padding
= sizeDWORD
- lineBoundary
;
2478 bytePerLine
+= padding
;
2482 // create a DIB header
2483 int headersize = sizeof(BITMAPINFOHEADER);
2484 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2487 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2491 // Fill in the DIB header
2492 lpDIBh->bmiHeader.biSize = headersize;
2493 lpDIBh->bmiHeader.biWidth = width;
2494 lpDIBh->bmiHeader.biHeight = -height;
2495 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2496 lpDIBh->bmiHeader.biPlanes = 1;
2497 lpDIBh->bmiHeader.biBitCount = 24;
2498 lpDIBh->bmiHeader.biCompression = BI_RGB;
2499 lpDIBh->bmiHeader.biClrUsed = 0;
2500 // These seem not really needed for our purpose here.
2501 lpDIBh->bmiHeader.biClrImportant = 0;
2502 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2503 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2504 // memory for DIB data
2505 unsigned char *lpBits;
2506 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2509 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2515 // copy data from the device-dependent bitmap to the DIB
2516 HDC hdc = ::GetDC(NULL);
2518 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2519 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2521 // copy DIB data into the wxImage object
2523 unsigned char *ptdata = data;
2524 unsigned char *ptbits = lpBits;
2525 for( i=0; i<height; i++ )
2527 for( j=0; j<width; j++ )
2529 *(ptdata++) = *(ptbits+2);
2530 *(ptdata++) = *(ptbits+1);
2531 *(ptdata++) = *(ptbits );
2537 // similarly, set data according to the possible mask bitmap
2538 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2540 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2541 // memory DC created, color set, data copied, and memory DC deleted
2542 HDC memdc = ::CreateCompatibleDC( hdc );
2543 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2544 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2545 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2546 ::DeleteDC( memdc );
2547 // background color set to RGB(16,16,16) in consistent with wxGTK
2548 unsigned char r=16, g=16, b=16;
2551 for( i=0; i<height; i++ )
2553 for( j=0; j<width; j++ )
2567 SetMaskColour( r, g, b );
2574 // free allocated resources
2575 ::ReleaseDC(NULL, hdc);
2583 // A module to allow wxImage initialization/cleanup
2584 // without calling these functions from app.cpp or from
2585 // the user's application.
2587 class wxImageModule
: public wxModule
2589 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2592 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2593 void OnExit() { wxImage::CleanUpHandlers(); };
2596 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2599 //-----------------------------------------------------------------------------
2602 // Counts and returns the number of different colours. Optionally stops
2603 // when it exceeds 'stopafter' different colours. This is useful, for
2604 // example, to see if the image can be saved as 8-bit (256 colour or
2605 // less, in this case it would be invoked as CountColours(256)). Default
2606 // value for stopafter is -1 (don't care).
2608 unsigned long wxImage::CountColours( unsigned long stopafter
)
2612 unsigned char r
, g
, b
, *p
;
2613 unsigned long size
, nentries
, key
;
2616 size
= GetWidth() * GetHeight();
2619 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2624 key
= (r
<< 16) | (g
<< 8) | b
;
2626 if (h
.Get(key
) == NULL
)
2638 // Computes the histogram of the image and fills a hash table, indexed
2639 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2640 // wxHNode contains an 'index' (useful to build a palette with the image
2641 // colours) and a 'value', which is the number of pixels in the image with
2644 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2646 unsigned char r
, g
, b
, *p
;
2647 unsigned long size
, nentries
, key
;
2651 size
= GetWidth() * GetHeight();
2654 for (unsigned long j
= 0; j
< size
; j
++)
2659 key
= (r
<< 16) | (g
<< 8) | b
;
2661 hnode
= (wxHNode
*) h
.Get(key
);
2667 hnode
= new wxHNode();
2668 hnode
->index
= nentries
++;
2671 h
.Put(key
, (wxObject
*)hnode
);
2679 * Rotation code by Carlos Moreno
2682 struct wxRotationPixel
2684 unsigned char rgb
[3];
2687 struct wxRotationPoint
2689 wxRotationPoint (double _x
, double _y
) : x(_x
), y(_y
) {}
2690 wxRotationPoint (const wxPoint
& p
) : x(p
.x
), y(p
.y
) {}
2694 static const double gs_Epsilon
= 1e-10;
2696 static inline int wxCint (double x
)
2698 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
2702 // Auxiliary function to rotate a point (x,y) with respect to point p0
2703 // make it inline and use a straight return to facilitate optimization
2704 // also, the function receives the sine and cosine of the angle to avoid
2705 // repeating the time-consuming calls to these functions -- sin/cos can
2706 // be computed and stored in the calling function.
2708 inline wxRotationPoint
rotated_point (const wxRotationPoint
& p
, double cos_angle
, double sin_angle
, const wxRotationPoint
& p0
)
2710 return wxRotationPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
2711 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
2714 inline wxRotationPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRotationPoint
& p0
)
2716 return rotated_point (wxRotationPoint(x
,y
), cos_angle
, sin_angle
, p0
);
2719 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
2721 const wxImage
& img
= * this;
2723 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
2725 // Create pointer-based array to accelerate access to wxImage's data
2726 wxRotationPixel
** data
= new wxRotationPixel
* [img
.GetHeight()];
2728 data
[0] = (wxRotationPixel
*) img
.GetData();
2730 for (i
= 1; i
< img
.GetHeight(); i
++)
2732 data
[i
] = data
[i
- 1] + img
.GetWidth();
2735 // pre-compute coefficients for rotation formula
2736 // (sine and cosine of the angle)
2737 const double cos_angle
= cos(angle
);
2738 const double sin_angle
= sin(angle
);
2740 // Create new Image to store the result
2741 // First, find rectangle that covers the rotated image; to do that,
2742 // rotate the four corners
2744 const wxRotationPoint p0
= centre_of_rotation
;
2746 wxRotationPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
2747 wxRotationPoint p2
= rotated_point (0, img
.GetHeight(), cos_angle
, sin_angle
, p0
);
2748 wxRotationPoint p3
= rotated_point (img
.GetWidth(), 0, cos_angle
, sin_angle
, p0
);
2749 wxRotationPoint p4
= rotated_point (img
.GetWidth(), img
.GetHeight(), cos_angle
, sin_angle
, p0
);
2751 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
2752 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
2754 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
2755 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
2757 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
2759 if (offset_after_rotation
!= NULL
)
2761 *offset_after_rotation
= wxPoint (x1
, y1
);
2764 wxRotationPixel
** result_data
= new wxRotationPixel
* [rotated
.GetHeight()];
2766 result_data
[0] = (wxRotationPixel
*) rotated
.GetData();
2768 for (i
= 1; i
< rotated
.GetHeight(); i
++)
2770 result_data
[i
] = result_data
[i
- 1] + rotated
.GetWidth();
2773 // GRG: if the original image has a mask, use its RGB values
2774 // as the blank pixel, else, fall back to default (black).
2776 wxRotationPixel blankPixel
= {{ 0, 0, 0 }};
2780 unsigned char r
= GetMaskRed();
2781 unsigned char g
= GetMaskGreen();
2782 unsigned char b
= GetMaskBlue();
2783 rotated
.SetMaskColour( r
, g
, b
);
2784 blankPixel
.rgb
[0] = r
;
2785 blankPixel
.rgb
[1] = g
;
2786 blankPixel
.rgb
[2] = b
;
2789 // Now, for each point of the rotated image, find where it came from, by
2790 // performing an inverse rotation (a rotation of -angle) and getting the
2791 // pixel at those coordinates
2793 // GRG: I'd suggest to take the (interpolating) test out of the loops
2796 for (x
= 0; x
< rotated
.GetWidth(); x
++)
2798 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
2800 wxRotationPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
2804 if (0 < src
.x
&& src
.x
< img
.GetWidth() - 1 &&
2805 0 < src
.y
&& src
.y
< img
.GetHeight() - 1)
2807 // interpolate using the 4 enclosing grid-points. Those
2808 // points can be obtained using floor and ceiling of the
2809 // exact coordinates of the point
2811 const int x1
= wxCint(floor(src
.x
));
2812 const int y1
= wxCint(floor(src
.y
));
2813 const int x2
= wxCint(ceil(src
.x
));
2814 const int y2
= wxCint(ceil(src
.y
));
2816 // get four points and the distances (square of the distance,
2817 // for efficiency reasons) for the interpolation formula
2818 const wxRotationPixel
& v1
= data
[y1
][x1
];
2819 const wxRotationPixel
& v2
= data
[y1
][x2
];
2820 const wxRotationPixel
& v3
= data
[y2
][x2
];
2821 const wxRotationPixel
& v4
= data
[y2
][x1
];
2823 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
2824 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
2825 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
2826 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
2828 // Now interpolate as a weighted average of the four surrounding
2829 // points, where the weights are the distances to each of those points
2831 // If the point is exactly at one point of the grid of the source
2832 // image, then don't interpolate -- just assign the pixel
2834 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
2836 result_data
[y
][x
] = v1
;
2838 else if (d2
< gs_Epsilon
)
2840 result_data
[y
][x
] = v2
;
2842 else if (d3
< gs_Epsilon
)
2844 result_data
[y
][x
] = v3
;
2846 else if (d4
< gs_Epsilon
)
2848 result_data
[y
][x
] = v4
;
2852 // weights for the weighted average are proportional to the inverse of the distance
2853 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
2855 for (int i
= 0; i
< 3; i
++) // repeat calculation for R, G, and B
2857 result_data
[y
][x
].rgb
[i
] =
2858 (unsigned char) ( (w1
* v1
.rgb
[i
] + w2
* v2
.rgb
[i
] +
2859 w3
* v3
.rgb
[i
] + w4
* v4
.rgb
[i
]) /
2860 (w1
+ w2
+ w3
+ w4
) );
2866 result_data
[y
][x
] = blankPixel
;
2871 const int xs
= wxCint (src
.x
); // wxCint performs rounding to the
2872 const int ys
= wxCint (src
.y
); // closest integer
2874 if (0 <= xs
&& xs
< img
.GetWidth() &&
2875 0 <= ys
&& ys
< img
.GetHeight())
2877 result_data
[y
][x
] = data
[ys
][xs
];
2881 result_data
[y
][x
] = blankPixel
;
2888 delete [] result_data
;