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
;
62 wxImageRefData::wxImageRefData()
66 m_data
= (unsigned char*) NULL
;
75 wxImageRefData::~wxImageRefData()
77 if (m_data
&& !m_static
)
81 wxList
wxImage::sm_handlers
;
83 //-----------------------------------------------------------------------------
85 #define M_IMGDATA ((wxImageRefData *)m_refData)
87 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
93 wxImage::wxImage( int width
, int height
)
95 Create( width
, height
);
98 wxImage::wxImage( int width
, int height
, unsigned char* data
, bool static_data
)
100 Create( width
, height
, data
, static_data
);
103 wxImage::wxImage( const wxString
& name
, long type
)
105 LoadFile( name
, type
);
108 wxImage::wxImage( const wxString
& name
, const wxString
& mimetype
)
110 LoadFile( name
, mimetype
);
114 wxImage::wxImage( wxInputStream
& stream
, long type
)
116 LoadFile( stream
, type
);
119 wxImage::wxImage( wxInputStream
& stream
, const wxString
& mimetype
)
121 LoadFile( stream
, mimetype
);
123 #endif // wxUSE_STREAMS
125 wxImage::wxImage( const wxImage
& image
)
130 wxImage::wxImage( const wxImage
* image
)
132 if (image
) Ref(*image
);
135 void wxImage::Create( int width
, int height
)
139 m_refData
= new wxImageRefData();
141 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
142 if (M_IMGDATA
->m_data
)
144 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
146 M_IMGDATA
->m_width
= width
;
147 M_IMGDATA
->m_height
= height
;
148 M_IMGDATA
->m_ok
= TRUE
;
156 void wxImage::Create( int width
, int height
, unsigned char* data
, bool static_data
)
160 m_refData
= new wxImageRefData();
162 M_IMGDATA
->m_data
= data
;
163 if (M_IMGDATA
->m_data
)
165 M_IMGDATA
->m_width
= width
;
166 M_IMGDATA
->m_height
= height
;
167 M_IMGDATA
->m_ok
= TRUE
;
168 M_IMGDATA
->m_static
= static_data
;
176 void wxImage::Destroy()
181 wxImage
wxImage::Copy() const
185 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
187 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
189 char unsigned *data
= image
.GetData();
191 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
193 if (M_IMGDATA
->m_hasMask
)
194 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
196 memcpy( data
, GetData(), M_IMGDATA
->m_width
*M_IMGDATA
->m_height
*3 );
201 wxImage
wxImage::Scale( int width
, int height
) const
205 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
207 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, wxT("invalid image size") );
209 image
.Create( width
, height
);
211 char unsigned *data
= image
.GetData();
213 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
215 if (M_IMGDATA
->m_hasMask
)
216 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
218 long old_height
= M_IMGDATA
->m_height
;
219 long old_width
= M_IMGDATA
->m_width
;
221 char unsigned *source_data
= M_IMGDATA
->m_data
;
222 char unsigned *target_data
= data
;
224 for (long j
= 0; j
< height
; j
++)
226 long y_offset
= (j
* old_height
/ height
) * old_width
;
228 for (long i
= 0; i
< width
; i
++)
231 source_data
+ 3*(y_offset
+ ((i
* old_width
)/ width
)),
240 wxImage
wxImage::Rotate90( bool clockwise
) const
244 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
246 image
.Create( M_IMGDATA
->m_height
, M_IMGDATA
->m_width
);
248 char unsigned *data
= image
.GetData();
250 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
252 if (M_IMGDATA
->m_hasMask
)
253 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
255 long height
= M_IMGDATA
->m_height
;
256 long width
= M_IMGDATA
->m_width
;
258 char unsigned *source_data
= M_IMGDATA
->m_data
;
259 char unsigned *target_data
;
261 for (long j
= 0; j
< height
; j
++)
263 for (long i
= 0; i
< width
; i
++)
266 target_data
= data
+ (((i
+1)*height
) - j
- 1)*3;
268 target_data
= data
+ ((height
*(width
-1)) + j
- (i
*height
))*3;
269 memcpy( target_data
, source_data
, 3 );
277 wxImage
wxImage::Mirror( bool horizontally
) const
281 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
283 image
.Create( M_IMGDATA
->m_width
, M_IMGDATA
->m_height
);
285 char unsigned *data
= image
.GetData();
287 wxCHECK_MSG( data
, image
, wxT("unable to create image") );
289 if (M_IMGDATA
->m_hasMask
)
290 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
292 long height
= M_IMGDATA
->m_height
;
293 long width
= M_IMGDATA
->m_width
;
295 char unsigned *source_data
= M_IMGDATA
->m_data
;
296 char unsigned *target_data
;
300 for (long j
= 0; j
< height
; j
++)
303 target_data
= data
-3;
304 for (long i
= 0; i
< width
; i
++)
306 memcpy( target_data
, source_data
, 3 );
314 for (long i
= 0; i
< height
; i
++)
316 target_data
= data
+ 3*width
*(height
-1-i
);
317 memcpy( target_data
, source_data
, 3*width
);
318 source_data
+= 3*width
;
325 wxImage
wxImage::GetSubImage( const wxRect
&rect
) const
329 wxCHECK_MSG( Ok(), image
, wxT("invalid image") );
331 wxCHECK_MSG( (rect
.GetLeft()>=0) && (rect
.GetTop()>=0) && (rect
.GetRight()<=GetWidth()) && (rect
.GetBottom()<=GetHeight()),
332 image
, wxT("invalid subimage size") );
334 int subwidth
=rect
.GetWidth();
335 const int subheight
=rect
.GetHeight();
337 image
.Create( subwidth
, subheight
);
339 char unsigned *subdata
= image
.GetData(), *data
=GetData();
341 wxCHECK_MSG( subdata
, image
, wxT("unable to create image") );
343 if (M_IMGDATA
->m_hasMask
)
344 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
346 const int subleft
=3*rect
.GetLeft();
347 const int width
=3*GetWidth();
350 data
+=rect
.GetTop()*width
+subleft
;
352 for (long j
= 0; j
< subheight
; ++j
)
354 memcpy( subdata
, data
, subwidth
);
362 void wxImage::Paste( const wxImage
&image
, int x
, int y
)
364 wxCHECK_RET( Ok(), wxT("invalid image") );
365 wxCHECK_RET( image
.Ok(), wxT("invalid image") );
369 int width
= image
.GetWidth();
370 int height
= image
.GetHeight();
383 if ((x
+xx
)+width
> M_IMGDATA
->m_width
)
384 width
= M_IMGDATA
->m_width
- (x
+xx
);
385 if ((y
+yy
)+height
> M_IMGDATA
->m_height
)
386 height
= M_IMGDATA
->m_height
- (y
+yy
);
388 if (width
< 1) return;
389 if (height
< 1) return;
391 if ((!HasMask() && !image
.HasMask()) ||
392 ((HasMask() && image
.HasMask() &&
393 (GetMaskRed()==image
.GetMaskRed()) &&
394 (GetMaskGreen()==image
.GetMaskGreen()) &&
395 (GetMaskBlue()==image
.GetMaskBlue()))))
398 unsigned char* source_data
= image
.GetData() + xx
*3 + yy
*3*image
.GetWidth();
399 int source_step
= image
.GetWidth()*3;
401 unsigned char* target_data
= GetData() + (x
+xx
)*3 + (y
+yy
)*3*M_IMGDATA
->m_width
;
402 int target_step
= M_IMGDATA
->m_width
*3;
403 for (int j
= 0; j
< height
; j
++)
405 memcpy( target_data
, source_data
, width
);
406 source_data
+= source_step
;
407 target_data
+= target_step
;
415 void wxImage::Replace( unsigned char r1
, unsigned char g1
, unsigned char b1
,
416 unsigned char r2
, unsigned char g2
, unsigned char b2
)
418 wxCHECK_RET( Ok(), wxT("invalid image") );
420 char unsigned *data
= GetData();
422 const int w
= GetWidth();
423 const int h
= GetHeight();
425 for (int j
= 0; j
< h
; j
++)
426 for (int i
= 0; i
< w
; i
++)
428 if ((data
[0] == r1
) && (data
[1] == g1
) && (data
[2] == b1
))
438 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
440 wxCHECK_RET( Ok(), wxT("invalid image") );
442 int w
= M_IMGDATA
->m_width
;
443 int h
= M_IMGDATA
->m_height
;
445 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), wxT("invalid image index") );
447 long pos
= (y
* w
+ x
) * 3;
449 M_IMGDATA
->m_data
[ pos
] = r
;
450 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
451 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
454 unsigned char wxImage::GetRed( int x
, int y
) const
456 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
458 int w
= M_IMGDATA
->m_width
;
459 int h
= M_IMGDATA
->m_height
;
461 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
463 long pos
= (y
* w
+ x
) * 3;
465 return M_IMGDATA
->m_data
[pos
];
468 unsigned char wxImage::GetGreen( int x
, int y
) const
470 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
472 int w
= M_IMGDATA
->m_width
;
473 int h
= M_IMGDATA
->m_height
;
475 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
477 long pos
= (y
* w
+ x
) * 3;
479 return M_IMGDATA
->m_data
[pos
+1];
482 unsigned char wxImage::GetBlue( int x
, int y
) const
484 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
486 int w
= M_IMGDATA
->m_width
;
487 int h
= M_IMGDATA
->m_height
;
489 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, wxT("invalid image index") );
491 long pos
= (y
* w
+ x
) * 3;
493 return M_IMGDATA
->m_data
[pos
+2];
496 bool wxImage::Ok() const
498 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
501 char unsigned *wxImage::GetData() const
503 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, wxT("invalid image") );
505 return M_IMGDATA
->m_data
;
508 void wxImage::SetData( char unsigned *data
)
510 wxCHECK_RET( Ok(), wxT("invalid image") );
512 wxImageRefData
*newRefData
= new wxImageRefData();
514 newRefData
->m_width
= M_IMGDATA
->m_width
;
515 newRefData
->m_height
= M_IMGDATA
->m_height
;
516 newRefData
->m_data
= data
;
517 newRefData
->m_ok
= TRUE
;
518 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
519 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
520 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
521 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
525 m_refData
= newRefData
;
528 void wxImage::SetData( char unsigned *data
, int new_width
, int new_height
)
530 wxImageRefData
*newRefData
= new wxImageRefData();
534 newRefData
->m_width
= new_width
;
535 newRefData
->m_height
= new_height
;
536 newRefData
->m_data
= data
;
537 newRefData
->m_ok
= TRUE
;
538 newRefData
->m_maskRed
= M_IMGDATA
->m_maskRed
;
539 newRefData
->m_maskGreen
= M_IMGDATA
->m_maskGreen
;
540 newRefData
->m_maskBlue
= M_IMGDATA
->m_maskBlue
;
541 newRefData
->m_hasMask
= M_IMGDATA
->m_hasMask
;
545 newRefData
->m_width
= new_width
;
546 newRefData
->m_height
= new_height
;
547 newRefData
->m_data
= data
;
548 newRefData
->m_ok
= TRUE
;
553 m_refData
= newRefData
;
556 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
558 wxCHECK_RET( Ok(), wxT("invalid image") );
560 M_IMGDATA
->m_maskRed
= r
;
561 M_IMGDATA
->m_maskGreen
= g
;
562 M_IMGDATA
->m_maskBlue
= b
;
563 M_IMGDATA
->m_hasMask
= TRUE
;
566 unsigned char wxImage::GetMaskRed() const
568 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
570 return M_IMGDATA
->m_maskRed
;
573 unsigned char wxImage::GetMaskGreen() const
575 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
577 return M_IMGDATA
->m_maskGreen
;
580 unsigned char wxImage::GetMaskBlue() const
582 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
584 return M_IMGDATA
->m_maskBlue
;
587 void wxImage::SetMask( bool mask
)
589 wxCHECK_RET( Ok(), wxT("invalid image") );
591 M_IMGDATA
->m_hasMask
= mask
;
594 bool wxImage::HasMask() const
596 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
598 return M_IMGDATA
->m_hasMask
;
601 int wxImage::GetWidth() const
603 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
605 return M_IMGDATA
->m_width
;
608 int wxImage::GetHeight() const
610 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
612 return M_IMGDATA
->m_height
;
615 bool wxImage::LoadFile( const wxString
& filename
, long type
)
618 if (wxFileExists(filename
))
620 wxFileInputStream
stream(filename
);
621 wxBufferedInputStream
bstream( stream
);
622 return LoadFile(bstream
, type
);
626 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
630 #else // !wxUSE_STREAMS
632 #endif // wxUSE_STREAMS
635 bool wxImage::LoadFile( const wxString
& filename
, const wxString
& mimetype
)
638 if (wxFileExists(filename
))
640 wxFileInputStream
stream(filename
);
641 wxBufferedInputStream
bstream( stream
);
642 return LoadFile(bstream
, mimetype
);
646 wxLogError( _("Can't load image from file '%s': file does not exist."), filename
.c_str() );
650 #else // !wxUSE_STREAMS
652 #endif // wxUSE_STREAMS
655 bool wxImage::SaveFile( const wxString
& filename
, int type
)
658 wxFileOutputStream
stream(filename
);
660 if ( stream
.LastError() == wxStream_NOERROR
)
662 wxBufferedOutputStream
bstream( stream
);
663 return SaveFile(bstream
, type
);
666 #endif // wxUSE_STREAMS
670 bool wxImage::SaveFile( const wxString
& filename
, const wxString
& mimetype
)
673 wxFileOutputStream
stream(filename
);
675 if ( stream
.LastError() == wxStream_NOERROR
)
677 wxBufferedOutputStream
bstream( stream
);
678 return SaveFile(bstream
, mimetype
);
681 #endif // wxUSE_STREAMS
685 bool wxImage::CanRead( const wxString
&name
)
688 wxFileInputStream
stream(name
);
689 return CanRead(stream
);
697 bool wxImage::CanRead( wxInputStream
&stream
)
699 wxList
&list
=GetHandlers();
701 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
703 wxImageHandler
*handler
=(wxImageHandler
*)node
->GetData();
704 if (handler
->CanRead( stream
))
711 bool wxImage::LoadFile( wxInputStream
& stream
, long type
)
715 m_refData
= new wxImageRefData
;
717 wxImageHandler
*handler
;
719 if (type
==wxBITMAP_TYPE_ANY
)
721 wxList
&list
=GetHandlers();
723 for ( wxList::Node
*node
= list
.GetFirst(); node
; node
= node
->GetNext() )
725 handler
=(wxImageHandler
*)node
->GetData();
726 if (handler
->CanRead( stream
))
727 return handler
->LoadFile( this, stream
);
731 wxLogWarning( _("No handler found for image type.") );
735 handler
= FindHandler(type
);
739 wxLogWarning( _("No image handler for type %d defined."), type
);
744 return handler
->LoadFile( this, stream
);
747 bool wxImage::LoadFile( wxInputStream
& stream
, const wxString
& mimetype
)
751 m_refData
= new wxImageRefData
;
753 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
757 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
762 return handler
->LoadFile( this, stream
);
765 bool wxImage::SaveFile( wxOutputStream
& stream
, int type
)
767 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
769 wxImageHandler
*handler
= FindHandler(type
);
773 wxLogWarning( _("No image handler for type %d defined."), type
);
778 return handler
->SaveFile( this, stream
);
781 bool wxImage::SaveFile( wxOutputStream
& stream
, const wxString
& mimetype
)
783 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid image") );
785 wxImageHandler
*handler
= FindHandlerMime(mimetype
);
789 wxLogWarning( _("No image handler for type %s defined."), mimetype
.GetData() );
794 return handler
->SaveFile( this, stream
);
796 #endif // wxUSE_STREAMS
798 void wxImage::AddHandler( wxImageHandler
*handler
)
800 // make sure that the memory will be freed at the program end
801 sm_handlers
.DeleteContents(TRUE
);
803 sm_handlers
.Append( handler
);
806 void wxImage::InsertHandler( wxImageHandler
*handler
)
808 // make sure that the memory will be freed at the program end
809 sm_handlers
.DeleteContents(TRUE
);
811 sm_handlers
.Insert( handler
);
814 bool wxImage::RemoveHandler( const wxString
& name
)
816 wxImageHandler
*handler
= FindHandler(name
);
819 sm_handlers
.DeleteObject(handler
);
826 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
828 wxNode
*node
= sm_handlers
.First();
831 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
832 if (handler
->GetName().Cmp(name
) == 0) return handler
;
836 return (wxImageHandler
*)NULL
;
839 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
841 wxNode
*node
= sm_handlers
.First();
844 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
845 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
846 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
850 return (wxImageHandler
*)NULL
;
853 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
855 wxNode
*node
= sm_handlers
.First();
858 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
859 if (handler
->GetType() == bitmapType
) return handler
;
865 wxImageHandler
*wxImage::FindHandlerMime( const wxString
& mimetype
)
867 wxNode
*node
= sm_handlers
.First();
870 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
871 if (handler
->GetMimeType().IsSameAs(mimetype
, FALSE
)) return handler
;
877 void wxImage::InitStandardHandlers()
879 AddHandler( new wxBMPHandler
);
882 void wxImage::CleanUpHandlers()
884 wxNode
*node
= sm_handlers
.First();
887 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
888 wxNode
*next
= node
->Next();
895 //-----------------------------------------------------------------------------
897 //-----------------------------------------------------------------------------
899 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler
,wxObject
)
902 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), wxInputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
), int WXUNUSED(index
) )
907 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
), bool WXUNUSED(verbose
) )
912 int wxImageHandler::GetImageCount( wxInputStream
& WXUNUSED(stream
) )
917 bool wxImageHandler::CanRead( const wxString
& name
)
919 if (wxFileExists(name
))
921 wxFileInputStream
stream(name
);
922 return CanRead(stream
);
926 wxLogError( _("Can't check image format of file '%s': file does not exist."), name
.c_str() );
933 #endif // wxUSE_STREAMS
935 //-----------------------------------------------------------------------------
936 // MSW conversion routines
937 //-----------------------------------------------------------------------------
941 wxBitmap
wxImage::ConvertToBitmap() const
946 // sizeLimit is the MS upper limit for the DIB size
948 int sizeLimit
= 1024*768*3;
950 int sizeLimit
= 0x7fff ;
953 // width and height of the device-dependent bitmap
954 int width
= GetWidth();
955 int bmpHeight
= GetHeight();
957 // calc the number of bytes per scanline and padding
958 int bytePerLine
= width
*3;
959 int sizeDWORD
= sizeof( DWORD
);
960 int lineBoundary
= bytePerLine
% sizeDWORD
;
962 if( lineBoundary
> 0 )
964 padding
= sizeDWORD
- lineBoundary
;
965 bytePerLine
+= padding
;
967 // calc the number of DIBs and heights of DIBs
970 int height
= sizeLimit
/bytePerLine
;
971 if( height
>= bmpHeight
)
975 numDIB
= bmpHeight
/ height
;
976 hRemain
= bmpHeight
% height
;
977 if( hRemain
>0 ) numDIB
++;
980 // set bitmap parameters
982 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
983 bitmap
.SetWidth( width
);
984 bitmap
.SetHeight( bmpHeight
);
985 bitmap
.SetDepth( wxDisplayDepth() );
987 // create a DIB header
988 int headersize
= sizeof(BITMAPINFOHEADER
);
989 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
990 wxCHECK_MSG( lpDIBh
, bitmap
, wxT("could not allocate memory for DIB header") );
991 // Fill in the DIB header
992 lpDIBh
->bmiHeader
.biSize
= headersize
;
993 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
994 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
995 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
996 // the general formula for biSizeImage:
997 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
998 lpDIBh
->bmiHeader
.biPlanes
= 1;
999 lpDIBh
->bmiHeader
.biBitCount
= 24;
1000 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1001 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1002 // These seem not really needed for our purpose here.
1003 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1004 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1005 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1006 // memory for DIB data
1007 unsigned char *lpBits
;
1008 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1011 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
1016 // create and set the device-dependent bitmap
1017 HDC hdc
= ::GetDC(NULL
);
1018 HDC memdc
= ::CreateCompatibleDC( hdc
);
1020 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
1021 ::SelectObject( memdc
, hbitmap
);
1023 // copy image data into DIB data and then into DDB (in a loop)
1024 unsigned char *data
= GetData();
1027 unsigned char *ptdata
= data
;
1028 unsigned char *ptbits
;
1030 for( n
=0; n
<numDIB
; n
++ )
1032 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
1034 // redefine height and size of the (possibly) last smaller DIB
1035 // memory is not reallocated
1037 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1038 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1042 for( j
=0; j
<height
; j
++ )
1044 for( i
=0; i
<width
; i
++ )
1046 *(ptbits
++) = *(ptdata
+2);
1047 *(ptbits
++) = *(ptdata
+1);
1048 *(ptbits
++) = *(ptdata
);
1051 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
1053 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1054 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1056 // if numDIB = 1, lines below can also be used
1057 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1058 // The above line is equivalent to the following two lines.
1059 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1060 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1061 // or the following lines
1062 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1063 // HDC memdc = ::CreateCompatibleDC( hdc );
1064 // ::SelectObject( memdc, hbitmap);
1065 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1066 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1067 // ::SelectObject( memdc, 0 );
1068 // ::DeleteDC( memdc );
1070 bitmap
.SetHBITMAP( (WXHBITMAP
) hbitmap
);
1072 // similarly, created an mono-bitmap for the possible mask
1075 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
1076 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
1077 if( numDIB
== 1 ) height
= bmpHeight
;
1078 else height
= sizeLimit
/bytePerLine
;
1079 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1080 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1082 unsigned char r
= GetMaskRed();
1083 unsigned char g
= GetMaskGreen();
1084 unsigned char b
= GetMaskBlue();
1085 unsigned char zero
= 0, one
= 255;
1087 for( n
=0; n
<numDIB
; n
++ )
1089 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
1091 // redefine height and size of the (possibly) last smaller DIB
1092 // memory is not reallocated
1094 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
1095 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
1098 for( int j
=0; j
<height
; j
++ )
1100 for(i
=0; i
<width
; i
++ )
1102 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
1103 unsigned char cr
= (*(ptdata
++)) ;
1104 unsigned char cg
= (*(ptdata
++)) ;
1105 unsigned char cb
= (*(ptdata
++)) ;
1107 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
1120 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
1122 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
1123 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
1126 // create a wxMask object
1127 wxMask
*mask
= new wxMask();
1128 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
1129 bitmap
.SetMask( mask
);
1130 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1131 /* The following can also be used but is slow to run
1132 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1133 wxMask *mask = new wxMask( bitmap, colour );
1134 bitmap.SetMask( mask );
1137 ::SelectObject( memdc
, hbmpOld
);
1140 // free allocated resources
1141 ::DeleteDC( memdc
);
1142 ::ReleaseDC(NULL
, hdc
);
1146 #if WXWIN_COMPATIBILITY_2
1147 // check the wxBitmap object
1148 bitmap
.GetBitmapData()->SetOk();
1149 #endif // WXWIN_COMPATIBILITY_2
1154 wxImage::wxImage( const wxBitmap
&bitmap
)
1159 wxFAIL_MSG( wxT("invalid bitmap") );
1163 // create an wxImage object
1164 int width
= bitmap
.GetWidth();
1165 int height
= bitmap
.GetHeight();
1166 Create( width
, height
);
1167 unsigned char *data
= GetData();
1170 wxFAIL_MSG( wxT("could not allocate data for image") );
1174 // calc the number of bytes per scanline and padding in the DIB
1175 int bytePerLine
= width
*3;
1176 int sizeDWORD
= sizeof( DWORD
);
1177 int lineBoundary
= bytePerLine
% sizeDWORD
;
1179 if( lineBoundary
> 0 )
1181 padding
= sizeDWORD
- lineBoundary
;
1182 bytePerLine
+= padding
;
1185 // create a DIB header
1186 int headersize
= sizeof(BITMAPINFOHEADER
);
1187 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1190 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1194 // Fill in the DIB header
1195 lpDIBh
->bmiHeader
.biSize
= headersize
;
1196 lpDIBh
->bmiHeader
.biWidth
= width
;
1197 lpDIBh
->bmiHeader
.biHeight
= -height
;
1198 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
1199 lpDIBh
->bmiHeader
.biPlanes
= 1;
1200 lpDIBh
->bmiHeader
.biBitCount
= 24;
1201 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1202 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1203 // These seem not really needed for our purpose here.
1204 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1205 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1206 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1207 // memory for DIB data
1208 unsigned char *lpBits
;
1209 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1212 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1218 // copy data from the device-dependent bitmap to the DIB
1219 HDC hdc
= ::GetDC(NULL
);
1221 hbitmap
= (HBITMAP
) bitmap
.GetHBITMAP();
1222 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1224 // copy DIB data into the wxImage object
1226 unsigned char *ptdata
= data
;
1227 unsigned char *ptbits
= lpBits
;
1228 for( i
=0; i
<height
; i
++ )
1230 for( j
=0; j
<width
; j
++ )
1232 *(ptdata
++) = *(ptbits
+2);
1233 *(ptdata
++) = *(ptbits
+1);
1234 *(ptdata
++) = *(ptbits
);
1240 // similarly, set data according to the possible mask bitmap
1241 if( bitmap
.GetMask() && bitmap
.GetMask()->GetMaskBitmap() )
1243 hbitmap
= (HBITMAP
) bitmap
.GetMask()->GetMaskBitmap();
1244 // memory DC created, color set, data copied, and memory DC deleted
1245 HDC memdc
= ::CreateCompatibleDC( hdc
);
1246 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1247 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1248 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1249 ::DeleteDC( memdc
);
1250 // background color set to RGB(16,16,16) in consistent with wxGTK
1251 unsigned char r
=16, g
=16, b
=16;
1254 for( i
=0; i
<height
; i
++ )
1256 for( j
=0; j
<width
; j
++ )
1270 SetMaskColour( r
, g
, b
);
1277 // free allocated resources
1278 ::ReleaseDC(NULL
, hdc
);
1287 #include <PictUtils.h>
1289 extern CTabHandle
wxMacCreateColorTable( int numColors
) ;
1290 extern void wxMacDestroyColorTable( CTabHandle colors
) ;
1291 extern void wxMacSetColorTableEntry( CTabHandle newColors
, int index
, int red
, int green
, int blue
) ;
1292 extern GWorldPtr
wxMacCreateGWorld( int height
, int width
, int depth
) ;
1293 extern void wxMacDestroyGWorld( GWorldPtr gw
) ;
1295 wxBitmap
wxImage::ConvertToBitmap() const
1297 // width and height of the device-dependent bitmap
1298 int width
= GetWidth();
1299 int height
= GetHeight();
1303 wxBitmap
bitmap( width
, height
, wxDisplayDepth() ) ;
1310 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1312 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1314 wxMask *mask = new wxMask();
1315 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1317 bitmap.SetMask( mask );
1323 int r_mask
= GetMaskRed();
1324 int g_mask
= GetMaskGreen();
1325 int b_mask
= GetMaskBlue();
1328 GDHandle origDevice
;
1330 GetGWorld( &origPort
, &origDevice
) ;
1331 SetGWorld( bitmap
.GetHBITMAP() , NULL
) ;
1333 register unsigned char* data
= GetData();
1336 for (int y
= 0; y
< height
; y
++)
1338 for (int x
= 0; x
< width
; x
++)
1340 unsigned char r
= data
[index
++];
1341 unsigned char g
= data
[index
++];
1342 unsigned char b
= data
[index
++];
1344 color
.red
= ( r
<< 8 ) + r
;
1345 color
.green
= ( g
<< 8 ) + g
;
1346 color
.blue
= ( b
<< 8 ) + b
;
1347 SetCPixel( x
, y
, &color
) ;
1351 SetGWorld( origPort
, origDevice
) ;
1355 wxColour
colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1356 wxMask
*mask
= new wxMask( bitmap
, colour
);
1357 bitmap
.SetMask( mask
);
1363 wxImage::wxImage( const wxBitmap
&bitmap
)
1368 wxFAIL_MSG( "invalid bitmap" );
1372 // create an wxImage object
1373 int width
= bitmap
.GetWidth();
1374 int height
= bitmap
.GetHeight();
1375 Create( width
, height
);
1377 unsigned char *data = GetData();
1380 wxFAIL_MSG( "could not allocate data for image" );
1384 // calc the number of bytes per scanline and padding in the DIB
1385 int bytePerLine = width*3;
1386 int sizeDWORD = sizeof( DWORD );
1387 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1389 if( lineBoundary.rem > 0 )
1391 padding = sizeDWORD - lineBoundary.rem;
1392 bytePerLine += padding;
1395 // create a DIB header
1396 int headersize = sizeof(BITMAPINFOHEADER);
1397 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1400 wxFAIL_MSG( "could not allocate data for DIB header" );
1404 // Fill in the DIB header
1405 lpDIBh->bmiHeader.biSize = headersize;
1406 lpDIBh->bmiHeader.biWidth = width;
1407 lpDIBh->bmiHeader.biHeight = -height;
1408 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1409 lpDIBh->bmiHeader.biPlanes = 1;
1410 lpDIBh->bmiHeader.biBitCount = 24;
1411 lpDIBh->bmiHeader.biCompression = BI_RGB;
1412 lpDIBh->bmiHeader.biClrUsed = 0;
1413 // These seem not really needed for our purpose here.
1414 lpDIBh->bmiHeader.biClrImportant = 0;
1415 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1416 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1417 // memory for DIB data
1418 unsigned char *lpBits;
1419 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1422 wxFAIL_MSG( "could not allocate data for DIB" );
1428 // copy data from the device-dependent bitmap to the DIB
1429 HDC hdc = ::GetDC(NULL);
1431 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1432 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1434 // copy DIB data into the wxImage object
1436 unsigned char *ptdata = data;
1437 unsigned char *ptbits = lpBits;
1438 for( i=0; i<height; i++ )
1440 for( j=0; j<width; j++ )
1442 *(ptdata++) = *(ptbits+2);
1443 *(ptdata++) = *(ptbits+1);
1444 *(ptdata++) = *(ptbits );
1450 // similarly, set data according to the possible mask bitmap
1451 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1453 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1454 // memory DC created, color set, data copied, and memory DC deleted
1455 HDC memdc = ::CreateCompatibleDC( hdc );
1456 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1457 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1458 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1459 ::DeleteDC( memdc );
1460 // background color set to RGB(16,16,16) in consistent with wxGTK
1461 unsigned char r=16, g=16, b=16;
1464 for( i=0; i<height; i++ )
1466 for( j=0; j<width; j++ )
1480 SetMaskColour( r, g, b );
1487 // free allocated resources
1488 ::ReleaseDC(NULL, hdc);
1496 //-----------------------------------------------------------------------------
1497 // GTK conversion routines
1498 //-----------------------------------------------------------------------------
1502 #include <gtk/gtk.h>
1503 #include <gdk/gdk.h>
1504 #include <gdk/gdkx.h>
1506 #if (GTK_MINOR_VERSION > 0)
1507 #include <gdk/gdkrgb.h>
1510 extern GtkWidget
*wxRootWindow
;
1512 wxBitmap
wxImage::ConvertToMonoBitmap( unsigned char red
, unsigned char green
, unsigned char blue
)
1516 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1518 int width
= GetWidth();
1519 int height
= GetHeight();
1521 bitmap
.SetHeight( height
);
1522 bitmap
.SetWidth( width
);
1524 bitmap
.SetBitmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 ) );
1526 bitmap
.SetDepth( 1 );
1528 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1531 // Create picture image
1533 unsigned char *data_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1535 GdkImage
*data_image
=
1536 gdk_image_new_bitmap( visual
, data_data
, width
, height
);
1538 // Create mask image
1540 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1544 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1546 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1548 wxMask
*mask
= new wxMask();
1549 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1551 bitmap
.SetMask( mask
);
1554 int r_mask
= GetMaskRed();
1555 int g_mask
= GetMaskGreen();
1556 int b_mask
= GetMaskBlue();
1558 unsigned char* data
= GetData();
1561 for (int y
= 0; y
< height
; y
++)
1563 for (int x
= 0; x
< width
; x
++)
1565 int r
= data
[index
];
1567 int g
= data
[index
];
1569 int b
= data
[index
];
1574 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1575 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1577 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1580 if ((r
== red
) && (b
== blue
) && (g
== green
))
1581 gdk_image_put_pixel( data_image
, x
, y
, 1 );
1583 gdk_image_put_pixel( data_image
, x
, y
, 0 );
1590 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetBitmap() );
1592 gdk_draw_image( bitmap
.GetBitmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1594 gdk_image_destroy( data_image
);
1595 gdk_gc_unref( data_gc
);
1601 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1603 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1605 gdk_image_destroy( mask_image
);
1606 gdk_gc_unref( mask_gc
);
1613 wxBitmap
wxImage::ConvertToBitmap() const
1617 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
1619 int width
= GetWidth();
1620 int height
= GetHeight();
1622 bitmap
.SetHeight( height
);
1623 bitmap
.SetWidth( width
);
1625 bitmap
.SetPixmap( gdk_pixmap_new( wxRootWindow
->window
, width
, height
, -1 ) );
1629 GdkVisual
*visual
= gdk_window_get_visual( wxRootWindow
->window
);
1632 int bpp
= visual
->depth
;
1634 bitmap
.SetDepth( bpp
);
1636 if ((bpp
== 16) && (visual
->red_mask
!= 0xf800)) bpp
= 15;
1637 if (bpp
< 8) bpp
= 8;
1639 #if (GTK_MINOR_VERSION > 0)
1641 if (!HasMask() && (bpp
> 8))
1643 static bool s_hasInitialized
= FALSE
;
1645 if (!s_hasInitialized
)
1648 s_hasInitialized
= TRUE
;
1651 GdkGC
*gc
= gdk_gc_new( bitmap
.GetPixmap() );
1653 gdk_draw_rgb_image( bitmap
.GetPixmap(),
1657 GDK_RGB_DITHER_NONE
,
1668 // Create picture image
1670 GdkImage
*data_image
=
1671 gdk_image_new( GDK_IMAGE_FASTEST
, visual
, width
, height
);
1673 // Create mask image
1675 GdkImage
*mask_image
= (GdkImage
*) NULL
;
1679 unsigned char *mask_data
= (unsigned char*)malloc( ((width
>> 3)+8) * height
);
1681 mask_image
= gdk_image_new_bitmap( visual
, mask_data
, width
, height
);
1683 wxMask
*mask
= new wxMask();
1684 mask
->m_bitmap
= gdk_pixmap_new( wxRootWindow
->window
, width
, height
, 1 );
1686 bitmap
.SetMask( mask
);
1691 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1692 byte_order b_o
= RGB
;
1696 if ((visual
->red_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->blue_mask
)) b_o
= RGB
;
1697 else if ((visual
->red_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->green_mask
)) b_o
= RGB
;
1698 else if ((visual
->blue_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->green_mask
)) b_o
= BRG
;
1699 else if ((visual
->blue_mask
> visual
->green_mask
) && (visual
->green_mask
> visual
->red_mask
)) b_o
= BGR
;
1700 else if ((visual
->green_mask
> visual
->red_mask
) && (visual
->red_mask
> visual
->blue_mask
)) b_o
= GRB
;
1701 else if ((visual
->green_mask
> visual
->blue_mask
) && (visual
->blue_mask
> visual
->red_mask
)) b_o
= GBR
;
1704 int r_mask
= GetMaskRed();
1705 int g_mask
= GetMaskGreen();
1706 int b_mask
= GetMaskBlue();
1708 unsigned char* data
= GetData();
1711 for (int y
= 0; y
< height
; y
++)
1713 for (int x
= 0; x
< width
; x
++)
1715 int r
= data
[index
];
1717 int g
= data
[index
];
1719 int b
= data
[index
];
1724 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1725 gdk_image_put_pixel( mask_image
, x
, y
, 1 );
1727 gdk_image_put_pixel( mask_image
, x
, y
, 0 );
1735 if (wxTheApp
->m_colorCube
)
1737 pixel
= wxTheApp
->m_colorCube
[ ((r
& 0xf8) << 7) + ((g
& 0xf8) << 2) + ((b
& 0xf8) >> 3) ];
1741 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1742 GdkColor
*colors
= cmap
->colors
;
1743 int max
= 3 * (65536);
1745 for (int i
= 0; i
< cmap
->size
; i
++)
1747 int rdiff
= (r
<< 8) - colors
[i
].red
;
1748 int gdiff
= (g
<< 8) - colors
[i
].green
;
1749 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1750 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
1751 if (sum
< max
) { pixel
= i
; max
= sum
; }
1755 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1761 guint32 pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1762 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1767 guint32 pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1768 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1777 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1778 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1779 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1780 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1781 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1782 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1784 gdk_image_put_pixel( data_image
, x
, y
, pixel
);
1793 GdkGC
*data_gc
= gdk_gc_new( bitmap
.GetPixmap() );
1795 gdk_draw_image( bitmap
.GetPixmap(), data_gc
, data_image
, 0, 0, 0, 0, width
, height
);
1797 gdk_image_destroy( data_image
);
1798 gdk_gc_unref( data_gc
);
1804 GdkGC
*mask_gc
= gdk_gc_new( bitmap
.GetMask()->GetBitmap() );
1806 gdk_draw_image( bitmap
.GetMask()->GetBitmap(), mask_gc
, mask_image
, 0, 0, 0, 0, width
, height
);
1808 gdk_image_destroy( mask_image
);
1809 gdk_gc_unref( mask_gc
);
1815 wxImage::wxImage( const wxBitmap
&bitmap
)
1817 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
1819 GdkImage
*gdk_image
= (GdkImage
*) NULL
;
1820 if (bitmap
.GetPixmap())
1822 gdk_image
= gdk_image_get( bitmap
.GetPixmap(),
1824 bitmap
.GetWidth(), bitmap
.GetHeight() );
1826 if (bitmap
.GetBitmap())
1828 gdk_image
= gdk_image_get( bitmap
.GetBitmap(),
1830 bitmap
.GetWidth(), bitmap
.GetHeight() );
1833 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1836 wxCHECK_RET( gdk_image
, wxT("couldn't create image") );
1838 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
1839 char unsigned *data
= GetData();
1843 gdk_image_destroy( gdk_image
);
1844 wxFAIL_MSG( wxT("couldn't create image") );
1848 GdkImage
*gdk_image_mask
= (GdkImage
*) NULL
;
1849 if (bitmap
.GetMask())
1851 gdk_image_mask
= gdk_image_get( bitmap
.GetMask()->GetBitmap(),
1853 bitmap
.GetWidth(), bitmap
.GetHeight() );
1855 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1859 int red_shift_right
= 0;
1860 int green_shift_right
= 0;
1861 int blue_shift_right
= 0;
1862 int red_shift_left
= 0;
1863 int green_shift_left
= 0;
1864 int blue_shift_left
= 0;
1865 bool use_shift
= FALSE
;
1867 if (bitmap
.GetPixmap())
1869 GdkVisual
*visual
= gdk_window_get_visual( bitmap
.GetPixmap() );
1871 if (visual
== NULL
) visual
= gdk_window_get_visual( wxRootWindow
->window
);
1872 bpp
= visual
->depth
;
1873 if (bpp
== 16) bpp
= visual
->red_prec
+ visual
->green_prec
+ visual
->blue_prec
;
1874 red_shift_right
= visual
->red_shift
;
1875 red_shift_left
= 8-visual
->red_prec
;
1876 green_shift_right
= visual
->green_shift
;
1877 green_shift_left
= 8-visual
->green_prec
;
1878 blue_shift_right
= visual
->blue_shift
;
1879 blue_shift_left
= 8-visual
->blue_prec
;
1881 use_shift
= (visual
->type
== GDK_VISUAL_TRUE_COLOR
) || (visual
->type
== GDK_VISUAL_DIRECT_COLOR
);
1883 if (bitmap
.GetBitmap())
1889 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
1892 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
1894 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
1896 wxUint32 pixel
= gdk_image_get_pixel( gdk_image
, i
, j
);
1914 data
[pos
] = (pixel
>> red_shift_right
) << red_shift_left
;
1915 data
[pos
+1] = (pixel
>> green_shift_right
) << green_shift_left
;
1916 data
[pos
+2] = (pixel
>> blue_shift_right
) << blue_shift_left
;
1918 else if (cmap
->colors
)
1920 data
[pos
] = cmap
->colors
[pixel
].red
>> 8;
1921 data
[pos
+1] = cmap
->colors
[pixel
].green
>> 8;
1922 data
[pos
+2] = cmap
->colors
[pixel
].blue
>> 8;
1926 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1931 int mask_pixel
= gdk_image_get_pixel( gdk_image_mask
, i
, j
);
1932 if (mask_pixel
== 0)
1944 gdk_image_destroy( gdk_image
);
1945 if (gdk_image_mask
) gdk_image_destroy( gdk_image_mask
);
1950 //-----------------------------------------------------------------------------
1951 // Motif conversion routines
1952 //-----------------------------------------------------------------------------
1956 #pragma message disable nosimpint
1960 #pragma message enable nosimpint
1962 #include "wx/utils.h"
1967 Date: Wed, 05 Jan 2000 11:45:40 +0100
1968 From: Frits Boel <boel@niob.knaw.nl>
1969 To: julian.smart@ukonline.co.uk
1970 Subject: Patch for Motif ConvertToBitmap
1974 I've been working on a wxWin application for image processing. From the
1975 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1976 till I looked in the source code of image.cpp. I saw that converting a
1977 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1978 to the 256 colors of the palet. A very time-consuming piece of code!
1980 Because I wanted a faster application, I've made a 'patch' for this. In
1981 short: every pixel of the image is compared to a sorted list with
1982 colors. If the color is found in the list, the palette entry is
1983 returned; if the color is not found, the color palette is searched and
1984 then the palette entry is returned and the color added to the sorted
1987 Maybe there is another method for this, namely changing the palette
1988 itself (if the colors are known, as is the case with tiffs with a
1989 colormap). I did not look at this, maybe someone else did?
1991 The code of the patch is attached, have a look on it, and maybe you will
1992 ship it with the next release of wxMotif?
1997 Software engineer at Hubrecht Laboratory, The Netherlands.
2004 wxSearchColor( void );
2005 wxSearchColor( int size
, XColor
*colors
);
2006 ~wxSearchColor( void );
2008 int SearchColor( int r
, int g
, int b
);
2010 int AddColor( unsigned int value
, int pos
);
2014 unsigned int *color
;
2021 wxSearchColor::wxSearchColor( void )
2024 colors
= (XColor
*) NULL
;
2025 color
= (unsigned int *) NULL
;
2026 entry
= (int*) NULL
;
2032 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
2037 color
= new unsigned int[size
];
2038 entry
= new int [size
];
2040 for (i
= 0; i
< size
; i
++ ) {
2044 bottom
= top
= ( size
>> 1 );
2047 wxSearchColor::~wxSearchColor( void )
2049 if ( color
) delete color
;
2050 if ( entry
) delete entry
;
2053 int wxSearchColor::SearchColor( int r
, int g
, int b
)
2055 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
2060 while ( begin
<= end
) {
2062 middle
= ( begin
+ end
) >> 1;
2064 if ( value
== color
[middle
] ) {
2065 return( entry
[middle
] );
2066 } else if ( value
< color
[middle
] ) {
2074 return AddColor( value
, middle
);
2077 int wxSearchColor::AddColor( unsigned int value
, int pos
)
2081 int max
= 3 * (65536);
2082 for ( i
= 0; i
< 256; i
++ ) {
2083 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
2084 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
2085 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
2086 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2087 if (sum
< max
) { pixel
= i
; max
= sum
; }
2090 if ( entry
[pos
] < 0 ) {
2093 } else if ( value
< color
[pos
] ) {
2096 for ( i
= bottom
; i
< pos
; i
++ ) {
2097 color
[i
-1] = color
[i
];
2098 entry
[i
-1] = entry
[i
];
2101 color
[pos
-1] = value
;
2102 entry
[pos
-1] = pixel
;
2103 } else if ( top
< size
-1 ) {
2104 for ( i
= top
; i
>= pos
; i
-- ) {
2105 color
[i
+1] = color
[i
];
2106 entry
[i
+1] = entry
[i
];
2115 if ( top
< size
-1 ) {
2116 for ( i
= top
; i
> pos
; i
-- ) {
2117 color
[i
+1] = color
[i
];
2118 entry
[i
+1] = entry
[i
];
2121 color
[pos
+1] = value
;
2122 entry
[pos
+1] = pixel
;
2123 } else if ( bottom
> 0 ) {
2124 for ( i
= bottom
; i
< pos
; i
++ ) {
2125 color
[i
-1] = color
[i
];
2126 entry
[i
-1] = entry
[i
];
2138 wxBitmap
wxImage::ConvertToBitmap() const
2142 wxCHECK_MSG( Ok(), bitmap
, wxT("invalid image") );
2144 int width
= GetWidth();
2145 int height
= GetHeight();
2147 bitmap
.SetHeight( height
);
2148 bitmap
.SetWidth( width
);
2150 Display
*dpy
= (Display
*) wxGetDisplay();
2151 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2152 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2156 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2157 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
2159 bitmap
.Create( width
, height
, bpp
);
2163 XImage
*mask_image
= (XImage
*) NULL
;
2166 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
2167 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
2170 // Retrieve depth info
2172 XVisualInfo vinfo_template
;
2175 vinfo_template
.visual
= vis
;
2176 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2177 vinfo_template
.depth
= bpp
;
2180 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2182 wxCHECK_MSG( vi
, wxNullBitmap
, wxT("no visual") );
2186 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2187 if (bpp
< 8) bpp
= 8;
2191 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
2192 byte_order b_o
= RGB
;
2196 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
2197 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
2198 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
2199 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
2200 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
2201 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
2204 int r_mask
= GetMaskRed();
2205 int g_mask
= GetMaskGreen();
2206 int b_mask
= GetMaskBlue();
2211 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
2213 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2214 XQueryColors( dpy
, cmap
, colors
, 256 );
2217 wxSearchColor
scolor( 256, colors
);
2218 unsigned char* data
= GetData();
2220 bool hasMask
= HasMask();
2223 for (int y
= 0; y
< height
; y
++)
2225 for (int x
= 0; x
< width
; x
++)
2227 int r
= data
[index
];
2229 int g
= data
[index
];
2231 int b
= data
[index
];
2236 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
2237 XPutPixel( mask_image
, x
, y
, 0 );
2239 XPutPixel( mask_image
, x
, y
, 1 );
2246 #if 0 // Old, slower code
2249 if (wxTheApp->m_colorCube)
2251 pixel = wxTheApp->m_colorCube
2252 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2257 int max
= 3 * (65536);
2258 for (int i
= 0; i
< 256; i
++)
2260 int rdiff
= (r
<< 8) - colors
[i
].red
;
2261 int gdiff
= (g
<< 8) - colors
[i
].green
;
2262 int bdiff
= (b
<< 8) - colors
[i
].blue
;
2263 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
2264 if (sum
< max
) { pixel
= i
; max
= sum
; }
2271 // And this is all to get the 'right' color...
2272 int pixel
= scolor
.SearchColor( r
, g
, b
);
2273 XPutPixel( data_image
, x
, y
, pixel
);
2278 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
2279 XPutPixel( data_image
, x
, y
, pixel
);
2284 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
2285 XPutPixel( data_image
, x
, y
, pixel
);
2294 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
2295 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
2296 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
2297 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
2298 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
2299 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
2301 XPutPixel( data_image
, x
, y
, pixel
);
2311 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
2312 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
2313 XPutImage( dpy
, (Drawable
)bitmap
.GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
2315 XDestroyImage( data_image
);
2321 wxBitmap
maskBitmap(width
, height
, 1);
2323 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
2324 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
2326 XDestroyImage( mask_image
);
2327 XFreeGC( dpy
, gcMask
);
2329 wxMask
* mask
= new wxMask
;
2330 mask
->SetPixmap(maskBitmap
.GetPixmap());
2332 bitmap
.SetMask(mask
);
2334 maskBitmap
.SetPixmapNull();
2340 wxImage::wxImage( const wxBitmap
&bitmap
)
2342 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
2344 Display
*dpy
= (Display
*) wxGetDisplay();
2345 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
2346 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
2348 XImage
*ximage
= XGetImage( dpy
,
2349 (Drawable
)bitmap
.GetPixmap(),
2351 bitmap
.GetWidth(), bitmap
.GetHeight(),
2352 AllPlanes
, ZPixmap
);
2354 wxCHECK_RET( ximage
, wxT("couldn't create image") );
2356 Create( bitmap
.GetWidth(), bitmap
.GetHeight() );
2357 char unsigned *data
= GetData();
2361 XDestroyImage( ximage
);
2362 wxFAIL_MSG( wxT("couldn't create image") );
2367 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2368 if (bitmap.GetMask())
2370 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2372 bitmap.GetWidth(), bitmap.GetHeight() );
2374 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2378 // Retrieve depth info
2380 XVisualInfo vinfo_template
;
2383 vinfo_template
.visual
= vis
;
2384 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
2385 vinfo_template
.depth
= bpp
;
2388 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
2390 wxCHECK_RET( vi
, wxT("no visual") );
2392 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
2399 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
2401 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
2402 XQueryColors( dpy
, cmap
, colors
, 256 );
2406 for (int j
= 0; j
< bitmap
.GetHeight(); j
++)
2408 for (int i
= 0; i
< bitmap
.GetWidth(); i
++)
2410 int pixel
= XGetPixel( ximage
, i
, j
);
2413 data
[pos
] = colors
[pixel
].red
>> 8;
2414 data
[pos
+1] = colors
[pixel
].green
>> 8;
2415 data
[pos
+2] = colors
[pixel
].blue
>> 8;
2416 } else if (bpp
== 15)
2418 data
[pos
] = (pixel
>> 7) & 0xf8;
2419 data
[pos
+1] = (pixel
>> 2) & 0xf8;
2420 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2421 } else if (bpp
== 16)
2423 data
[pos
] = (pixel
>> 8) & 0xf8;
2424 data
[pos
+1] = (pixel
>> 3) & 0xfc;
2425 data
[pos
+2] = (pixel
<< 3) & 0xf8;
2428 data
[pos
] = (pixel
>> 16) & 0xff;
2429 data
[pos
+1] = (pixel
>> 8) & 0xff;
2430 data
[pos
+2] = pixel
& 0xff;
2436 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2437 if (mask_pixel == 0)
2450 XDestroyImage( ximage
);
2452 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2458 // OS/2 Presentation manager conversion routings
2460 wxBitmap
wxImage::ConvertToBitmap() const
2463 return wxNullBitmap
;
2464 wxBitmap bitmap
; // remove
2467 int sizeLimit = 1024*768*3;
2469 // width and height of the device-dependent bitmap
2470 int width = GetWidth();
2471 int bmpHeight = GetHeight();
2473 // calc the number of bytes per scanline and padding
2474 int bytePerLine = width*3;
2475 int sizeDWORD = sizeof( DWORD );
2476 int lineBoundary = bytePerLine % sizeDWORD;
2478 if( lineBoundary > 0 )
2480 padding = sizeDWORD - lineBoundary;
2481 bytePerLine += padding;
2483 // calc the number of DIBs and heights of DIBs
2486 int height = sizeLimit/bytePerLine;
2487 if( height >= bmpHeight )
2491 numDIB = bmpHeight / height;
2492 hRemain = bmpHeight % height;
2493 if( hRemain >0 ) numDIB++;
2496 // set bitmap parameters
2498 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2499 bitmap.SetWidth( width );
2500 bitmap.SetHeight( bmpHeight );
2501 bitmap.SetDepth( wxDisplayDepth() );
2503 // create a DIB header
2504 int headersize = sizeof(BITMAPINFOHEADER);
2505 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2506 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2507 // Fill in the DIB header
2508 lpDIBh->bmiHeader.biSize = headersize;
2509 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2510 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2511 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2512 // the general formula for biSizeImage:
2513 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2514 lpDIBh->bmiHeader.biPlanes = 1;
2515 lpDIBh->bmiHeader.biBitCount = 24;
2516 lpDIBh->bmiHeader.biCompression = BI_RGB;
2517 lpDIBh->bmiHeader.biClrUsed = 0;
2518 // These seem not really needed for our purpose here.
2519 lpDIBh->bmiHeader.biClrImportant = 0;
2520 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2521 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2522 // memory for DIB data
2523 unsigned char *lpBits;
2524 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2527 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2532 // create and set the device-dependent bitmap
2533 HDC hdc = ::GetDC(NULL);
2534 HDC memdc = ::CreateCompatibleDC( hdc );
2536 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2537 ::SelectObject( memdc, hbitmap);
2539 // copy image data into DIB data and then into DDB (in a loop)
2540 unsigned char *data = GetData();
2543 unsigned char *ptdata = data;
2544 unsigned char *ptbits;
2546 for( n=0; n<numDIB; n++ )
2548 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2550 // redefine height and size of the (possibly) last smaller DIB
2551 // memory is not reallocated
2553 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2554 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2558 for( j=0; j<height; j++ )
2560 for( i=0; i<width; i++ )
2562 *(ptbits++) = *(ptdata+2);
2563 *(ptbits++) = *(ptdata+1);
2564 *(ptbits++) = *(ptdata );
2567 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2569 ::StretchDIBits( memdc, 0, origin, width, height,\
2570 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2572 // if numDIB = 1, lines below can also be used
2573 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2574 // The above line is equivalent to the following two lines.
2575 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2576 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2577 // or the following lines
2578 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2579 // HDC memdc = ::CreateCompatibleDC( hdc );
2580 // ::SelectObject( memdc, hbitmap);
2581 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2582 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2583 // ::SelectObject( memdc, 0 );
2584 // ::DeleteDC( memdc );
2586 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2588 // similarly, created an mono-bitmap for the possible mask
2591 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2592 ::SelectObject( memdc, hbitmap);
2593 if( numDIB == 1 ) height = bmpHeight;
2594 else height = sizeLimit/bytePerLine;
2595 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2596 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2598 unsigned char r = GetMaskRed();
2599 unsigned char g = GetMaskGreen();
2600 unsigned char b = GetMaskBlue();
2601 unsigned char zero = 0, one = 255;
2603 for( n=0; n<numDIB; n++ )
2605 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2607 // redefine height and size of the (possibly) last smaller DIB
2608 // memory is not reallocated
2610 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2611 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2614 for( int j=0; j<height; j++ )
2616 for(i=0; i<width; i++ )
2618 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2631 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2633 ::StretchDIBits( memdc, 0, origin, width, height,\
2634 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2637 // create a wxMask object
2638 wxMask *mask = new wxMask();
2639 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2640 bitmap.SetMask( mask );
2643 // free allocated resources
2644 ::SelectObject( memdc, 0 );
2645 ::DeleteDC( memdc );
2646 ::ReleaseDC(NULL, hdc);
2650 // check the wxBitmap object
2651 if( bitmap.GetHBITMAP() )
2652 bitmap.SetOk( TRUE );
2654 bitmap.SetOk( FALSE );
2659 wxImage::wxImage( const wxBitmap
&bitmap
)
2664 wxFAIL_MSG( wxT("invalid bitmap") );
2668 // create an wxImage object
2669 int width
= bitmap
.GetWidth();
2670 int height
= bitmap
.GetHeight();
2671 Create( width
, height
);
2672 unsigned char *data
= GetData();
2675 wxFAIL_MSG( wxT("could not allocate data for image") );
2679 // calc the number of bytes per scanline and padding in the DIB
2680 int bytePerLine
= width
*3;
2681 int sizeDWORD
= sizeof( DWORD
);
2682 int lineBoundary
= bytePerLine
% sizeDWORD
;
2684 if( lineBoundary
> 0 )
2686 padding
= sizeDWORD
- lineBoundary
;
2687 bytePerLine
+= padding
;
2691 // create a DIB header
2692 int headersize = sizeof(BITMAPINFOHEADER);
2693 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2696 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2700 // Fill in the DIB header
2701 lpDIBh->bmiHeader.biSize = headersize;
2702 lpDIBh->bmiHeader.biWidth = width;
2703 lpDIBh->bmiHeader.biHeight = -height;
2704 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2705 lpDIBh->bmiHeader.biPlanes = 1;
2706 lpDIBh->bmiHeader.biBitCount = 24;
2707 lpDIBh->bmiHeader.biCompression = BI_RGB;
2708 lpDIBh->bmiHeader.biClrUsed = 0;
2709 // These seem not really needed for our purpose here.
2710 lpDIBh->bmiHeader.biClrImportant = 0;
2711 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2712 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2713 // memory for DIB data
2714 unsigned char *lpBits;
2715 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2718 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2724 // copy data from the device-dependent bitmap to the DIB
2725 HDC hdc = ::GetDC(NULL);
2727 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2728 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2730 // copy DIB data into the wxImage object
2732 unsigned char *ptdata = data;
2733 unsigned char *ptbits = lpBits;
2734 for( i=0; i<height; i++ )
2736 for( j=0; j<width; j++ )
2738 *(ptdata++) = *(ptbits+2);
2739 *(ptdata++) = *(ptbits+1);
2740 *(ptdata++) = *(ptbits );
2746 // similarly, set data according to the possible mask bitmap
2747 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2749 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2750 // memory DC created, color set, data copied, and memory DC deleted
2751 HDC memdc = ::CreateCompatibleDC( hdc );
2752 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2753 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2754 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2755 ::DeleteDC( memdc );
2756 // background color set to RGB(16,16,16) in consistent with wxGTK
2757 unsigned char r=16, g=16, b=16;
2760 for( i=0; i<height; i++ )
2762 for( j=0; j<width; j++ )
2776 SetMaskColour( r, g, b );
2783 // free allocated resources
2784 ::ReleaseDC(NULL, hdc);
2792 // A module to allow wxImage initialization/cleanup
2793 // without calling these functions from app.cpp or from
2794 // the user's application.
2796 class wxImageModule
: public wxModule
2798 DECLARE_DYNAMIC_CLASS(wxImageModule
)
2801 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE
; };
2802 void OnExit() { wxImage::CleanUpHandlers(); };
2805 IMPLEMENT_DYNAMIC_CLASS(wxImageModule
, wxModule
)
2808 //-----------------------------------------------------------------------------
2811 // Counts and returns the number of different colours. Optionally stops
2812 // when it exceeds 'stopafter' different colours. This is useful, for
2813 // example, to see if the image can be saved as 8-bit (256 colour or
2814 // less, in this case it would be invoked as CountColours(256)). Default
2815 // value for stopafter is -1 (don't care).
2817 unsigned long wxImage::CountColours( unsigned long stopafter
)
2821 unsigned char r
, g
, b
, *p
;
2822 unsigned long size
, nentries
, key
;
2825 size
= GetWidth() * GetHeight();
2828 for (unsigned long j
= 0; (j
< size
) && (nentries
<= stopafter
) ; j
++)
2833 key
= (r
<< 16) | (g
<< 8) | b
;
2835 if (h
.Get(key
) == NULL
)
2847 // Computes the histogram of the image and fills a hash table, indexed
2848 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2849 // wxHNode contains an 'index' (useful to build a palette with the image
2850 // colours) and a 'value', which is the number of pixels in the image with
2853 unsigned long wxImage::ComputeHistogram( wxHashTable
&h
)
2855 unsigned char r
, g
, b
, *p
;
2856 unsigned long size
, nentries
, key
;
2860 size
= GetWidth() * GetHeight();
2863 for (unsigned long j
= 0; j
< size
; j
++)
2868 key
= (r
<< 16) | (g
<< 8) | b
;
2870 hnode
= (wxHNode
*) h
.Get(key
);
2876 hnode
= new wxHNode();
2877 hnode
->index
= nentries
++;
2880 h
.Put(key
, (wxObject
*)hnode
);
2888 * Rotation code by Carlos Moreno
2891 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2892 // does exactly the same thing. And I also got rid of wxRotationPixel
2893 // bacause of potential problems in architectures where alignment
2894 // is an issue, so I had to rewrite parts of the code.
2896 static const double gs_Epsilon
= 1e-10;
2898 static inline int wxCint (double x
)
2900 return (x
> 0) ? (int) (x
+ 0.5) : (int) (x
- 0.5);
2904 // Auxiliary function to rotate a point (x,y) with respect to point p0
2905 // make it inline and use a straight return to facilitate optimization
2906 // also, the function receives the sine and cosine of the angle to avoid
2907 // repeating the time-consuming calls to these functions -- sin/cos can
2908 // be computed and stored in the calling function.
2910 inline wxRealPoint
rotated_point (const wxRealPoint
& p
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2912 return wxRealPoint (p0
.x
+ (p
.x
- p0
.x
) * cos_angle
- (p
.y
- p0
.y
) * sin_angle
,
2913 p0
.y
+ (p
.y
- p0
.y
) * cos_angle
+ (p
.x
- p0
.x
) * sin_angle
);
2916 inline wxRealPoint
rotated_point (double x
, double y
, double cos_angle
, double sin_angle
, const wxRealPoint
& p0
)
2918 return rotated_point (wxRealPoint(x
,y
), cos_angle
, sin_angle
, p0
);
2921 wxImage
wxImage::Rotate(double angle
, const wxPoint
& centre_of_rotation
, bool interpolating
, wxPoint
* offset_after_rotation
) const
2924 angle
= -angle
; // screen coordinates are a mirror image of "real" coordinates
2926 // Create pointer-based array to accelerate access to wxImage's data
2927 unsigned char ** data
= new unsigned char * [GetHeight()];
2929 data
[0] = GetData();
2931 for (i
= 1; i
< GetHeight(); i
++)
2932 data
[i
] = data
[i
- 1] + (3 * GetWidth());
2934 // precompute coefficients for rotation formula
2935 // (sine and cosine of the angle)
2936 const double cos_angle
= cos(angle
);
2937 const double sin_angle
= sin(angle
);
2939 // Create new Image to store the result
2940 // First, find rectangle that covers the rotated image; to do that,
2941 // rotate the four corners
2943 const wxRealPoint
p0(centre_of_rotation
.x
, centre_of_rotation
.y
);
2945 wxRealPoint p1
= rotated_point (0, 0, cos_angle
, sin_angle
, p0
);
2946 wxRealPoint p2
= rotated_point (0, GetHeight(), cos_angle
, sin_angle
, p0
);
2947 wxRealPoint p3
= rotated_point (GetWidth(), 0, cos_angle
, sin_angle
, p0
);
2948 wxRealPoint p4
= rotated_point (GetWidth(), GetHeight(), cos_angle
, sin_angle
, p0
);
2950 int x1
= (int) floor (wxMin (wxMin(p1
.x
, p2
.x
), wxMin(p3
.x
, p4
.x
)));
2951 int y1
= (int) floor (wxMin (wxMin(p1
.y
, p2
.y
), wxMin(p3
.y
, p4
.y
)));
2952 int x2
= (int) ceil (wxMax (wxMax(p1
.x
, p2
.x
), wxMax(p3
.x
, p4
.x
)));
2953 int y2
= (int) ceil (wxMax (wxMax(p1
.y
, p2
.y
), wxMax(p3
.y
, p4
.y
)));
2955 wxImage
rotated (x2
- x1
+ 1, y2
- y1
+ 1);
2957 if (offset_after_rotation
!= NULL
)
2959 *offset_after_rotation
= wxPoint (x1
, y1
);
2962 // GRG: The rotated (destination) image is always accessed
2963 // sequentially, so there is no need for a pointer-based
2964 // array here (and in fact it would be slower).
2966 unsigned char * dst
= rotated
.GetData();
2968 // GRG: if the original image has a mask, use its RGB values
2969 // as the blank pixel, else, fall back to default (black).
2971 unsigned char blank_r
= 0;
2972 unsigned char blank_g
= 0;
2973 unsigned char blank_b
= 0;
2977 blank_r
= GetMaskRed();
2978 blank_g
= GetMaskGreen();
2979 blank_b
= GetMaskBlue();
2980 rotated
.SetMaskColour( blank_r
, blank_g
, blank_b
);
2983 // Now, for each point of the rotated image, find where it came from, by
2984 // performing an inverse rotation (a rotation of -angle) and getting the
2985 // pixel at those coordinates
2987 // GRG: I've taken the (interpolating) test out of the loops, so that
2988 // it is done only once, instead of repeating it for each pixel.
2993 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
2995 for (x
= 0; x
< rotated
.GetWidth(); x
++)
2997 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
2999 if (-0.25 < src
.x
&& src
.x
< GetWidth() - 0.75 &&
3000 -0.25 < src
.y
&& src
.y
< GetHeight() - 0.75)
3002 // interpolate using the 4 enclosing grid-points. Those
3003 // points can be obtained using floor and ceiling of the
3004 // exact coordinates of the point
3005 // C.M. 2000-02-17: when the point is near the border, special care is required.
3009 if (0 < src
.x
&& src
.x
< GetWidth() - 1)
3011 x1
= wxCint(floor(src
.x
));
3012 x2
= wxCint(ceil(src
.x
));
3014 else // else means that x is near one of the borders (0 or width-1)
3016 x1
= x2
= wxCint (src
.x
);
3019 if (0 < src
.y
&& src
.y
< GetHeight() - 1)
3021 y1
= wxCint(floor(src
.y
));
3022 y2
= wxCint(ceil(src
.y
));
3026 y1
= y2
= wxCint (src
.y
);
3029 // get four points and the distances (square of the distance,
3030 // for efficiency reasons) for the interpolation formula
3032 // GRG: Do not calculate the points until they are
3033 // really needed -- this way we can calculate
3034 // just one, instead of four, if d1, d2, d3
3035 // or d4 are < gs_Epsilon
3037 const double d1
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y1
) * (src
.y
- y1
);
3038 const double d2
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y1
) * (src
.y
- y1
);
3039 const double d3
= (src
.x
- x2
) * (src
.x
- x2
) + (src
.y
- y2
) * (src
.y
- y2
);
3040 const double d4
= (src
.x
- x1
) * (src
.x
- x1
) + (src
.y
- y2
) * (src
.y
- y2
);
3042 // Now interpolate as a weighted average of the four surrounding
3043 // points, where the weights are the distances to each of those points
3045 // If the point is exactly at one point of the grid of the source
3046 // image, then don't interpolate -- just assign the pixel
3048 if (d1
< gs_Epsilon
) // d1,d2,d3,d4 are positive -- no need for abs()
3050 unsigned char *p
= data
[y1
] + (3 * x1
);
3055 else if (d2
< gs_Epsilon
)
3057 unsigned char *p
= data
[y1
] + (3 * x2
);
3062 else if (d3
< gs_Epsilon
)
3064 unsigned char *p
= data
[y2
] + (3 * x2
);
3069 else if (d4
< gs_Epsilon
)
3071 unsigned char *p
= data
[y2
] + (3 * x1
);
3078 // weights for the weighted average are proportional to the inverse of the distance
3079 unsigned char *v1
= data
[y1
] + (3 * x1
);
3080 unsigned char *v2
= data
[y1
] + (3 * x2
);
3081 unsigned char *v3
= data
[y2
] + (3 * x2
);
3082 unsigned char *v4
= data
[y2
] + (3 * x1
);
3084 const double w1
= 1/d1
, w2
= 1/d2
, w3
= 1/d3
, w4
= 1/d4
;
3088 *(dst
++) = (unsigned char)
3089 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3090 w3
* *(v3
++) + w4
* *(v4
++)) /
3091 (w1
+ w2
+ w3
+ w4
) );
3092 *(dst
++) = (unsigned char)
3093 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3094 w3
* *(v3
++) + w4
* *(v4
++)) /
3095 (w1
+ w2
+ w3
+ w4
) );
3096 *(dst
++) = (unsigned char)
3097 ( (w1
* *(v1
++) + w2
* *(v2
++) +
3098 w3
* *(v3
++) + w4
* *(v4
++)) /
3099 (w1
+ w2
+ w3
+ w4
) );
3111 else // not interpolating
3113 for (int y
= 0; y
< rotated
.GetHeight(); y
++)
3115 for (x
= 0; x
< rotated
.GetWidth(); x
++)
3117 wxRealPoint src
= rotated_point (x
+ x1
, y
+ y1
, cos_angle
, -sin_angle
, p0
);
3119 const int xs
= wxCint (src
.x
); // wxCint rounds to the
3120 const int ys
= wxCint (src
.y
); // closest integer
3122 if (0 <= xs
&& xs
< GetWidth() &&
3123 0 <= ys
&& ys
< GetHeight())
3125 unsigned char *p
= data
[ys
] + (3 * xs
);