1 ////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/bitmap.cpp
3 // Purpose:     wxBitmap
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     04/01/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #include "wx/bitmap.h"
27 
28 #ifndef WX_PRECOMP
29     #include <stdio.h>
30 
31     #include "wx/list.h"
32     #include "wx/utils.h"
33     #include "wx/app.h"
34     #include "wx/palette.h"
35     #include "wx/dcmemory.h"
36     #include "wx/icon.h"
37     #include "wx/log.h"
38     #include "wx/image.h"
39 #endif
40 
41 #include "wx/scopedptr.h"
42 #include "wx/msw/private.h"
43 #include "wx/msw/dc.h"
44 
45 #if wxUSE_WXDIB
46     #include "wx/msw/dib.h"
47 #endif
48 
49 #ifdef wxHAS_RAW_BITMAP
50     #include "wx/rawbmp.h"
51 #endif
52 
53 // missing from mingw32 header
54 #ifndef CLR_INVALID
55     #define CLR_INVALID ((COLORREF)-1)
56 #endif // no CLR_INVALID
57 
58 // ----------------------------------------------------------------------------
59 // wxBitmapRefData
60 // ----------------------------------------------------------------------------
61 
62 class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData
63 {
64 public:
wxBitmapRefData()65     wxBitmapRefData() { Init(); }
66     wxBitmapRefData(const wxBitmapRefData& data);
~wxBitmapRefData()67     virtual ~wxBitmapRefData() { Free(); }
68 
69     virtual void Free();
70 
71     // Creates a new bitmap (DDB or DIB) from the contents of the given DIB.
72     void CopyFromDIB(const wxDIB& dib);
73 
74 #if wxUSE_WXDIB
75     // Takes ownership of the given DIB.
76     bool AssignDIB(wxDIB& dib);
77 #endif // wxUSE_WXDIB
78 
79 
80     // set the mask object to use as the mask, we take ownership of it
SetMask(wxMask * mask)81     void SetMask(wxMask *mask)
82     {
83         delete m_bitmapMask;
84         m_bitmapMask = mask;
85     }
86 
87     // set the HBITMAP to use as the mask
SetMask(HBITMAP hbmpMask)88     void SetMask(HBITMAP hbmpMask)
89     {
90         SetMask(new wxMask((WXHBITMAP)hbmpMask));
91     }
92 
93     // return the mask
GetMask() const94     wxMask *GetMask() const { return m_bitmapMask; }
95 
96 public:
97 #if wxUSE_PALETTE
98     wxPalette     m_bitmapPalette;
99 #endif // wxUSE_PALETTE
100 
101     // MSW-specific
102     // ------------
103 
104 #if wxDEBUG_LEVEL
105     // this field is solely for error checking: we detect selecting a bitmap
106     // into more than one DC at once or deleting a bitmap still selected into a
107     // DC (both are serious programming errors under Windows)
108     wxDC         *m_selectedInto;
109 #endif // wxDEBUG_LEVEL
110 
111 #if wxUSE_WXDIB
112     // when GetRawData() is called for a DDB we need to convert it to a DIB
113     // first to be able to provide direct access to it and we cache that DIB
114     // here and convert it back to DDB when UngetRawData() is called
115     wxDIB *m_dib;
116 #endif
117 
118     // true if we have alpha transparency info and can be drawn using
119     // AlphaBlend()
120     bool m_hasAlpha;
121 
122     // true if our HBITMAP is a DIB section, false if it is a DDB
123     bool m_isDIB;
124 
125 private:
126     void Init();
127 
128     // Initialize using the given DIB but use (and take ownership of) the
129     // bitmap handle if it is valid, assuming it's a DDB. If it's not valid,
130     // use the DIB handle itself taking ownership of it (i.e. wxDIB will become
131     // invalid when this function returns even though we take it as const
132     // reference because this is how it's passed to us).
133     void InitFromDIB(const wxDIB& dib, HBITMAP hbitmap = NULL);
134 
135 
136     // optional mask for transparent drawing
137     wxMask       *m_bitmapMask;
138 
139 
140     // not implemented
141     wxBitmapRefData& operator=(const wxBitmapRefData&);
142 };
143 
144 // ----------------------------------------------------------------------------
145 // macros
146 // ----------------------------------------------------------------------------
147 
IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)148 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
149 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
150 
151 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
152 
153 // ============================================================================
154 // implementation
155 // ============================================================================
156 
157 // ----------------------------------------------------------------------------
158 // helper functions
159 // ----------------------------------------------------------------------------
160 
161 // decide whether we should create a DIB or a DDB for the given parameters
162 //
163 // NB: we always use DIBs under Windows CE as this is much simpler (even if
164 //     also less efficient...) and we obviously can't use them if there is no
165 //     DIB support compiled in at all
166 #ifdef __WXWINCE__
167     static inline bool wxShouldCreateDIB(int, int, int, WXHDC) { return true; }
168 
169     #define ALWAYS_USE_DIB
170 #elif !wxUSE_WXDIB
171     // no sense in defining wxShouldCreateDIB() as we can't compile code
172     // executed if it is true, so we have to use #if's anyhow
173     #define NEVER_USE_DIB
174 #else // wxUSE_WXDIB && !__WXWINCE__
175     static inline bool wxShouldCreateDIB(int w, int h, int d, WXHDC hdc)
176     {
177         // here is the logic:
178         //
179         //  (a) if hdc is specified, the caller explicitly wants DDB
180         //  (b) otherwise, create a DIB if depth >= 24 (we don't support 16bpp
181         //      or less DIBs anyhow)
182         //  (c) finally, create DIBs under Win9x even if the depth hasn't been
183         //      explicitly specified but the current display depth is 24 or
184         //      more and the image is "big", i.e. > 16Mb which is the
185         //      theoretical limit for DDBs under Win9x
186         //
187         // consequences (all of which seem to make sense):
188         //
189         //  (i)     by default, DDBs are created (depth == -1 usually)
190         //  (ii)    DIBs can be created by explicitly specifying the depth
191         //  (iii)   using a DC always forces creating a DDB
192         return !hdc &&
193                 (d >= 24 ||
194                     (d == -1 &&
195                         wxDIB::GetLineSize(w, wxDisplayDepth())*h > 16*1024*1024));
196     }
197 
198     #define SOMETIMES_USE_DIB
199 #endif // different DIB usage scenarious
200 
201 // ----------------------------------------------------------------------------
202 // wxBitmapRefData
203 // ----------------------------------------------------------------------------
204 
Init()205 void wxBitmapRefData::Init()
206 {
207 #if wxDEBUG_LEVEL
208     m_selectedInto = NULL;
209 #endif
210     m_bitmapMask = NULL;
211 
212     m_hBitmap = (WXHBITMAP) NULL;
213 #if wxUSE_WXDIB
214     m_dib = NULL;
215 #endif
216 
217     m_isDIB =
218     m_hasAlpha = false;
219 }
220 
wxBitmapRefData(const wxBitmapRefData & data)221 wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data)
222                : wxGDIImageRefData(data)
223 {
224     Init();
225 
226     // (deep) copy the mask if present
227     if (data.m_bitmapMask)
228         m_bitmapMask = new wxMask(*data.m_bitmapMask);
229 
230     wxASSERT_MSG( !data.m_dib,
231                     wxT("can't copy bitmap locked for raw access!") );
232 
233     m_hasAlpha = data.m_hasAlpha;
234 
235 #if wxUSE_WXDIB
236     // copy the other bitmap
237     if ( data.m_hBitmap )
238     {
239         wxDIB dib((HBITMAP)(data.m_hBitmap));
240         CopyFromDIB(dib);
241     }
242 #endif // wxUSE_WXDIB
243 }
244 
Free()245 void wxBitmapRefData::Free()
246 {
247     wxASSERT_MSG( !m_selectedInto,
248                   wxT("deleting bitmap still selected into wxMemoryDC") );
249 
250 #if wxUSE_WXDIB
251     wxASSERT_MSG( !m_dib, wxT("forgot to call wxBitmap::UngetRawData()!") );
252 #endif
253 
254     if ( m_hBitmap)
255     {
256         if ( !::DeleteObject((HBITMAP)m_hBitmap) )
257         {
258             wxLogLastError(wxT("DeleteObject(hbitmap)"));
259         }
260     }
261 
262     wxDELETE(m_bitmapMask);
263 }
264 
InitFromDIB(const wxDIB & dib,HBITMAP hbitmap)265 void wxBitmapRefData::InitFromDIB(const wxDIB& dib, HBITMAP hbitmap)
266 {
267     m_width = dib.GetWidth();
268     m_height = dib.GetHeight();
269     m_depth = dib.GetDepth();
270 
271 #if wxUSE_PALETTE
272     wxPalette *palette = dib.CreatePalette();
273     if ( palette )
274         m_bitmapPalette = *palette;
275     delete palette;
276 #endif // wxUSE_PALETTE
277 
278     if ( hbitmap )
279     {
280         // We assume it's a DDB, otherwise there would be no point in passing
281         // it to us in addition to the DIB.
282         m_isDIB = false;
283     }
284     else // No valid DDB provided
285     {
286         // Just use DIB itself.
287         m_isDIB = true;
288 
289         // Notice that we must not try to use the DIB after calling Detach() on
290         // it, e.g. this must be done after calling CreatePalette() above.
291         hbitmap = const_cast<wxDIB &>(dib).Detach();
292     }
293 
294     // In any case, take ownership of this bitmap.
295     m_hBitmap = (WXHBITMAP)hbitmap;
296 }
297 
CopyFromDIB(const wxDIB & dib)298 void wxBitmapRefData::CopyFromDIB(const wxDIB& dib)
299 {
300     wxCHECK_RET( !IsOk(), "bitmap already initialized" );
301     wxCHECK_RET( dib.IsOk(), wxT("invalid DIB in CopyFromDIB") );
302 
303     HBITMAP hbitmap;
304 #ifdef SOMETIMES_USE_DIB
305     hbitmap = dib.CreateDDB();
306 #else // ALWAYS_USE_DIB
307     hbitmap = NULL;
308 #endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
309 
310     InitFromDIB(dib, hbitmap);
311 }
312 
313 #if wxUSE_WXDIB
314 
AssignDIB(wxDIB & dib)315 bool wxBitmapRefData::AssignDIB(wxDIB& dib)
316 {
317     if ( !dib.IsOk() )
318         return false;
319 
320     Free();
321     InitFromDIB(dib);
322 
323     return true;
324 }
325 
326 #endif // wxUSE_WXDIB
327 
328 // ----------------------------------------------------------------------------
329 // wxBitmap creation
330 // ----------------------------------------------------------------------------
331 
CreateData() const332 wxGDIImageRefData *wxBitmap::CreateData() const
333 {
334     return new wxBitmapRefData;
335 }
336 
CloneGDIRefData(const wxGDIRefData * data) const337 wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const
338 {
339     return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
340 }
341 
342 // Premultiply the values of all RGBA pixels in the given range.
PremultiplyPixels(unsigned char * begin,unsigned char * end)343 static void PremultiplyPixels(unsigned char* begin, unsigned char* end)
344 {
345     for ( unsigned char* pixels = begin; pixels < end; pixels += 4 )
346     {
347         const unsigned char a = pixels[3];
348 
349         pixels[0] = ((pixels[0]*a) + 127)/255;
350         pixels[1] = ((pixels[1]*a) + 127)/255;
351         pixels[2] = ((pixels[2]*a) + 127)/255;
352     }
353 }
354 
355 // Helper which examines the alpha channel for any non-0 values and also
356 // possibly returns the DIB with premultiplied values if it does have alpha
357 // (i.e. this DIB is only filled if the function returns true).
358 //
359 // The function semantics is complicated but necessary to avoid converting to
360 // DIB twice, which is expensive for large bitmaps, yet avoid code duplication
361 // between CopyFromIconOrCursor() and MSWUpdateAlpha().
CheckAlpha(HBITMAP hbmp,HBITMAP * hdib=NULL)362 static bool CheckAlpha(HBITMAP hbmp, HBITMAP* hdib = NULL)
363 {
364     BITMAP bm;
365     if ( !::GetObject(hbmp, sizeof(bm), &bm) || (bm.bmBitsPixel != 32) )
366         return false;
367 
368     wxDIB dib(hbmp);
369     if ( !dib.IsOk() )
370         return false;
371 
372     unsigned char* pixels = dib.GetData();
373     unsigned char* const end = pixels + 4*dib.GetWidth()*dib.GetHeight();
374     for ( ; pixels < end; pixels += 4 )
375     {
376         if ( pixels[3] != 0 )
377         {
378             if ( hdib )
379             {
380                 // If we do have alpha, ensure we use premultiplied data for
381                 // our pixels as this is what the bitmaps created in other ways
382                 // do and this is necessary for e.g. AlphaBlend() to work with
383                 // this bitmap.
384                 PremultiplyPixels(dib.GetData(), end);
385 
386                 *hdib = dib.Detach();
387             }
388 
389             return true;
390         }
391     }
392 
393     return false;
394 }
395 
CopyFromIconOrCursor(const wxGDIImage & icon,wxBitmapTransparency transp)396 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon,
397                                     wxBitmapTransparency transp)
398 {
399 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
400     // it may be either HICON or HCURSOR
401     HICON hicon = (HICON)icon.GetHandle();
402 
403     ICONINFO iconInfo;
404     if ( !::GetIconInfo(hicon, &iconInfo) )
405     {
406         wxLogLastError(wxT("GetIconInfo"));
407 
408         return false;
409     }
410 
411     wxBitmapRefData *refData = new wxBitmapRefData;
412     m_refData = refData;
413 
414     int w = icon.GetWidth(),
415         h = icon.GetHeight();
416 
417     if ( iconInfo.hbmColor )
418     {
419         refData->m_width = w;
420         refData->m_height = h;
421         refData->m_depth = wxDisplayDepth();
422         refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor;
423     }
424     else // we only have monochrome icon/cursor
425     {
426         // Then we need to create our own empty bitmap, which will be modified
427         // by the mask below.
428         wxDIB dib(w, h, wxDisplayDepth());
429         if ( dib.IsOk() )
430         {
431             memset(dib.GetData(), 0, wxDIB::GetLineSize(w, dib.GetDepth())*h);
432             refData->AssignDIB(dib);
433         }
434     }
435 
436     switch ( transp )
437     {
438         default:
439             wxFAIL_MSG( wxT("unknown wxBitmapTransparency value") );
440 
441         case wxBitmapTransparency_None:
442             // nothing to do, refData->m_hasAlpha is false by default
443             break;
444 
445         case wxBitmapTransparency_Auto:
446 #if wxUSE_WXDIB
447             // If the icon is 32 bits per pixel then it may have alpha channel
448             // data, although there are some icons that are 32 bpp but have no
449             // alpha, so check for this.
450             {
451                 HBITMAP hdib = 0;
452                 if ( CheckAlpha(iconInfo.hbmColor, &hdib) )
453                 {
454                     refData->m_hasAlpha = true;
455                     ::DeleteObject(refData->m_hBitmap);
456                     refData->m_hBitmap = hdib;
457                 }
458             }
459             break;
460 #endif // wxUSE_WXDIB
461 
462         case wxBitmapTransparency_Always:
463             refData->m_hasAlpha = true;
464             break;
465     }
466 
467     if ( !refData->m_hasAlpha )
468     {
469         // the mask returned by GetIconInfo() is inverted compared to the usual
470         // wxWin convention
471         refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h));
472     }
473 
474     // delete the old one now as we don't need it any more
475     ::DeleteObject(iconInfo.hbmMask);
476 
477     return true;
478 #else // __WXMICROWIN__ || __WXWINCE__
479     wxUnusedVar(icon);
480     wxUnusedVar(transp);
481 
482     return false;
483 #endif // !__WXWINCE__/__WXWINCE__
484 }
485 
CopyFromCursor(const wxCursor & cursor,wxBitmapTransparency transp)486 bool wxBitmap::CopyFromCursor(const wxCursor& cursor, wxBitmapTransparency transp)
487 {
488     UnRef();
489 
490     if ( !cursor.IsOk() )
491         return false;
492 
493     return CopyFromIconOrCursor(cursor, transp);
494 }
495 
CopyFromIcon(const wxIcon & icon,wxBitmapTransparency transp)496 bool wxBitmap::CopyFromIcon(const wxIcon& icon, wxBitmapTransparency transp)
497 {
498     UnRef();
499 
500     if ( !icon.IsOk() )
501         return false;
502 
503     return CopyFromIconOrCursor(icon, transp);
504 }
505 
506 #if wxUSE_WXDIB
507 
CopyFromDIB(const wxDIB & dib)508 bool wxBitmap::CopyFromDIB(const wxDIB& dib)
509 {
510     wxScopedPtr<wxBitmapRefData> newData(new wxBitmapRefData);
511     newData->CopyFromDIB(dib);
512     if ( !newData->IsOk() )
513         return false;
514 
515     UnRef();
516     m_refData = newData.release();
517     return true;
518 }
519 
IsDIB() const520 bool wxBitmap::IsDIB() const
521 {
522     return GetBitmapData() && GetBitmapData()->m_isDIB;
523 }
524 
ConvertToDIB()525 bool wxBitmap::ConvertToDIB()
526 {
527     if ( IsDIB() )
528         return true;
529 
530     wxDIB dib(*this);
531     if ( !dib.IsOk() )
532         return false;
533 
534     // It is important to reuse the current GetBitmapData() instead of creating
535     // a new one, as our object identity shouldn't change just because our
536     // internal representation did, but IsSameAs() compares data pointers.
537     return GetBitmapData()->AssignDIB(dib);
538 }
539 
540 #endif // wxUSE_WXDIB
541 
~wxBitmap()542 wxBitmap::~wxBitmap()
543 {
544 }
545 
wxBitmap(const char bits[],int width,int height,int depth)546 wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
547 {
548 #ifndef __WXMICROWIN__
549     wxBitmapRefData *refData = new wxBitmapRefData;
550     m_refData = refData;
551 
552     refData->m_width = width;
553     refData->m_height = height;
554     refData->m_depth = depth;
555 
556     char *data;
557     if ( depth == 1 )
558     {
559         // we assume that it is in XBM format which is not quite the same as
560         // the format CreateBitmap() wants because the order of bytes in the
561         // line is reversed!
562         const size_t bytesPerLine = (width + 7) / 8;
563         const size_t padding = bytesPerLine % 2;
564         const size_t len = height * ( padding + bytesPerLine );
565         data = (char *)malloc(len);
566         const char *src = bits;
567         char *dst = data;
568 
569         for ( int rows = 0; rows < height; rows++ )
570         {
571             for ( size_t cols = 0; cols < bytesPerLine; cols++ )
572             {
573                 unsigned char val = *src++;
574                 unsigned char reversed = 0;
575 
576                 for ( int bit = 0; bit < 8; bit++)
577                 {
578                     reversed <<= 1;
579                     reversed |= (unsigned char)(val & 0x01);
580                     val >>= 1;
581                 }
582                 *dst++ = ~reversed;
583             }
584 
585             if ( padding )
586                 *dst++ = 0;
587         }
588     }
589     else
590     {
591         // bits should already be in Windows standard format
592         data = const_cast<char *>(bits);
593     }
594 
595     HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data);
596     if ( !hbmp )
597     {
598         wxLogLastError(wxT("CreateBitmap"));
599     }
600 
601     if ( data != bits )
602     {
603         free(data);
604     }
605 
606     SetHBITMAP((WXHBITMAP)hbmp);
607 #endif
608 }
609 
wxBitmap(int w,int h,const wxDC & dc)610 wxBitmap::wxBitmap(int w, int h, const wxDC& dc)
611 {
612     (void)Create(w, h, dc);
613 }
614 
wxBitmap(const void * data,wxBitmapType type,int width,int height,int depth)615 wxBitmap::wxBitmap(const void* data, wxBitmapType type, int width, int height, int depth)
616 {
617     (void)Create(data, type, width, height, depth);
618 }
619 
wxBitmap(const wxString & filename,wxBitmapType type)620 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
621 {
622     LoadFile(filename, type);
623 }
624 
Create(int width,int height,int depth)625 bool wxBitmap::Create(int width, int height, int depth)
626 {
627     return DoCreate(width, height, depth, 0);
628 }
629 
Create(int width,int height,const wxDC & dc)630 bool wxBitmap::Create(int width, int height, const wxDC& dc)
631 {
632     wxCHECK_MSG( dc.IsOk(), false, wxT("invalid HDC in wxBitmap::Create()") );
633 
634     const wxMSWDCImpl *impl = wxDynamicCast( dc.GetImpl(), wxMSWDCImpl );
635 
636     if (impl)
637         return DoCreate(width, height, -1, impl->GetHDC());
638     else
639         return false;
640 }
641 
DoCreate(int w,int h,int d,WXHDC hdc)642 bool wxBitmap::DoCreate(int w, int h, int d, WXHDC hdc)
643 {
644     UnRef();
645 
646     m_refData = new wxBitmapRefData;
647 
648     GetBitmapData()->m_width = w;
649     GetBitmapData()->m_height = h;
650 
651     HBITMAP hbmp    wxDUMMY_INITIALIZE(0);
652 
653 #ifndef NEVER_USE_DIB
654     if ( wxShouldCreateDIB(w, h, d, hdc) )
655     {
656         if ( d == -1 )
657         {
658             // create DIBs without alpha channel by default
659             d = 24;
660         }
661 
662         wxDIB dib(w, h, d);
663         if ( !dib.IsOk() )
664            return false;
665 
666         // don't delete the DIB section in dib object dtor
667         hbmp = dib.Detach();
668 
669         GetBitmapData()->m_isDIB = true;
670         GetBitmapData()->m_depth = d;
671     }
672     else // create a DDB
673 #endif // NEVER_USE_DIB
674     {
675 #ifndef ALWAYS_USE_DIB
676 #ifndef __WXMICROWIN__
677         if ( d > 0 )
678         {
679             hbmp = ::CreateBitmap(w, h, 1, d, NULL);
680             if ( !hbmp )
681             {
682                 wxLogLastError(wxT("CreateBitmap"));
683             }
684 
685             GetBitmapData()->m_depth = d;
686         }
687         else // d == 0, create bitmap compatible with the screen
688 #endif // !__WXMICROWIN__
689         {
690             ScreenHDC dc;
691             hbmp = ::CreateCompatibleBitmap(dc, w, h);
692             if ( !hbmp )
693             {
694                 wxLogLastError(wxT("CreateCompatibleBitmap"));
695             }
696 
697             GetBitmapData()->m_depth = wxDisplayDepth();
698         }
699 #endif // !ALWAYS_USE_DIB
700     }
701 
702     SetHBITMAP((WXHBITMAP)hbmp);
703 
704     return IsOk();
705 }
706 
707 #if wxUSE_IMAGE
708 
709 // ----------------------------------------------------------------------------
710 // wxImage to/from conversions for Microwin
711 // ----------------------------------------------------------------------------
712 
713 // Microwin versions are so different from normal ones that it really doesn't
714 // make sense to use #ifdefs inside the function bodies
715 #ifdef __WXMICROWIN__
716 
CreateFromImage(const wxImage & image,int depth,const wxDC & dc)717 bool wxBitmap::CreateFromImage(const wxImage& image, int depth, const wxDC& dc)
718 {
719     // Set this to 1 to experiment with mask code,
720     // which currently doesn't work
721     #define USE_MASKS 0
722 
723     m_refData = new wxBitmapRefData();
724 
725     // Initial attempt at a simple-minded implementation.
726     // The bitmap will always be created at the screen depth,
727     // so the 'depth' argument is ignored.
728 
729     HDC hScreenDC = ::GetDC(NULL);
730     int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL);
731 
732     HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight());
733     HBITMAP hMaskBitmap = NULL;
734     HBITMAP hOldMaskBitmap = NULL;
735     HDC hMaskDC = NULL;
736     unsigned char maskR = 0;
737     unsigned char maskG = 0;
738     unsigned char maskB = 0;
739 
740     //    printf("Created bitmap %d\n", (int) hBitmap);
741     if (hBitmap == NULL)
742     {
743         ::ReleaseDC(NULL, hScreenDC);
744         return false;
745     }
746     HDC hMemDC = ::CreateCompatibleDC(hScreenDC);
747 
748     HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap);
749     ::ReleaseDC(NULL, hScreenDC);
750 
751     // created an mono-bitmap for the possible mask
752     bool hasMask = image.HasMask();
753 
754     if ( hasMask )
755     {
756 #if USE_MASKS
757         // FIXME: we should be able to pass bpp = 1, but
758         // GdBlit can't handle a different depth
759 #if 0
760         hMaskBitmap = ::CreateBitmap( (WORD)image.GetWidth(), (WORD)image.GetHeight(), 1, 1, NULL );
761 #else
762         hMaskBitmap = ::CreateCompatibleBitmap( hMemDC, (WORD)image.GetWidth(), (WORD)image.GetHeight());
763 #endif
764         maskR = image.GetMaskRed();
765         maskG = image.GetMaskGreen();
766         maskB = image.GetMaskBlue();
767 
768         if (!hMaskBitmap)
769         {
770             hasMask = false;
771         }
772         else
773         {
774             hScreenDC = ::GetDC(NULL);
775             hMaskDC = ::CreateCompatibleDC(hScreenDC);
776            ::ReleaseDC(NULL, hScreenDC);
777 
778             hOldMaskBitmap = ::SelectObject( hMaskDC, hMaskBitmap);
779         }
780 #else
781         hasMask = false;
782 #endif
783     }
784 
785     int i, j;
786     for (i = 0; i < image.GetWidth(); i++)
787     {
788         for (j = 0; j < image.GetHeight(); j++)
789         {
790             unsigned char red = image.GetRed(i, j);
791             unsigned char green = image.GetGreen(i, j);
792             unsigned char blue = image.GetBlue(i, j);
793 
794             ::SetPixel(hMemDC, i, j, PALETTERGB(red, green, blue));
795 
796             if (hasMask)
797             {
798                 // scan the bitmap for the transparent colour and set the corresponding
799                 // pixels in the mask to BLACK and the rest to WHITE
800                 if (maskR == red && maskG == green && maskB == blue)
801                     ::SetPixel(hMaskDC, i, j, PALETTERGB(0, 0, 0));
802                 else
803                     ::SetPixel(hMaskDC, i, j, PALETTERGB(255, 255, 255));
804             }
805         }
806     }
807 
808     ::SelectObject(hMemDC, hOldBitmap);
809     ::DeleteDC(hMemDC);
810     if (hasMask)
811     {
812         ::SelectObject(hMaskDC, hOldMaskBitmap);
813         ::DeleteDC(hMaskDC);
814 
815         ((wxBitmapRefData*)m_refData)->SetMask(hMaskBitmap);
816     }
817 
818     SetWidth(image.GetWidth());
819     SetHeight(image.GetHeight());
820     SetDepth(screenDepth);
821     SetHBITMAP( (WXHBITMAP) hBitmap );
822 
823 #if wxUSE_PALETTE
824     // Copy the palette from the source image
825     SetPalette(image.GetPalette());
826 #endif // wxUSE_PALETTE
827 
828     return true;
829 }
830 
ConvertToImage() const831 wxImage wxBitmap::ConvertToImage() const
832 {
833     // Initial attempt at a simple-minded implementation.
834     // The bitmap will always be created at the screen depth,
835     // so the 'depth' argument is ignored.
836     // TODO: transparency (create a mask image)
837 
838     if (!IsOk())
839     {
840         wxFAIL_MSG( wxT("bitmap is invalid") );
841         return wxNullImage;
842     }
843 
844     wxImage image;
845 
846     wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
847 
848     // create an wxImage object
849     int width = GetWidth();
850     int height = GetHeight();
851     image.Create( width, height );
852     unsigned char *data = image.GetData();
853     if( !data )
854     {
855         wxFAIL_MSG( wxT("could not allocate data for image") );
856         return wxNullImage;
857     }
858 
859     HDC hScreenDC = ::GetDC(NULL);
860 
861     HDC hMemDC = ::CreateCompatibleDC(hScreenDC);
862     ::ReleaseDC(NULL, hScreenDC);
863 
864     HBITMAP hBitmap = (HBITMAP) GetHBITMAP();
865 
866     HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap);
867 
868     int i, j;
869     for (i = 0; i < GetWidth(); i++)
870     {
871         for (j = 0; j < GetHeight(); j++)
872         {
873             COLORREF color = ::GetPixel(hMemDC, i, j);
874             unsigned char red = GetRValue(color);
875             unsigned char green = GetGValue(color);
876             unsigned char blue = GetBValue(color);
877 
878             image.SetRGB(i, j, red, green, blue);
879         }
880     }
881 
882     ::SelectObject(hMemDC, hOldBitmap);
883     ::DeleteDC(hMemDC);
884 
885 #if wxUSE_PALETTE
886     // Copy the palette from the source image
887     if (GetPalette())
888         image.SetPalette(* GetPalette());
889 #endif // wxUSE_PALETTE
890 
891     return image;
892 }
893 
894 #endif // __WXMICROWIN__
895 
896 // ----------------------------------------------------------------------------
897 // wxImage to/from conversions
898 // ----------------------------------------------------------------------------
899 
CreateFromImage(const wxImage & image,int depth)900 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
901 {
902     return CreateFromImage(image, depth, 0);
903 }
904 
CreateFromImage(const wxImage & image,const wxDC & dc)905 bool wxBitmap::CreateFromImage(const wxImage& image, const wxDC& dc)
906 {
907     wxCHECK_MSG( dc.IsOk(), false,
908                     wxT("invalid HDC in wxBitmap::CreateFromImage()") );
909 
910     const wxMSWDCImpl *impl = wxDynamicCast( dc.GetImpl(), wxMSWDCImpl );
911 
912     if (impl)
913         return CreateFromImage(image, -1, impl->GetHDC());
914     else
915         return false;
916 }
917 
918 #if wxUSE_WXDIB
919 
CreateFromImage(const wxImage & image,int depth,WXHDC hdc)920 bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc)
921 {
922     wxCHECK_MSG( image.IsOk(), false, wxT("invalid image") );
923 
924     UnRef();
925 
926     // first convert the image to DIB
927     const int h = image.GetHeight();
928     const int w = image.GetWidth();
929 
930     wxDIB dib(image);
931     if ( !dib.IsOk() )
932         return false;
933 
934     const bool hasAlpha = image.HasAlpha();
935 
936     if (depth == -1)
937       depth = dib.GetDepth();
938 
939     // store the bitmap parameters
940     wxBitmapRefData * const refData = new wxBitmapRefData;
941     refData->m_width = w;
942     refData->m_height = h;
943     refData->m_hasAlpha = hasAlpha;
944     refData->m_depth = depth;
945 
946     m_refData = refData;
947 
948 
949     // next either store DIB as is or create a DDB from it
950     HBITMAP hbitmap     wxDUMMY_INITIALIZE(0);
951 
952     // are we going to use DIB?
953     //
954     // NB: DDBs don't support alpha so if we have alpha channel we must use DIB
955     if ( hasAlpha || wxShouldCreateDIB(w, h, depth, hdc) )
956     {
957         // don't delete the DIB section in dib object dtor
958         hbitmap = dib.Detach();
959 
960         refData->m_isDIB = true;
961     }
962 #ifndef ALWAYS_USE_DIB
963     else // we need to convert DIB to DDB
964     {
965         hbitmap = dib.CreateDDB((HDC)hdc);
966     }
967 #endif // !ALWAYS_USE_DIB
968 
969     // validate this object
970     SetHBITMAP((WXHBITMAP)hbitmap);
971 
972     // finally also set the mask if we have one
973     if ( image.HasMask() )
974     {
975         const size_t len  = 2*((w+15)/16);
976         BYTE *src  = image.GetData();
977         BYTE *data = new BYTE[h*len];
978         memset(data, 0, h*len);
979         BYTE r = image.GetMaskRed(),
980              g = image.GetMaskGreen(),
981              b = image.GetMaskBlue();
982         BYTE *dst = data;
983         for ( int y = 0; y < h; y++, dst += len )
984         {
985             BYTE *dstLine = dst;
986             BYTE mask = 0x80;
987             for ( int x = 0; x < w; x++, src += 3 )
988             {
989                 if (src[0] != r || src[1] != g || src[2] != b)
990                     *dstLine |= mask;
991 
992                 if ( (mask >>= 1) == 0 )
993                 {
994                     dstLine++;
995                     mask = 0x80;
996                 }
997             }
998         }
999 
1000         hbitmap = ::CreateBitmap(w, h, 1, 1, data);
1001         if ( !hbitmap )
1002         {
1003             wxLogLastError(wxT("CreateBitmap(mask)"));
1004         }
1005         else
1006         {
1007             SetMask(new wxMask((WXHBITMAP)hbitmap));
1008         }
1009 
1010         delete[] data;
1011     }
1012 
1013     return true;
1014 }
1015 
ConvertToImage() const1016 wxImage wxBitmap::ConvertToImage() const
1017 {
1018     // convert DDB to DIB
1019     wxDIB dib(*this);
1020 
1021     if ( !dib.IsOk() )
1022     {
1023         return wxNullImage;
1024     }
1025 
1026     // and then DIB to our wxImage
1027     wxImage image = dib.ConvertToImage();
1028     if ( !image.IsOk() )
1029     {
1030         return wxNullImage;
1031     }
1032 
1033     // now do the same for the mask, if we have any
1034     HBITMAP hbmpMask = GetMask() ? (HBITMAP) GetMask()->GetMaskBitmap() : NULL;
1035     if ( hbmpMask )
1036     {
1037         wxDIB dibMask(hbmpMask);
1038         if ( dibMask.IsOk() )
1039         {
1040             // TODO: use wxRawBitmap to iterate over DIB
1041 
1042             // we hard code the mask colour for now but we could also make an
1043             // effort (and waste time) to choose a colour not present in the
1044             // image already to avoid having to fudge the pixels below --
1045             // whether it's worth to do it is unclear however
1046             static const int MASK_RED = 1;
1047             static const int MASK_GREEN = 2;
1048             static const int MASK_BLUE = 3;
1049             static const int MASK_BLUE_REPLACEMENT = 2;
1050 
1051             const int h = dibMask.GetHeight();
1052             const int w = dibMask.GetWidth();
1053             const int bpp = dibMask.GetDepth();
1054             const int maskBytesPerPixel = bpp >> 3;
1055             const int maskBytesPerLine = wxDIB::GetLineSize(w, bpp);
1056             unsigned char *data = image.GetData();
1057 
1058             // remember that DIBs are stored in bottom to top order
1059             unsigned char *
1060                 maskLineStart = dibMask.GetData() + ((h - 1) * maskBytesPerLine);
1061 
1062             for ( int y = 0; y < h; y++, maskLineStart -= maskBytesPerLine )
1063             {
1064                 // traverse one mask DIB line
1065                 unsigned char *mask = maskLineStart;
1066                 for ( int x = 0; x < w; x++, mask += maskBytesPerPixel )
1067                 {
1068                     // should this pixel be transparent?
1069                     if ( *mask )
1070                     {
1071                         // no, check that it isn't transparent by accident
1072                         if ( (data[0] == MASK_RED) &&
1073                                 (data[1] == MASK_GREEN) &&
1074                                     (data[2] == MASK_BLUE) )
1075                         {
1076                             // we have to fudge the colour a bit to prevent
1077                             // this pixel from appearing transparent
1078                             data[2] = MASK_BLUE_REPLACEMENT;
1079                         }
1080 
1081                         data += 3;
1082                     }
1083                     else // yes, transparent pixel
1084                     {
1085                         *data++ = MASK_RED;
1086                         *data++ = MASK_GREEN;
1087                         *data++ = MASK_BLUE;
1088                     }
1089                 }
1090             }
1091 
1092             image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
1093         }
1094     }
1095 
1096     return image;
1097 }
1098 
1099 #else // !wxUSE_WXDIB
1100 
1101 bool
CreateFromImage(const wxImage & WXUNUSED (image),int WXUNUSED (depth),WXHDC WXUNUSED (hdc))1102 wxBitmap::CreateFromImage(const wxImage& WXUNUSED(image),
1103                           int WXUNUSED(depth),
1104                           WXHDC WXUNUSED(hdc))
1105 {
1106     return false;
1107 }
1108 
ConvertToImage() const1109 wxImage wxBitmap::ConvertToImage() const
1110 {
1111     return wxImage();
1112 }
1113 
1114 #endif // wxUSE_WXDIB/!wxUSE_WXDIB
1115 
1116 #endif // wxUSE_IMAGE
1117 
1118 // ----------------------------------------------------------------------------
1119 // loading and saving bitmaps
1120 // ----------------------------------------------------------------------------
1121 
LoadFile(const wxString & filename,wxBitmapType type)1122 bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
1123 {
1124     UnRef();
1125 
1126     wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
1127 
1128     if ( handler )
1129     {
1130         m_refData = new wxBitmapRefData;
1131 
1132         return handler->LoadFile(this, filename, type, -1, -1);
1133     }
1134 #if wxUSE_IMAGE && wxUSE_WXDIB
1135     else // no bitmap handler found
1136     {
1137         wxImage image;
1138         if ( image.LoadFile( filename, type ) && image.IsOk() )
1139         {
1140             *this = wxBitmap(image);
1141 
1142             return true;
1143         }
1144     }
1145 #endif // wxUSE_IMAGE
1146 
1147     return false;
1148 }
1149 
Create(const void * data,wxBitmapType type,int width,int height,int depth)1150 bool wxBitmap::Create(const void* data, wxBitmapType type, int width, int height, int depth)
1151 {
1152     UnRef();
1153 
1154     wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
1155 
1156     if ( !handler )
1157     {
1158         wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type);
1159 
1160         return false;
1161     }
1162 
1163     m_refData = new wxBitmapRefData;
1164 
1165     return handler->Create(this, data, type, width, height, depth);
1166 }
1167 
SaveFile(const wxString & filename,wxBitmapType type,const wxPalette * palette) const1168 bool wxBitmap::SaveFile(const wxString& filename,
1169                         wxBitmapType type,
1170                         const wxPalette *palette) const
1171 {
1172     wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
1173 
1174     if ( handler )
1175     {
1176         return handler->SaveFile(this, filename, type, palette);
1177     }
1178 #if wxUSE_IMAGE && wxUSE_WXDIB
1179     else // no bitmap handler found
1180     {
1181         // FIXME what about palette? shouldn't we use it?
1182         wxImage image = ConvertToImage();
1183         if ( image.IsOk() )
1184         {
1185             return image.SaveFile(filename, type);
1186         }
1187     }
1188 #endif // wxUSE_IMAGE
1189 
1190     return false;
1191 }
1192 
1193 // ----------------------------------------------------------------------------
1194 // sub bitmap extraction
1195 // ----------------------------------------------------------------------------
GetSubBitmap(const wxRect & rect) const1196 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect ) const
1197 {
1198         MemoryHDC dcSrc;
1199         SelectInHDC selectSrc(dcSrc, GetHbitmap());
1200         return GetSubBitmapOfHDC( rect, (WXHDC)dcSrc );
1201 }
1202 
GetSubBitmapOfHDC(const wxRect & rect,WXHDC hdc) const1203 wxBitmap wxBitmap::GetSubBitmapOfHDC( const wxRect& rect, WXHDC hdc ) const
1204 {
1205     wxCHECK_MSG( IsOk() &&
1206                  (rect.x >= 0) && (rect.y >= 0) &&
1207                  (rect.x+rect.width <= GetWidth()) &&
1208                  (rect.y+rect.height <= GetHeight()),
1209                  wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
1210 
1211     wxBitmap ret( rect.width, rect.height, GetDepth() );
1212     wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
1213 
1214 #ifndef __WXMICROWIN__
1215     // handle alpha channel, if any
1216     if (HasAlpha())
1217         ret.UseAlpha();
1218 
1219     // copy bitmap data
1220     MemoryHDC dcSrc,
1221               dcDst;
1222 
1223     {
1224         SelectInHDC selectDst(dcDst, GetHbitmapOf(ret));
1225 
1226         if ( !selectDst )
1227         {
1228             wxLogLastError(wxT("SelectObject(destBitmap)"));
1229         }
1230 
1231         if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
1232                        (HDC)hdc, rect.x, rect.y, SRCCOPY) )
1233         {
1234             wxLogLastError(wxT("BitBlt"));
1235         }
1236     }
1237 
1238     // copy mask if there is one
1239     if ( GetMask() )
1240     {
1241         HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0);
1242 
1243         SelectInHDC selectSrc(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()),
1244                     selectDst(dcDst, hbmpMask);
1245 
1246         if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
1247                        dcSrc, rect.x, rect.y, SRCCOPY) )
1248         {
1249             wxLogLastError(wxT("BitBlt"));
1250         }
1251 
1252         wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
1253         ret.SetMask(mask);
1254     }
1255 #endif // !__WXMICROWIN__
1256 
1257     return ret;
1258 }
1259 
1260 // ----------------------------------------------------------------------------
1261 // wxBitmap accessors
1262 // ----------------------------------------------------------------------------
1263 
1264 #if wxUSE_PALETTE
GetPalette() const1265 wxPalette* wxBitmap::GetPalette() const
1266 {
1267     return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette
1268                            : NULL;
1269 }
1270 #endif
1271 
GetMask() const1272 wxMask *wxBitmap::GetMask() const
1273 {
1274     return GetBitmapData() ? GetBitmapData()->GetMask() : NULL;
1275 }
1276 
GetSelectedInto() const1277 wxDC *wxBitmap::GetSelectedInto() const
1278 {
1279 #if wxDEBUG_LEVEL
1280     return GetBitmapData() ? GetBitmapData()->m_selectedInto : NULL;
1281 #else
1282     return NULL;
1283 #endif
1284 }
1285 
UseAlpha()1286 void wxBitmap::UseAlpha()
1287 {
1288     if ( GetBitmapData() )
1289         GetBitmapData()->m_hasAlpha = true;
1290 }
1291 
ResetAlpha()1292 void wxBitmap::ResetAlpha()
1293 {
1294     if ( GetBitmapData() )
1295         GetBitmapData()->m_hasAlpha = false;
1296 }
1297 
HasAlpha() const1298 bool wxBitmap::HasAlpha() const
1299 {
1300     return GetBitmapData() && GetBitmapData()->m_hasAlpha;
1301 }
1302 
MSWUpdateAlpha()1303 void wxBitmap::MSWUpdateAlpha()
1304 {
1305     if ( CheckAlpha(GetHbitmap()) )
1306         GetBitmapData()->m_hasAlpha = true;
1307 }
1308 
1309 // ----------------------------------------------------------------------------
1310 // wxBitmap setters
1311 // ----------------------------------------------------------------------------
1312 
SetSelectedInto(wxDC * dc)1313 void wxBitmap::SetSelectedInto(wxDC *dc)
1314 {
1315 #if wxDEBUG_LEVEL
1316     if ( GetBitmapData() )
1317         GetBitmapData()->m_selectedInto = dc;
1318 #else
1319     wxUnusedVar(dc);
1320 #endif
1321 }
1322 
1323 #if wxUSE_PALETTE
1324 
SetPalette(const wxPalette & palette)1325 void wxBitmap::SetPalette(const wxPalette& palette)
1326 {
1327     AllocExclusive();
1328 
1329     GetBitmapData()->m_bitmapPalette = palette;
1330 }
1331 
1332 #endif // wxUSE_PALETTE
1333 
SetMask(wxMask * mask)1334 void wxBitmap::SetMask(wxMask *mask)
1335 {
1336     AllocExclusive();
1337 
1338     GetBitmapData()->SetMask(mask);
1339 }
1340 
1341 // ----------------------------------------------------------------------------
1342 // raw bitmap access support
1343 // ----------------------------------------------------------------------------
1344 
1345 #ifdef wxHAS_RAW_BITMAP
1346 
GetRawData(wxPixelDataBase & data,int bpp)1347 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
1348 {
1349 #if wxUSE_WXDIB
1350     if ( !IsOk() )
1351     {
1352         // no bitmap, no data (raw or otherwise)
1353         return NULL;
1354     }
1355 
1356     // if we're already a DIB we can access our data directly, but if not we
1357     // need to convert this DDB to a DIB section and use it for raw access and
1358     // then convert it back
1359     HBITMAP hDIB;
1360     if ( !GetBitmapData()->m_isDIB )
1361     {
1362         wxCHECK_MSG( !GetBitmapData()->m_dib, NULL,
1363                         wxT("GetRawData() may be called only once") );
1364 
1365         wxDIB *dib = new wxDIB(*this);
1366         if ( !dib->IsOk() )
1367         {
1368             delete dib;
1369 
1370             return NULL;
1371         }
1372 
1373         // we'll free it in UngetRawData()
1374         GetBitmapData()->m_dib = dib;
1375 
1376         hDIB = dib->GetHandle();
1377     }
1378     else // we're a DIB
1379     {
1380         hDIB = GetHbitmap();
1381     }
1382 
1383     DIBSECTION ds;
1384     if ( ::GetObject(hDIB, sizeof(ds), &ds) != sizeof(DIBSECTION) )
1385     {
1386         wxFAIL_MSG( wxT("failed to get DIBSECTION from a DIB?") );
1387 
1388         return NULL;
1389     }
1390 
1391     // check that the bitmap is in correct format
1392     if ( ds.dsBm.bmBitsPixel != bpp )
1393     {
1394         wxFAIL_MSG( wxT("incorrect bitmap type in wxBitmap::GetRawData()") );
1395 
1396         return NULL;
1397     }
1398 
1399     // ok, store the relevant info in wxPixelDataBase
1400     const LONG h = ds.dsBm.bmHeight;
1401 
1402     data.m_width = ds.dsBm.bmWidth;
1403     data.m_height = h;
1404 
1405     // remember that DIBs are stored in top to bottom order!
1406     // (We can't just use ds.dsBm.bmWidthBytes here, because it isn't always a
1407     // multiple of 2, as required by the documentation.  So we use the official
1408     // formula, which we already use elsewhere.)
1409     const LONG bytesPerRow =
1410         wxDIB::GetLineSize(ds.dsBm.bmWidth, ds.dsBm.bmBitsPixel);
1411     data.m_stride = -bytesPerRow;
1412 
1413     char *bits = (char *)ds.dsBm.bmBits;
1414     if ( h > 1 )
1415     {
1416         bits += (h - 1)*bytesPerRow;
1417     }
1418 
1419     return bits;
1420 #else
1421     return NULL;
1422 #endif
1423 }
1424 
UngetRawData(wxPixelDataBase & dataBase)1425 void wxBitmap::UngetRawData(wxPixelDataBase& dataBase)
1426 {
1427 #if wxUSE_WXDIB
1428     if ( !IsOk() )
1429         return;
1430 
1431     if ( !&dataBase )
1432     {
1433         // invalid data, don't crash -- but don't assert neither as we're
1434         // called automatically from wxPixelDataBase dtor and so there is no
1435         // way to prevent this from happening
1436         return;
1437     }
1438 
1439     // if we're a DDB we need to convert DIB back to DDB now to make the
1440     // changes made via raw bitmap access effective
1441     if ( !GetBitmapData()->m_isDIB )
1442     {
1443         wxDIB *dib = GetBitmapData()->m_dib;
1444         GetBitmapData()->m_dib = NULL;
1445 
1446         // TODO: convert
1447 
1448         delete dib;
1449     }
1450 #endif // wxUSE_WXDIB
1451 }
1452 #endif // wxHAS_RAW_BITMAP
1453 
1454 // ----------------------------------------------------------------------------
1455 // wxMask
1456 // ----------------------------------------------------------------------------
1457 
wxMask()1458 wxMask::wxMask()
1459 {
1460     m_maskBitmap = 0;
1461 }
1462 
1463 // Copy constructor
wxMask(const wxMask & mask)1464 wxMask::wxMask(const wxMask &mask)
1465       : wxObject()
1466 {
1467     BITMAP bmp;
1468 
1469     HDC srcDC = CreateCompatibleDC(0);
1470     HDC destDC = CreateCompatibleDC(0);
1471 
1472     // GetBitmapDimensionEx won't work if SetBitmapDimensionEx wasn't used
1473     // so we'll use GetObject() API here:
1474     if (::GetObject((HGDIOBJ)mask.m_maskBitmap, sizeof(bmp), &bmp) == 0)
1475     {
1476         wxFAIL_MSG(wxT("Cannot retrieve the dimensions of the wxMask to copy"));
1477         return;
1478     }
1479 
1480     // create our HBITMAP
1481     int w = bmp.bmWidth, h = bmp.bmHeight;
1482     m_maskBitmap = (WXHBITMAP)CreateCompatibleBitmap(srcDC, w, h);
1483 
1484     // copy the mask's HBITMAP into our HBITMAP
1485     SelectObject(srcDC, (HBITMAP) mask.m_maskBitmap);
1486     SelectObject(destDC, (HBITMAP) m_maskBitmap);
1487 
1488     BitBlt(destDC, 0, 0, w, h, srcDC, 0, 0, SRCCOPY);
1489 
1490     SelectObject(srcDC, 0);
1491     DeleteDC(srcDC);
1492     SelectObject(destDC, 0);
1493     DeleteDC(destDC);
1494 }
1495 
1496 // Construct a mask from a bitmap and a colour indicating
1497 // the transparent area
wxMask(const wxBitmap & bitmap,const wxColour & colour)1498 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
1499 {
1500     m_maskBitmap = 0;
1501     Create(bitmap, colour);
1502 }
1503 
1504 // Construct a mask from a bitmap and a palette index indicating
1505 // the transparent area
wxMask(const wxBitmap & bitmap,int paletteIndex)1506 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
1507 {
1508     m_maskBitmap = 0;
1509     Create(bitmap, paletteIndex);
1510 }
1511 
1512 // Construct a mask from a mono bitmap (copies the bitmap).
wxMask(const wxBitmap & bitmap)1513 wxMask::wxMask(const wxBitmap& bitmap)
1514 {
1515     m_maskBitmap = 0;
1516     Create(bitmap);
1517 }
1518 
~wxMask()1519 wxMask::~wxMask()
1520 {
1521     if ( m_maskBitmap )
1522         ::DeleteObject((HBITMAP) m_maskBitmap);
1523 }
1524 
1525 // Create a mask from a mono bitmap (copies the bitmap).
Create(const wxBitmap & bitmap)1526 bool wxMask::Create(const wxBitmap& bitmap)
1527 {
1528 #ifndef __WXMICROWIN__
1529     wxCHECK_MSG( bitmap.IsOk() && bitmap.GetDepth() == 1, false,
1530                  wxT("can't create mask from invalid or not monochrome bitmap") );
1531 
1532     if ( m_maskBitmap )
1533     {
1534         ::DeleteObject((HBITMAP) m_maskBitmap);
1535         m_maskBitmap = 0;
1536     }
1537 
1538     m_maskBitmap = (WXHBITMAP) CreateBitmap(
1539                                             bitmap.GetWidth(),
1540                                             bitmap.GetHeight(),
1541                                             1, 1, 0
1542                                            );
1543     HDC srcDC = CreateCompatibleDC(0);
1544     SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
1545     HDC destDC = CreateCompatibleDC(0);
1546     SelectObject(destDC, (HBITMAP) m_maskBitmap);
1547     BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY);
1548     SelectObject(srcDC, 0);
1549     DeleteDC(srcDC);
1550     SelectObject(destDC, 0);
1551     DeleteDC(destDC);
1552     return true;
1553 #else
1554     wxUnusedVar(bitmap);
1555     return false;
1556 #endif
1557 }
1558 
1559 // Create a mask from a bitmap and a palette index indicating
1560 // the transparent area
Create(const wxBitmap & bitmap,int paletteIndex)1561 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
1562 {
1563     if ( m_maskBitmap )
1564     {
1565         ::DeleteObject((HBITMAP) m_maskBitmap);
1566         m_maskBitmap = 0;
1567     }
1568 
1569 #if wxUSE_PALETTE
1570     if (bitmap.IsOk() && bitmap.GetPalette()->IsOk())
1571     {
1572         unsigned char red, green, blue;
1573         if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
1574         {
1575             wxColour transparentColour(red, green, blue);
1576             return Create(bitmap, transparentColour);
1577         }
1578     }
1579 #endif // wxUSE_PALETTE
1580 
1581     return false;
1582 }
1583 
1584 // Create a mask from a bitmap and a colour indicating
1585 // the transparent area
Create(const wxBitmap & bitmap,const wxColour & colour)1586 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1587 {
1588 #ifndef __WXMICROWIN__
1589     wxCHECK_MSG( bitmap.IsOk(), false, wxT("invalid bitmap in wxMask::Create") );
1590 
1591     if ( m_maskBitmap )
1592     {
1593         ::DeleteObject((HBITMAP) m_maskBitmap);
1594         m_maskBitmap = 0;
1595     }
1596 
1597     int width = bitmap.GetWidth(),
1598         height = bitmap.GetHeight();
1599 
1600     // scan the bitmap for the transparent colour and set the corresponding
1601     // pixels in the mask to BLACK and the rest to WHITE
1602     COLORREF maskColour = wxColourToPalRGB(colour);
1603     m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0);
1604 
1605     HDC srcDC = ::CreateCompatibleDC(NULL);
1606     HDC destDC = ::CreateCompatibleDC(NULL);
1607     if ( !srcDC || !destDC )
1608     {
1609         wxLogLastError(wxT("CreateCompatibleDC"));
1610     }
1611 
1612     bool ok = true;
1613 
1614     // SelectObject() will fail
1615     wxASSERT_MSG( !bitmap.GetSelectedInto(),
1616                   wxT("bitmap can't be selected in another DC") );
1617 
1618     HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap));
1619     if ( !hbmpSrcOld )
1620     {
1621         wxLogLastError(wxT("SelectObject"));
1622 
1623         ok = false;
1624     }
1625 
1626     HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap);
1627     if ( !hbmpDstOld )
1628     {
1629         wxLogLastError(wxT("SelectObject"));
1630 
1631         ok = false;
1632     }
1633 
1634     if ( ok )
1635     {
1636         // this will create a monochrome bitmap with 0 points for the pixels
1637         // which have the same value as the background colour and 1 for the
1638         // others
1639         ::SetBkColor(srcDC, maskColour);
1640         ::BitBlt(destDC, 0, 0, width, height, srcDC, 0, 0, NOTSRCCOPY);
1641     }
1642 
1643     ::SelectObject(srcDC, hbmpSrcOld);
1644     ::DeleteDC(srcDC);
1645     ::SelectObject(destDC, hbmpDstOld);
1646     ::DeleteDC(destDC);
1647 
1648     return ok;
1649 #else // __WXMICROWIN__
1650     wxUnusedVar(bitmap);
1651     wxUnusedVar(colour);
1652     return false;
1653 #endif // __WXMICROWIN__/!__WXMICROWIN__
1654 }
1655 
GetBitmap() const1656 wxBitmap wxMask::GetBitmap() const
1657 {
1658     wxBitmap bmp;
1659     bmp.SetHBITMAP(m_maskBitmap);
1660     return bmp;
1661 }
1662 
1663 // ----------------------------------------------------------------------------
1664 // wxBitmapHandler
1665 // ----------------------------------------------------------------------------
1666 
Create(wxGDIImage * image,const void * data,wxBitmapType type,int width,int height,int depth)1667 bool wxBitmapHandler::Create(wxGDIImage *image,
1668                              const void* data,
1669                              wxBitmapType type,
1670                              int width, int height, int depth)
1671 {
1672     wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1673 
1674     return bitmap && Create(bitmap, data, type, width, height, depth);
1675 }
1676 
Load(wxGDIImage * image,const wxString & name,wxBitmapType type,int width,int height)1677 bool wxBitmapHandler::Load(wxGDIImage *image,
1678                            const wxString& name,
1679                            wxBitmapType type,
1680                            int width, int height)
1681 {
1682     wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1683 
1684     return bitmap && LoadFile(bitmap, name, type, width, height);
1685 }
1686 
Save(const wxGDIImage * image,const wxString & name,wxBitmapType type) const1687 bool wxBitmapHandler::Save(const wxGDIImage *image,
1688                            const wxString& name,
1689                            wxBitmapType type) const
1690 {
1691     wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1692 
1693     return bitmap && SaveFile(bitmap, name, type);
1694 }
1695 
Create(wxBitmap * WXUNUSED (bitmap),const void * WXUNUSED (data),wxBitmapType WXUNUSED (type),int WXUNUSED (width),int WXUNUSED (height),int WXUNUSED (depth))1696 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap),
1697                              const void* WXUNUSED(data),
1698                              wxBitmapType WXUNUSED(type),
1699                              int WXUNUSED(width),
1700                              int WXUNUSED(height),
1701                              int WXUNUSED(depth))
1702 {
1703     return false;
1704 }
1705 
LoadFile(wxBitmap * WXUNUSED (bitmap),const wxString & WXUNUSED (name),wxBitmapType WXUNUSED (type),int WXUNUSED (desiredWidth),int WXUNUSED (desiredHeight))1706 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap),
1707                                const wxString& WXUNUSED(name),
1708                                wxBitmapType WXUNUSED(type),
1709                                int WXUNUSED(desiredWidth),
1710                                int WXUNUSED(desiredHeight))
1711 {
1712     return false;
1713 }
1714 
SaveFile(const wxBitmap * WXUNUSED (bitmap),const wxString & WXUNUSED (name),wxBitmapType WXUNUSED (type),const wxPalette * WXUNUSED (palette)) const1715 bool wxBitmapHandler::SaveFile(const wxBitmap *WXUNUSED(bitmap),
1716                                const wxString& WXUNUSED(name),
1717                                wxBitmapType WXUNUSED(type),
1718                                const wxPalette *WXUNUSED(palette)) const
1719 {
1720     return false;
1721 }
1722 
1723 // ----------------------------------------------------------------------------
1724 // global helper functions implemented here
1725 // ----------------------------------------------------------------------------
1726 
1727 // helper of wxBitmapToHICON/HCURSOR
1728 static
wxBitmapToIconOrCursor(const wxBitmap & bmp,bool iconWanted,int hotSpotX,int hotSpotY)1729 HICON wxBitmapToIconOrCursor(const wxBitmap& bmp,
1730                              bool iconWanted,
1731                              int hotSpotX,
1732                              int hotSpotY)
1733 {
1734     if ( !bmp.IsOk() )
1735     {
1736         // we can't create an icon/cursor form nothing
1737         return 0;
1738     }
1739 
1740     if ( bmp.HasAlpha() )
1741     {
1742         HBITMAP hbmp;
1743 
1744 #if wxUSE_WXDIB && wxUSE_IMAGE
1745         // CreateIconIndirect() requires non-pre-multiplied pixel data on input
1746         // as it does pre-multiplication internally itself so we need to create
1747         // a special DIB in such format to pass to it. This is inefficient but
1748         // better than creating an icon with wrong colours.
1749         AutoHBITMAP hbmpRelease;
1750         hbmp = wxDIB(bmp.ConvertToImage(),
1751                      wxDIB::PixelFormat_NotPreMultiplied).Detach();
1752         hbmpRelease.Init(hbmp);
1753 #else // !(wxUSE_WXDIB && wxUSE_IMAGE)
1754         hbmp = GetHbitmapOf(bmp);
1755 #endif // wxUSE_WXDIB && wxUSE_IMAGE
1756 
1757         // Create an empty mask bitmap.
1758         // it doesn't seem to work if we mess with the mask at all.
1759         AutoHBITMAP
1760             hMonoBitmap(CreateBitmap(bmp.GetWidth(),bmp.GetHeight(),1,1,NULL));
1761 
1762         ICONINFO iconInfo;
1763         wxZeroMemory(iconInfo);
1764         iconInfo.fIcon = iconWanted;  // do we want an icon or a cursor?
1765         if ( !iconWanted )
1766         {
1767             iconInfo.xHotspot = hotSpotX;
1768             iconInfo.yHotspot = hotSpotY;
1769         }
1770 
1771         iconInfo.hbmMask = hMonoBitmap;
1772         iconInfo.hbmColor = hbmp;
1773 
1774         return ::CreateIconIndirect(&iconInfo);
1775     }
1776 
1777     wxMask* mask = bmp.GetMask();
1778 
1779     if ( !mask )
1780     {
1781         // we must have a mask for an icon, so even if it's probably incorrect,
1782         // do create it (grey is the "standard" transparent colour)
1783         mask = new wxMask(bmp, *wxLIGHT_GREY);
1784     }
1785 
1786     ICONINFO iconInfo;
1787     wxZeroMemory(iconInfo);
1788     iconInfo.fIcon = iconWanted;  // do we want an icon or a cursor?
1789     if ( !iconWanted )
1790     {
1791         iconInfo.xHotspot = hotSpotX;
1792         iconInfo.yHotspot = hotSpotY;
1793     }
1794 
1795     AutoHBITMAP hbmpMask(wxInvertMask((HBITMAP)mask->GetMaskBitmap()));
1796     iconInfo.hbmMask = hbmpMask;
1797     iconInfo.hbmColor = GetHbitmapOf(bmp);
1798 
1799     // black out the transparent area to preserve background colour, because
1800     // Windows blits the original bitmap using SRCINVERT (XOR) after applying
1801     // the mask to the dest rect.
1802     {
1803         MemoryHDC dcSrc, dcDst;
1804         SelectInHDC selectMask(dcSrc, (HBITMAP)mask->GetMaskBitmap()),
1805                     selectBitmap(dcDst, iconInfo.hbmColor);
1806 
1807         if ( !::BitBlt(dcDst, 0, 0, bmp.GetWidth(), bmp.GetHeight(),
1808                        dcSrc, 0, 0, SRCAND) )
1809         {
1810             wxLogLastError(wxT("BitBlt"));
1811         }
1812     }
1813 
1814     HICON hicon = ::CreateIconIndirect(&iconInfo);
1815 
1816     if ( !bmp.GetMask() && !bmp.HasAlpha() )
1817     {
1818         // we created the mask, now delete it
1819         delete mask;
1820     }
1821 
1822     return hicon;
1823 }
1824 
wxBitmapToHICON(const wxBitmap & bmp)1825 HICON wxBitmapToHICON(const wxBitmap& bmp)
1826 {
1827     return wxBitmapToIconOrCursor(bmp, true, 0, 0);
1828 }
1829 
wxBitmapToHCURSOR(const wxBitmap & bmp,int hotSpotX,int hotSpotY)1830 HCURSOR wxBitmapToHCURSOR(const wxBitmap& bmp, int hotSpotX, int hotSpotY)
1831 {
1832     return (HCURSOR)wxBitmapToIconOrCursor(bmp, false, hotSpotX, hotSpotY);
1833 }
1834 
wxInvertMask(HBITMAP hbmpMask,int w,int h)1835 HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h)
1836 {
1837 #ifndef __WXMICROWIN__
1838     wxCHECK_MSG( hbmpMask, 0, wxT("invalid bitmap in wxInvertMask") );
1839 
1840     // get width/height from the bitmap if not given
1841     if ( !w || !h )
1842     {
1843         BITMAP bm;
1844         ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm);
1845         w = bm.bmWidth;
1846         h = bm.bmHeight;
1847     }
1848 
1849     HDC hdcSrc = ::CreateCompatibleDC(NULL);
1850     HDC hdcDst = ::CreateCompatibleDC(NULL);
1851     if ( !hdcSrc || !hdcDst )
1852     {
1853         wxLogLastError(wxT("CreateCompatibleDC"));
1854     }
1855 
1856     HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0);
1857     if ( !hbmpInvMask )
1858     {
1859         wxLogLastError(wxT("CreateBitmap"));
1860     }
1861 
1862     HGDIOBJ srcTmp = ::SelectObject(hdcSrc, hbmpMask);
1863     HGDIOBJ dstTmp = ::SelectObject(hdcDst, hbmpInvMask);
1864     if ( !::BitBlt(hdcDst, 0, 0, w, h,
1865                    hdcSrc, 0, 0,
1866                    NOTSRCCOPY) )
1867     {
1868         wxLogLastError(wxT("BitBlt"));
1869     }
1870 
1871     // Deselect objects
1872     SelectObject(hdcSrc,srcTmp);
1873     SelectObject(hdcDst,dstTmp);
1874 
1875     ::DeleteDC(hdcSrc);
1876     ::DeleteDC(hdcDst);
1877 
1878     return hbmpInvMask;
1879 #else
1880     return 0;
1881 #endif
1882 }
1883