]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/bitmap.cpp
1 ////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "bitmap.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
37 #include "wx/palette.h"
38 #include "wx/dcmemory.h"
39 #include "wx/bitmap.h"
45 #include "wx/msw/private.h"
48 #if !defined(__WXMICROWIN__)
49 #include "wx/msw/dib.h"
53 #include "wx/xpmdecod.h"
55 // missing from mingw32 header
57 #define CLR_INVALID ((COLORREF)-1)
58 #endif // no CLR_INVALID
60 // ----------------------------------------------------------------------------
62 // ----------------------------------------------------------------------------
64 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxGDIObject
)
65 IMPLEMENT_DYNAMIC_CLASS(wxMask
, wxObject
)
67 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
69 // ============================================================================
71 // ============================================================================
73 // ----------------------------------------------------------------------------
75 // ----------------------------------------------------------------------------
77 wxBitmapRefData::wxBitmapRefData()
80 m_selectedInto
= NULL
;
83 m_hBitmap
= (WXHBITMAP
) NULL
;
84 #if wxUSE_DIB_FOR_BITMAP
89 void wxBitmapRefData::Free()
91 wxASSERT_MSG( !m_selectedInto
,
92 wxT("deleting bitmap still selected into wxMemoryDC") );
96 // printf("About to delete bitmap %d\n", (int) (HBITMAP) m_hBitmap);
98 if ( !::DeleteObject((HBITMAP
)m_hBitmap
) )
100 wxLogLastError(wxT("DeleteObject(hbitmap)"));
105 #if wxUSE_DIB_FOR_BITMAP
108 ::CloseHandle((void*)m_hFileMap
);
117 // ----------------------------------------------------------------------------
119 // ----------------------------------------------------------------------------
121 // this function should be called from all wxBitmap ctors
122 void wxBitmap::Init()
124 // m_refData = NULL; done in the base class ctor
130 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage
& icon
)
132 #ifndef __WXMICROWIN__
133 // it may be either HICON or HCURSOR
134 HICON hicon
= (HICON
)icon
.GetHandle();
137 if ( !::GetIconInfo(hicon
, &iconInfo
) )
139 wxLogLastError(wxT("GetIconInfo"));
144 wxBitmapRefData
*refData
= new wxBitmapRefData
;
147 int w
= icon
.GetWidth(),
148 h
= icon
.GetHeight();
150 refData
->m_width
= w
;
151 refData
->m_height
= h
;
152 refData
->m_depth
= wxDisplayDepth();
154 refData
->m_hBitmap
= (WXHBITMAP
)iconInfo
.hbmColor
;
156 // the mask returned by GetIconInfo() is inversed compared to the usual
158 refData
->m_bitmapMask
= new wxMask((WXHBITMAP
)
159 wxInvertMask(iconInfo
.hbmMask
, w
, h
));
162 // delete the old one now as we don't need it any more
163 ::DeleteObject(iconInfo
.hbmMask
);
165 #if WXWIN_COMPATIBILITY_2
166 refData
->m_ok
= TRUE
;
167 #endif // WXWIN_COMPATIBILITY_2
177 bool wxBitmap::CopyFromCursor(const wxCursor
& cursor
)
185 wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") );
189 return CopyFromIconOrCursor(cursor
);
193 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
200 // GetIconInfo() doesn't exist under Win16 and I don't know any other way
201 // to create a bitmap from icon there - but using this way we won't have
204 int width
= icon
.GetWidth(),
205 height
= icon
.GetHeight();
207 // copy the icon to the bitmap
209 HDC hdc
= ::CreateCompatibleDC(hdcScreen
);
210 HBITMAP hbitmap
= ::CreateCompatibleBitmap(hdcScreen
, width
, height
);
211 HBITMAP hbmpOld
= (HBITMAP
)::SelectObject(hdc
, hbitmap
);
213 ::DrawIcon(hdc
, 0, 0, GetHiconOf(icon
));
215 ::SelectObject(hdc
, hbmpOld
);
218 wxBitmapRefData
*refData
= new wxBitmapRefData
;
221 refData
->m_width
= width
;
222 refData
->m_height
= height
;
223 refData
->m_depth
= wxDisplayDepth();
225 refData
->m_hBitmap
= (WXHBITMAP
)hbitmap
;
227 #if WXWIN_COMPATIBILITY_2
228 refData
->m_ok
= TRUE
;
229 #endif // WXWIN_COMPATIBILITY_2
233 return CopyFromIconOrCursor(icon
);
234 #endif // Win16/Win32
237 wxBitmap::~wxBitmap()
241 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
245 #ifndef __WXMICROWIN__
246 wxBitmapRefData
*refData
= new wxBitmapRefData
;
249 refData
->m_width
= width
;
250 refData
->m_height
= height
;
251 refData
->m_depth
= depth
;
252 refData
->m_numColors
= 0;
253 refData
->m_selectedInto
= NULL
;
258 // we assume that it is in XBM format which is not quite the same as
259 // the format CreateBitmap() wants because the order of bytes in the
261 const size_t bytesPerLine
= (width
+ 7) / 8;
262 const size_t padding
= bytesPerLine
% 2;
263 const size_t len
= height
* ( padding
+ bytesPerLine
);
264 data
= (char *)malloc(len
);
265 const char *src
= bits
;
268 for ( int rows
= 0; rows
< height
; rows
++ )
270 for ( size_t cols
= 0; cols
< bytesPerLine
; cols
++ )
272 unsigned char val
= *src
++;
273 unsigned char reversed
= 0;
275 for ( int bits
= 0; bits
< 8; bits
++)
278 reversed
|= (val
& 0x01);
290 // bits should already be in Windows standard format
291 data
= (char *)bits
; // const_cast is harmless
294 HBITMAP hbmp
= ::CreateBitmap(width
, height
, 1, depth
, data
);
297 wxLogLastError(wxT("CreateBitmap"));
305 SetHBITMAP((WXHBITMAP
)hbmp
);
309 // Create from XPM data
310 bool wxBitmap::CreateFromXpm(const char **data
)
312 #if wxUSE_IMAGE && wxUSE_XPM
315 wxCHECK_MSG( data
!= NULL
, FALSE
, wxT("invalid bitmap data") )
317 wxXPMDecoder decoder
;
318 wxImage img
= decoder
.ReadData(data
);
319 wxCHECK_MSG( img
.Ok(), FALSE
, wxT("invalid bitmap data") )
321 *this = wxBitmap(img
);
328 wxBitmap::wxBitmap(int w
, int h
, int d
)
332 (void)Create(w
, h
, d
);
335 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
339 (void)Create(data
, type
, width
, height
, depth
);
342 wxBitmap::wxBitmap(const wxString
& filename
, wxBitmapType type
)
346 LoadFile(filename
, (int)type
);
349 bool wxBitmap::Create(int w
, int h
, int d
)
353 m_refData
= new wxBitmapRefData
;
355 #if wxUSE_DIB_FOR_BITMAP
356 if ( w
&& h
&& d
>= 16 )
358 if ( !CreateDIB(w
, h
, d
) )
362 #endif // wxUSE_DIB_FOR_BITMAP
364 GetBitmapData()->m_width
= w
;
365 GetBitmapData()->m_height
= h
;
366 GetBitmapData()->m_depth
= d
;
369 #ifndef __WXMICROWIN__
372 hbmp
= ::CreateBitmap(w
, h
, 1, d
, NULL
);
375 wxLogLastError(wxT("CreateBitmap"));
379 #endif // !__WXMICROWIN__
382 hbmp
= ::CreateCompatibleBitmap(dc
, w
, h
);
385 wxLogLastError(wxT("CreateCompatibleBitmap"));
388 GetBitmapData()->m_depth
= wxDisplayDepth();
391 SetHBITMAP((WXHBITMAP
)hbmp
);
393 #if WXWIN_COMPATIBILITY_2
394 GetBitmapData()->m_ok
= hbmp
!= 0;
395 #endif // WXWIN_COMPATIBILITY_2
401 #if wxUSE_DIB_FOR_BITMAP
403 void *wxBitmap::CreateDIB(int width
, int height
, int depth
)
406 const int infosize
= sizeof(BITMAPINFOHEADER
);
408 BITMAPINFO
*info
= (BITMAPINFO
*)malloc(infosize
);
411 memset(info
, 0, infosize
);
413 info
->bmiHeader
.biSize
= infosize
;
414 info
->bmiHeader
.biWidth
= width
;
415 info
->bmiHeader
.biHeight
= height
;
416 info
->bmiHeader
.biPlanes
= 1;
417 info
->bmiHeader
.biBitCount
= depth
;
418 info
->bmiHeader
.biCompression
= BI_RGB
;
419 info
->bmiHeader
.biSizeImage
=
420 (((width
* (depth
/8)) + sizeof(DWORD
) - 1) /
421 sizeof(DWORD
) * sizeof(DWORD
)) * height
;
422 info
->bmiHeader
.biXPelsPerMeter
= 0;
423 info
->bmiHeader
.biYPelsPerMeter
= 0;
424 info
->bmiHeader
.biClrUsed
= 0;
425 info
->bmiHeader
.biClrImportant
= 0;
426 GetBitmapData()->m_hFileMap
=
427 (WXHANDLE
)::CreateFileMapping
429 INVALID_HANDLE_VALUE
,
431 PAGE_READWRITE
| SEC_COMMIT
,
433 info
->bmiHeader
.biSizeImage
,
437 // No need to report an error here. If it fails, we just won't use a
438 // file mapping and CreateDIBSection will just allocate memory for us.
439 GetBitmapData()->m_handle
=
440 (WXHANDLE
)::CreateDIBSection
446 (HANDLE
)GetBitmapData()->m_hFileMap
,
450 if ( !GetBitmapData()->m_handle
)
451 wxLogLastError(wxT("CreateDIBSection"));
461 wxFAIL_MSG( wxT("could not allocate memory for DIB header") );
469 #endif // wxUSE_DIB_FOR_BITMAP
471 // ----------------------------------------------------------------------------
472 // wxImage to/from conversions
473 // ----------------------------------------------------------------------------
477 bool wxBitmap::CreateFromImage( const wxImage
& image
, int depth
)
479 #ifdef __WXMICROWIN__
481 // Set this to 1 to experiment with mask code,
482 // which currently doesn't work
485 m_refData
= new wxBitmapRefData();
487 // Initial attempt at a simple-minded implementation.
488 // The bitmap will always be created at the screen depth,
489 // so the 'depth' argument is ignored.
491 HDC hScreenDC
= ::GetDC(NULL
);
492 int screenDepth
= ::GetDeviceCaps(hScreenDC
, BITSPIXEL
);
494 HBITMAP hBitmap
= ::CreateCompatibleBitmap(hScreenDC
, image
.GetWidth(), image
.GetHeight());
495 HBITMAP hMaskBitmap
= NULL
;
496 HBITMAP hOldMaskBitmap
= NULL
;
498 unsigned char maskR
= 0;
499 unsigned char maskG
= 0;
500 unsigned char maskB
= 0;
502 // printf("Created bitmap %d\n", (int) hBitmap);
505 ::ReleaseDC(NULL
, hScreenDC
);
508 HDC hMemDC
= ::CreateCompatibleDC(hScreenDC
);
510 HBITMAP hOldBitmap
= ::SelectObject(hMemDC
, hBitmap
);
511 ::ReleaseDC(NULL
, hScreenDC
);
513 // created an mono-bitmap for the possible mask
514 bool hasMask
= image
.HasMask();
519 // FIXME: we should be able to pass bpp = 1, but
520 // GdBlit can't handle a different depth
522 hMaskBitmap
= ::CreateBitmap( (WORD
)image
.GetWidth(), (WORD
)image
.GetHeight(), 1, 1, NULL
);
524 hMaskBitmap
= ::CreateCompatibleBitmap( hMemDC
, (WORD
)image
.GetWidth(), (WORD
)image
.GetHeight());
526 maskR
= image
.GetMaskRed();
527 maskG
= image
.GetMaskGreen();
528 maskB
= image
.GetMaskBlue();
536 hScreenDC
= ::GetDC(NULL
);
537 hMaskDC
= ::CreateCompatibleDC(hScreenDC
);
538 ::ReleaseDC(NULL
, hScreenDC
);
540 hOldMaskBitmap
= ::SelectObject( hMaskDC
, hMaskBitmap
);
548 for (i
= 0; i
< image
.GetWidth(); i
++)
550 for (j
= 0; j
< image
.GetHeight(); j
++)
552 unsigned char red
= image
.GetRed(i
, j
);
553 unsigned char green
= image
.GetGreen(i
, j
);
554 unsigned char blue
= image
.GetBlue(i
, j
);
556 ::SetPixel(hMemDC
, i
, j
, PALETTERGB(red
, green
, blue
));
560 // scan the bitmap for the transparent colour and set the corresponding
561 // pixels in the mask to BLACK and the rest to WHITE
562 if (maskR
== red
&& maskG
== green
&& maskB
== blue
)
563 ::SetPixel(hMaskDC
, i
, j
, PALETTERGB(0, 0, 0));
565 ::SetPixel(hMaskDC
, i
, j
, PALETTERGB(255, 255, 255));
570 ::SelectObject(hMemDC
, hOldBitmap
);
574 ::SelectObject(hMaskDC
, hOldMaskBitmap
);
577 ((wxBitmapRefData
*)m_refData
)->m_bitmapMask
= new wxMask((WXHBITMAP
) hMaskBitmap
);
580 SetWidth(image
.GetWidth());
581 SetHeight(image
.GetHeight());
582 SetDepth(screenDepth
);
583 SetHBITMAP( (WXHBITMAP
) hBitmap
);
586 // Copy the palette from the source image
587 SetPalette(image
.GetPalette());
588 #endif // wxUSE_PALETTE
590 #if WXWIN_COMPATIBILITY_2
591 // check the wxBitmap object
592 GetBitmapData()->SetOk();
593 #endif // WXWIN_COMPATIBILITY_2
597 #else // !__WXMICROWIN__
598 wxCHECK_MSG( image
.Ok(), FALSE
, wxT("invalid image") )
600 m_refData
= new wxBitmapRefData();
602 #if wxUSE_DIB_FOR_BITMAP
603 int h
= image
.GetHeight();
604 int w
= image
.GetWidth();
605 unsigned char *dibBits
= (unsigned char*)CreateDIB(w
, h
, 24);
609 // DIBs are stored in bottom to top order so we need to copy bits line by
610 // line and starting from the end
611 const int srcBytesPerLine
= w
* 3;
612 const int dstBytesPerLine
= (srcBytesPerLine
+ sizeof(DWORD
) - 1) /
613 sizeof(DWORD
) * sizeof(DWORD
);
614 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
615 for ( int i
= 0; i
< h
; i
++ )
619 const unsigned char *rgbBits
= src
;
622 // also, the order of RGB is inversed for DIBs
623 *dibBits
++ = rgbBits
[2];
624 *dibBits
++ = rgbBits
[1];
625 *dibBits
++ = rgbBits
[0];
630 // pass to the next line
631 src
-= srcBytesPerLine
;
632 dibBits
+= dstBytesPerLine
- srcBytesPerLine
;
635 if ( image
.HasMask() )
637 SetMask(new wxMask(*this, wxColour(image
.GetMaskRed(),
638 image
.GetMaskGreen(),
639 image
.GetMaskBlue())));
641 #else // wxUSE_DIB_FOR_BITMAP
642 // sizeLimit is the MS upper limit for the DIB size
644 int sizeLimit
= 1024*768*3;
646 int sizeLimit
= 0x7fff;
649 // width and height of the device-dependent bitmap
650 int width
= image
.GetWidth();
651 int bmpHeight
= image
.GetHeight();
653 // calc the number of bytes per scanline and padding
654 int bytePerLine
= width
*3;
655 int sizeDWORD
= sizeof( DWORD
);
656 int lineBoundary
= bytePerLine
% sizeDWORD
;
658 if( lineBoundary
> 0 )
660 padding
= sizeDWORD
- lineBoundary
;
661 bytePerLine
+= padding
;
663 // calc the number of DIBs and heights of DIBs
666 int height
= sizeLimit
/bytePerLine
;
667 if( height
>= bmpHeight
)
671 numDIB
= bmpHeight
/ height
;
672 hRemain
= bmpHeight
% height
;
673 if( hRemain
>0 ) numDIB
++;
676 // set bitmap parameters
677 wxCHECK_MSG( image
.Ok(), FALSE
, wxT("invalid image") );
679 SetHeight( bmpHeight
);
680 if (depth
== -1) depth
= wxDisplayDepth();
684 // Copy the palette from the source image
685 SetPalette(image
.GetPalette());
686 #endif // wxUSE_PALETTE
688 // create a DIB header
689 int headersize
= sizeof(BITMAPINFOHEADER
);
690 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
691 wxCHECK_MSG( lpDIBh
, FALSE
, wxT("could not allocate memory for DIB header") );
692 // Fill in the DIB header
693 lpDIBh
->bmiHeader
.biSize
= headersize
;
694 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
695 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
696 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
697 // the general formula for biSizeImage:
698 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
699 lpDIBh
->bmiHeader
.biPlanes
= 1;
700 lpDIBh
->bmiHeader
.biBitCount
= 24;
701 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
702 lpDIBh
->bmiHeader
.biClrUsed
= 0;
703 // These seem not really needed for our purpose here.
704 lpDIBh
->bmiHeader
.biClrImportant
= 0;
705 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
706 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
707 // memory for DIB data
708 unsigned char *lpBits
;
709 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
712 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
717 // create and set the device-dependent bitmap
718 HDC hdc
= ::GetDC(NULL
);
719 HDC memdc
= ::CreateCompatibleDC( hdc
);
721 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
722 ::SelectObject( memdc
, hbitmap
);
725 HPALETTE hOldPalette
= 0;
726 if (image
.GetPalette().Ok())
728 hOldPalette
= ::SelectPalette(memdc
, (HPALETTE
) image
.GetPalette().GetHPALETTE(), FALSE
);
729 ::RealizePalette(memdc
);
731 #endif // wxUSE_PALETTE
733 // copy image data into DIB data and then into DDB (in a loop)
734 unsigned char *data
= image
.GetData();
737 unsigned char *ptdata
= data
;
738 unsigned char *ptbits
;
740 for( n
=0; n
<numDIB
; n
++ )
742 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
744 // redefine height and size of the (possibly) last smaller DIB
745 // memory is not reallocated
747 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
748 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
752 for( j
=0; j
<height
; j
++ )
754 for( i
=0; i
<width
; i
++ )
756 *(ptbits
++) = *(ptdata
+2);
757 *(ptbits
++) = *(ptdata
+1);
758 *(ptbits
++) = *(ptdata
);
761 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
763 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
764 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
766 // if numDIB = 1, lines below can also be used
767 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
768 // The above line is equivalent to the following two lines.
769 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
770 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
771 // or the following lines
772 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
773 // HDC memdc = ::CreateCompatibleDC( hdc );
774 // ::SelectObject( memdc, hbitmap);
775 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
776 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
777 // ::SelectObject( memdc, 0 );
778 // ::DeleteDC( memdc );
780 SetHBITMAP( (WXHBITMAP
) hbitmap
);
784 SelectPalette(memdc
, hOldPalette
, FALSE
);
785 #endif // wxUSE_PALETTE
787 // similarly, created an mono-bitmap for the possible mask
788 if( image
.HasMask() )
790 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
791 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
792 if( numDIB
== 1 ) height
= bmpHeight
;
793 else height
= sizeLimit
/bytePerLine
;
794 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
795 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
797 unsigned char r
= image
.GetMaskRed();
798 unsigned char g
= image
.GetMaskGreen();
799 unsigned char b
= image
.GetMaskBlue();
800 unsigned char zero
= 0, one
= 255;
802 for( n
=0; n
<numDIB
; n
++ )
804 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
806 // redefine height and size of the (possibly) last smaller DIB
807 // memory is not reallocated
809 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
810 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
813 for( int j
=0; j
<height
; j
++ )
815 for(i
=0; i
<width
; i
++ )
817 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
818 unsigned char cr
= (*(ptdata
++)) ;
819 unsigned char cg
= (*(ptdata
++)) ;
820 unsigned char cb
= (*(ptdata
++)) ;
822 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
835 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
837 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
838 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
841 // create a wxMask object
842 wxMask
*mask
= new wxMask();
843 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
845 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
846 /* The following can also be used but is slow to run
847 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
848 wxMask *mask = new wxMask( *this, colour );
852 ::SelectObject( memdc
, hbmpOld
);
855 // free allocated resources
857 ::ReleaseDC(NULL
, hdc
);
860 #endif // wxUSE_DIB_FOR_BITMAP
862 #if WXWIN_COMPATIBILITY_2
863 // check the wxBitmap object
864 GetBitmapData()->SetOk();
865 #endif // WXWIN_COMPATIBILITY_2
868 #endif // __WXMICROWIN__/!__WXMICROWIN__
871 wxImage
wxBitmap::ConvertToImage() const
873 #ifdef __WXMICROWIN__
874 // Initial attempt at a simple-minded implementation.
875 // The bitmap will always be created at the screen depth,
876 // so the 'depth' argument is ignored.
877 // TODO: transparency (create a mask image)
881 wxFAIL_MSG( wxT("bitmap is invalid") );
887 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
889 // create an wxImage object
890 int width
= GetWidth();
891 int height
= GetHeight();
892 image
.Create( width
, height
);
893 unsigned char *data
= image
.GetData();
896 wxFAIL_MSG( wxT("could not allocate data for image") );
900 HDC hScreenDC
= ::GetDC(NULL
);
902 HDC hMemDC
= ::CreateCompatibleDC(hScreenDC
);
903 ::ReleaseDC(NULL
, hScreenDC
);
905 HBITMAP hBitmap
= (HBITMAP
) GetHBITMAP();
907 HBITMAP hOldBitmap
= ::SelectObject(hMemDC
, hBitmap
);
910 for (i
= 0; i
< GetWidth(); i
++)
912 for (j
= 0; j
< GetHeight(); j
++)
914 COLORREF color
= ::GetPixel(hMemDC
, i
, j
);
915 unsigned char red
= GetRValue(color
);
916 unsigned char green
= GetGValue(color
);
917 unsigned char blue
= GetBValue(color
);
919 image
.SetRGB(i
, j
, red
, green
, blue
);
923 ::SelectObject(hMemDC
, hOldBitmap
);
927 // Copy the palette from the source image
929 image
.SetPalette(* GetPalette());
930 #endif // wxUSE_PALETTE
934 #else // !__WXMICROWIN__
937 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
939 // create an wxImage object
940 int width
= GetWidth();
941 int height
= GetHeight();
942 image
.Create( width
, height
);
943 unsigned char *data
= image
.GetData();
946 wxFAIL_MSG( wxT("could not allocate data for image") );
950 // calc the number of bytes per scanline and padding in the DIB
951 int bytePerLine
= width
*3;
952 int sizeDWORD
= sizeof( DWORD
);
953 int lineBoundary
= bytePerLine
% sizeDWORD
;
955 if( lineBoundary
> 0 )
957 padding
= sizeDWORD
- lineBoundary
;
958 bytePerLine
+= padding
;
961 // create a DIB header
962 int headersize
= sizeof(BITMAPINFOHEADER
);
963 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
966 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
970 // Fill in the DIB header
971 lpDIBh
->bmiHeader
.biSize
= headersize
;
972 lpDIBh
->bmiHeader
.biWidth
= width
;
973 lpDIBh
->bmiHeader
.biHeight
= -height
;
974 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
975 lpDIBh
->bmiHeader
.biPlanes
= 1;
976 lpDIBh
->bmiHeader
.biBitCount
= 24;
977 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
978 lpDIBh
->bmiHeader
.biClrUsed
= 0;
979 // These seem not really needed for our purpose here.
980 lpDIBh
->bmiHeader
.biClrImportant
= 0;
981 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
982 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
983 // memory for DIB data
984 unsigned char *lpBits
;
985 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
988 wxFAIL_MSG( wxT("could not allocate data for DIB") );
994 // copy data from the device-dependent bitmap to the DIB
995 HDC hdc
= ::GetDC(NULL
);
997 hbitmap
= (HBITMAP
) GetHBITMAP();
998 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1000 // copy DIB data into the wxImage object
1002 unsigned char *ptdata
= data
;
1003 unsigned char *ptbits
= lpBits
;
1004 for( i
=0; i
<height
; i
++ )
1006 for( j
=0; j
<width
; j
++ )
1008 *(ptdata
++) = *(ptbits
+2);
1009 *(ptdata
++) = *(ptbits
+1);
1010 *(ptdata
++) = *(ptbits
);
1016 // similarly, set data according to the possible mask bitmap
1017 if( GetMask() && GetMask()->GetMaskBitmap() )
1019 hbitmap
= (HBITMAP
) GetMask()->GetMaskBitmap();
1020 // memory DC created, color set, data copied, and memory DC deleted
1021 HDC memdc
= ::CreateCompatibleDC( hdc
);
1022 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1023 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1024 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1025 ::DeleteDC( memdc
);
1026 // background color set to RGB(16,16,16) in consistent with wxGTK
1027 unsigned char r
=16, g
=16, b
=16;
1030 for( i
=0; i
<height
; i
++ )
1032 for( j
=0; j
<width
; j
++ )
1046 image
.SetMaskColour( r
, g
, b
);
1047 image
.SetMask( TRUE
);
1051 image
.SetMask( FALSE
);
1053 // free allocated resources
1054 ::ReleaseDC(NULL
, hdc
);
1059 #endif // __WXMICROWIN__/!__WXMICROWIN__
1062 #endif // wxUSE_IMAGE
1064 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
1068 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
1072 m_refData
= new wxBitmapRefData
;
1074 return handler
->LoadFile(this, filename
, type
, -1, -1);
1080 if ( image
.LoadFile( filename
, type
) && image
.Ok() )
1082 *this = wxBitmap(image
);
1087 #endif // wxUSE_IMAGE
1092 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
1096 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
1100 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type
);
1105 m_refData
= new wxBitmapRefData
;
1107 return handler
->Create(this, data
, type
, width
, height
, depth
);
1110 bool wxBitmap::SaveFile(const wxString
& filename
,
1112 const wxPalette
*palette
)
1114 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
1118 return handler
->SaveFile(this, filename
, type
, palette
);
1123 // FIXME what about palette? shouldn't we use it?
1124 wxImage image
= ConvertToImage();
1127 return image
.SaveFile(filename
, type
);
1130 #endif // wxUSE_IMAGE
1135 // ----------------------------------------------------------------------------
1136 // sub bitmap extraction
1137 // ----------------------------------------------------------------------------
1139 wxBitmap
wxBitmap::GetSubBitmap( const wxRect
& rect
) const
1141 wxCHECK_MSG( Ok() &&
1142 (rect
.x
>= 0) && (rect
.y
>= 0) &&
1143 (rect
.x
+rect
.width
<= GetWidth()) &&
1144 (rect
.y
+rect
.height
<= GetHeight()),
1145 wxNullBitmap
, wxT("Invalid bitmap or bitmap region") );
1147 wxBitmap
ret( rect
.width
, rect
.height
, GetDepth() );
1148 wxASSERT_MSG( ret
.Ok(), wxT("GetSubBitmap error") );
1150 #ifndef __WXMICROWIN__
1152 MemoryHDC dcSrc
, dcDst
;
1155 SelectInHDC
selectSrc(dcSrc
, GetHbitmap()),
1156 selectDst(dcDst
, GetHbitmapOf(ret
));
1158 if ( !::BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
,
1159 dcSrc
, rect
.x
, rect
.y
, SRCCOPY
) )
1161 wxLogLastError(_T("BitBlt"));
1165 // copy mask if there is one
1168 HBITMAP hbmpMask
= ::CreateBitmap(rect
.width
, rect
.height
, 1, 1, 0);
1170 SelectInHDC
selectSrc(dcSrc
, (HBITMAP
) GetMask()->GetMaskBitmap()),
1171 selectDst(dcDst
, hbmpMask
);
1173 if ( !::BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
,
1174 dcSrc
, rect
.x
, rect
.y
, SRCCOPY
) )
1176 wxLogLastError(_T("BitBlt"));
1179 wxMask
*mask
= new wxMask((WXHBITMAP
) hbmpMask
);
1182 #endif // !__WXMICROWIN__
1187 // ----------------------------------------------------------------------------
1188 // wxBitmap accessors
1189 // ----------------------------------------------------------------------------
1191 void wxBitmap::SetQuality(int q
)
1195 GetBitmapData()->m_quality
= q
;
1198 #if WXWIN_COMPATIBILITY_2
1199 void wxBitmap::SetOk(bool isOk
)
1203 GetBitmapData()->m_ok
= isOk
;
1205 #endif // WXWIN_COMPATIBILITY_2
1209 void wxBitmap::SetPalette(const wxPalette
& palette
)
1213 GetBitmapData()->m_bitmapPalette
= palette
;
1216 #endif // wxUSE_PALETTE
1218 void wxBitmap::SetMask(wxMask
*mask
)
1222 GetBitmapData()->m_bitmapMask
= mask
;
1225 // Creates a bitmap that matches the device context, from
1226 // an arbitray bitmap. At present, the original bitmap must have an
1227 // associated palette. TODO: use a default palette if no palette exists.
1228 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
1229 wxBitmap
wxBitmap::GetBitmapForDC(wxDC
& dc
) const
1231 #ifdef __WXMICROWIN__
1235 wxBitmap
tmpBitmap(GetWidth(), GetHeight(), dc
.GetDepth());
1236 HPALETTE hPal
= (HPALETTE
) NULL
;
1238 void *lpBits
= (void*) NULL
;
1241 if( GetPalette() && GetPalette()->Ok() )
1243 tmpBitmap
.SetPalette(*GetPalette());
1244 memDC
.SelectObject(tmpBitmap
);
1245 memDC
.SetPalette(*GetPalette());
1246 hPal
= (HPALETTE
)GetPalette()->GetHPALETTE();
1250 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
1252 palette
.SetHPALETTE( (WXHPALETTE
)hPal
);
1253 tmpBitmap
.SetPalette( palette
);
1254 memDC
.SelectObject(tmpBitmap
);
1255 memDC
.SetPalette( palette
);
1257 #else // !wxUSE_PALETTE
1258 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
1259 #endif // wxUSE_PALETTE/!wxUSE_PALETTE
1261 // set the height negative because in a DIB the order of the lines is
1263 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal
, &lpDib
) )
1265 return wxNullBitmap
;
1268 lpBits
= malloc(lpDib
->bmiHeader
.biSizeImage
);
1270 ::GetBitmapBits(GetHbitmap(), lpDib
->bmiHeader
.biSizeImage
, lpBits
);
1272 ::SetDIBitsToDevice(GetHdcOf(memDC
), 0, 0,
1273 GetWidth(), GetHeight(),
1274 0, 0, 0, GetHeight(),
1275 lpBits
, lpDib
, DIB_RGB_COLORS
);
1285 // ----------------------------------------------------------------------------
1287 // ----------------------------------------------------------------------------
1294 // Construct a mask from a bitmap and a colour indicating
1295 // the transparent area
1296 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
1299 Create(bitmap
, colour
);
1302 // Construct a mask from a bitmap and a palette index indicating
1303 // the transparent area
1304 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
1307 Create(bitmap
, paletteIndex
);
1310 // Construct a mask from a mono bitmap (copies the bitmap).
1311 wxMask::wxMask(const wxBitmap
& bitmap
)
1320 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1323 // Create a mask from a mono bitmap (copies the bitmap).
1324 bool wxMask::Create(const wxBitmap
& bitmap
)
1326 #ifndef __WXMICROWIN__
1327 wxCHECK_MSG( bitmap
.Ok() && bitmap
.GetDepth() == 1, FALSE
,
1328 _T("can't create mask from invalid or not monochrome bitmap") );
1332 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1336 m_maskBitmap
= (WXHBITMAP
) CreateBitmap(
1341 HDC srcDC
= CreateCompatibleDC(0);
1342 SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
1343 HDC destDC
= CreateCompatibleDC(0);
1344 SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
1345 BitBlt(destDC
, 0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), srcDC
, 0, 0, SRCCOPY
);
1346 SelectObject(srcDC
, 0);
1348 SelectObject(destDC
, 0);
1356 // Create a mask from a bitmap and a palette index indicating
1357 // the transparent area
1358 bool wxMask::Create(const wxBitmap
& bitmap
, int paletteIndex
)
1362 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1367 if (bitmap
.Ok() && bitmap
.GetPalette()->Ok())
1369 unsigned char red
, green
, blue
;
1370 if (bitmap
.GetPalette()->GetRGB(paletteIndex
, &red
, &green
, &blue
))
1372 wxColour
transparentColour(red
, green
, blue
);
1373 return Create(bitmap
, transparentColour
);
1376 #endif // wxUSE_PALETTE
1381 // Create a mask from a bitmap and a colour indicating
1382 // the transparent area
1383 bool wxMask::Create(const wxBitmap
& bitmap
, const wxColour
& colour
)
1385 #ifndef __WXMICROWIN__
1386 wxCHECK_MSG( bitmap
.Ok(), FALSE
, _T("invalid bitmap in wxMask::Create") );
1390 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1394 int width
= bitmap
.GetWidth(),
1395 height
= bitmap
.GetHeight();
1397 // scan the bitmap for the transparent colour and set the corresponding
1398 // pixels in the mask to BLACK and the rest to WHITE
1399 COLORREF maskColour
= wxColourToPalRGB(colour
);
1400 m_maskBitmap
= (WXHBITMAP
)::CreateBitmap(width
, height
, 1, 1, 0);
1402 HDC srcDC
= ::CreateCompatibleDC(NULL
);
1403 HDC destDC
= ::CreateCompatibleDC(NULL
);
1404 if ( !srcDC
|| !destDC
)
1406 wxLogLastError(wxT("CreateCompatibleDC"));
1411 // SelectObject() will fail
1412 wxASSERT_MSG( !bitmap
.GetSelectedInto(),
1413 _T("bitmap can't be selected in another DC") );
1415 HGDIOBJ hbmpSrcOld
= ::SelectObject(srcDC
, GetHbitmapOf(bitmap
));
1418 wxLogLastError(wxT("SelectObject"));
1423 HGDIOBJ hbmpDstOld
= ::SelectObject(destDC
, (HBITMAP
)m_maskBitmap
);
1426 wxLogLastError(wxT("SelectObject"));
1433 // this will create a monochrome bitmap with 0 points for the pixels
1434 // which have the same value as the background colour and 1 for the
1436 ::SetBkColor(srcDC
, maskColour
);
1437 ::BitBlt(destDC
, 0, 0, width
, height
, srcDC
, 0, 0, NOTSRCCOPY
);
1440 ::SelectObject(srcDC
, hbmpSrcOld
);
1442 ::SelectObject(destDC
, hbmpDstOld
);
1446 #else // __WXMICROWIN__
1448 #endif // __WXMICROWIN__/!__WXMICROWIN__
1451 // ----------------------------------------------------------------------------
1453 // ----------------------------------------------------------------------------
1455 bool wxBitmapHandler::Create(wxGDIImage
*image
,
1458 int width
, int height
, int depth
)
1460 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
1462 return bitmap
? Create(bitmap
, data
, flags
, width
, height
, depth
) : FALSE
;
1465 bool wxBitmapHandler::Load(wxGDIImage
*image
,
1466 const wxString
& name
,
1468 int width
, int height
)
1470 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
1472 return bitmap
? LoadFile(bitmap
, name
, flags
, width
, height
) : FALSE
;
1475 bool wxBitmapHandler::Save(wxGDIImage
*image
,
1476 const wxString
& name
,
1479 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
1481 return bitmap
? SaveFile(bitmap
, name
, type
) : FALSE
;
1484 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
),
1485 void *WXUNUSED(data
),
1486 long WXUNUSED(type
),
1487 int WXUNUSED(width
),
1488 int WXUNUSED(height
),
1489 int WXUNUSED(depth
))
1494 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
),
1495 const wxString
& WXUNUSED(name
),
1496 long WXUNUSED(type
),
1497 int WXUNUSED(desiredWidth
),
1498 int WXUNUSED(desiredHeight
))
1503 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
),
1504 const wxString
& WXUNUSED(name
),
1506 const wxPalette
*WXUNUSED(palette
))
1511 // ----------------------------------------------------------------------------
1513 // ----------------------------------------------------------------------------
1515 #ifndef __WXMICROWIN__
1516 bool wxCreateDIB(long xSize
, long ySize
, long bitsPerPixel
,
1517 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
)
1519 unsigned long i
, headerSize
;
1520 LPBITMAPINFO lpDIBheader
= NULL
;
1521 LPPALETTEENTRY lpPe
= NULL
;
1524 // Allocate space for a DIB header
1525 headerSize
= (sizeof(BITMAPINFOHEADER
) + (256 * sizeof(PALETTEENTRY
)));
1526 lpDIBheader
= (BITMAPINFO
*) malloc(headerSize
);
1527 lpPe
= (PALETTEENTRY
*)((BYTE
*)lpDIBheader
+ sizeof(BITMAPINFOHEADER
));
1529 GetPaletteEntries(hPal
, 0, 256, lpPe
);
1531 memset(lpDIBheader
, 0x00, sizeof(BITMAPINFOHEADER
));
1533 // Fill in the static parts of the DIB header
1534 lpDIBheader
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1535 lpDIBheader
->bmiHeader
.biWidth
= xSize
;
1536 lpDIBheader
->bmiHeader
.biHeight
= ySize
;
1537 lpDIBheader
->bmiHeader
.biPlanes
= 1;
1539 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
1540 lpDIBheader
->bmiHeader
.biBitCount
= (WORD
)(bitsPerPixel
);
1541 lpDIBheader
->bmiHeader
.biCompression
= BI_RGB
;
1542 lpDIBheader
->bmiHeader
.biSizeImage
= xSize
* abs(ySize
) * bitsPerPixel
>> 3;
1543 lpDIBheader
->bmiHeader
.biClrUsed
= 256;
1546 // Initialize the DIB palette
1547 for (i
= 0; i
< 256; i
++) {
1548 lpDIBheader
->bmiColors
[i
].rgbReserved
= lpPe
[i
].peFlags
;
1549 lpDIBheader
->bmiColors
[i
].rgbRed
= lpPe
[i
].peRed
;
1550 lpDIBheader
->bmiColors
[i
].rgbGreen
= lpPe
[i
].peGreen
;
1551 lpDIBheader
->bmiColors
[i
].rgbBlue
= lpPe
[i
].peBlue
;
1554 *lpDIBHeader
= lpDIBheader
;
1559 void wxFreeDIB(LPBITMAPINFO lpDIBHeader
)
1565 // ----------------------------------------------------------------------------
1566 // other helper functions
1567 // ----------------------------------------------------------------------------
1569 extern HBITMAP
wxInvertMask(HBITMAP hbmpMask
, int w
, int h
)
1571 #ifndef __WXMICROWIN__
1572 wxCHECK_MSG( hbmpMask
, 0, _T("invalid bitmap in wxInvertMask") );
1574 // get width/height from the bitmap if not given
1578 ::GetObject(hbmpMask
, sizeof(BITMAP
), (LPVOID
)&bm
);
1583 HDC hdcSrc
= ::CreateCompatibleDC(NULL
);
1584 HDC hdcDst
= ::CreateCompatibleDC(NULL
);
1585 if ( !hdcSrc
|| !hdcDst
)
1587 wxLogLastError(wxT("CreateCompatibleDC"));
1590 HBITMAP hbmpInvMask
= ::CreateBitmap(w
, h
, 1, 1, 0);
1593 wxLogLastError(wxT("CreateBitmap"));
1596 ::SelectObject(hdcSrc
, hbmpMask
);
1597 ::SelectObject(hdcDst
, hbmpInvMask
);
1598 if ( !::BitBlt(hdcDst
, 0, 0, w
, h
,
1602 wxLogLastError(wxT("BitBlt"));