made wxBitmapRefData private (actually, this also fixes some bug so it's not absolute...
[wxWidgets.git] / src / msw / bitmap.cpp
1 ////////////////////////////////////////////////////////////////////////////
2 // Name: bitmap.cpp
3 // Purpose: wxBitmap
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "bitmap.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include <stdio.h>
33
34 #include "wx/list.h"
35 #include "wx/utils.h"
36 #include "wx/app.h"
37 #include "wx/palette.h"
38 #include "wx/dcmemory.h"
39 #include "wx/bitmap.h"
40 #include "wx/icon.h"
41 #endif
42
43 #include "wx/msw/private.h"
44 #include "wx/log.h"
45
46 #if !defined(__WXMICROWIN__)
47 #include "wx/msw/dib.h"
48 #endif
49
50 #include "wx/image.h"
51 #include "wx/xpmdecod.h"
52
53 // missing from mingw32 header
54 #ifndef CLR_INVALID
55 #define CLR_INVALID ((COLORREF)-1)
56 #endif // no CLR_INVALID
57
58 // ----------------------------------------------------------------------------
59 // Bitmap data
60 // ----------------------------------------------------------------------------
61
62 class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData
63 {
64 public:
65 wxBitmapRefData();
66 virtual ~wxBitmapRefData() { Free(); }
67
68 virtual void Free();
69
70 // set the mask object to use as the mask, we take ownership of it
71 void SetMask(wxMask *mask)
72 {
73 delete m_bitmapMask;
74 m_bitmapMask = mask;
75 }
76
77 // set the HBITMAP to use as the mask
78 void SetMask(HBITMAP hbmpMask)
79 {
80 SetMask(new wxMask((WXHBITMAP)hbmpMask));
81 }
82
83 // return the mask
84 wxMask *GetMask() const { return m_bitmapMask; }
85
86 public:
87 int m_numColors;
88 #if wxUSE_PALETTE
89 wxPalette m_bitmapPalette;
90 #endif // wxUSE_PALETTE
91
92 // MSW-specific
93 // ------------
94
95 // this field is solely for error checking: we detect selecting a bitmap
96 // into more than one DC at once or deleting a bitmap still selected into a
97 // DC (both are serious programming errors under Windows)
98 wxDC *m_selectedInto;
99
100 #if wxUSE_DIB_FOR_BITMAP
101 // file mapping handle for large DIB's
102 HANDLE m_hFileMap;
103 #endif // wxUSE_DIB_FOR_BITMAP
104
105 private:
106 // optional mask for transparent drawing
107 wxMask *m_bitmapMask;
108
109 DECLARE_NO_COPY_CLASS(wxBitmapRefData)
110 };
111
112 // ----------------------------------------------------------------------------
113 // macros
114 // ----------------------------------------------------------------------------
115
116 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
117 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
118
119 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
120
121 // ============================================================================
122 // implementation
123 // ============================================================================
124
125 // ----------------------------------------------------------------------------
126 // wxBitmapRefData
127 // ----------------------------------------------------------------------------
128
129 wxBitmapRefData::wxBitmapRefData()
130 {
131 m_selectedInto = NULL;
132 m_numColors = 0;
133 m_bitmapMask = NULL;
134 m_hBitmap = (WXHBITMAP) NULL;
135 #if wxUSE_DIB_FOR_BITMAP
136 m_hFileMap = 0;
137 #endif // wxUSE_DIB_FOR_BITMAP
138 }
139
140 void wxBitmapRefData::Free()
141 {
142 wxASSERT_MSG( !m_selectedInto,
143 wxT("deleting bitmap still selected into wxMemoryDC") );
144
145 if ( m_hBitmap)
146 {
147 if ( !::DeleteObject((HBITMAP)m_hBitmap) )
148 {
149 wxLogLastError(wxT("DeleteObject(hbitmap)"));
150 }
151 }
152
153 #if wxUSE_DIB_FOR_BITMAP
154 if ( m_hFileMap )
155 {
156 ::CloseHandle(m_hFileMap);
157
158 m_hFileMap = 0;
159 }
160 #endif // wxUSE_DIB_FOR_BITMAP
161
162 delete m_bitmapMask;
163 m_bitmapMask = NULL;
164 }
165
166 // ----------------------------------------------------------------------------
167 // wxBitmap creation
168 // ----------------------------------------------------------------------------
169
170 // this function should be called from all wxBitmap ctors
171 void wxBitmap::Init()
172 {
173 // m_refData = NULL; done in the base class ctor
174
175 }
176
177 wxGDIImageRefData *wxBitmap::CreateData() const
178 {
179 return new wxBitmapRefData;
180 }
181
182 #ifdef __WIN32__
183
184 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon)
185 {
186 #ifndef __WXMICROWIN__
187 // it may be either HICON or HCURSOR
188 HICON hicon = (HICON)icon.GetHandle();
189
190 ICONINFO iconInfo;
191 if ( !::GetIconInfo(hicon, &iconInfo) )
192 {
193 wxLogLastError(wxT("GetIconInfo"));
194
195 return FALSE;
196 }
197
198 wxBitmapRefData *refData = new wxBitmapRefData;
199 m_refData = refData;
200
201 int w = icon.GetWidth(),
202 h = icon.GetHeight();
203
204 refData->m_width = w;
205 refData->m_height = h;
206 refData->m_depth = wxDisplayDepth();
207
208 refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor;
209
210 // the mask returned by GetIconInfo() is inversed compared to the usual
211 // wxWin convention
212 refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h));
213
214
215 // delete the old one now as we don't need it any more
216 ::DeleteObject(iconInfo.hbmMask);
217
218 #if WXWIN_COMPATIBILITY_2
219 refData->m_ok = TRUE;
220 #endif // WXWIN_COMPATIBILITY_2
221
222 return TRUE;
223 #else
224 return FALSE;
225 #endif
226 }
227
228 #endif // Win32
229
230 bool wxBitmap::CopyFromCursor(const wxCursor& cursor)
231 {
232 UnRef();
233
234 if ( !cursor.Ok() )
235 return FALSE;
236
237 #ifdef __WIN16__
238 wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") );
239
240 return FALSE;
241 #else
242 return CopyFromIconOrCursor(cursor);
243 #endif // Win16
244 }
245
246 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
247 {
248 UnRef();
249
250 if ( !icon.Ok() )
251 return FALSE;
252
253 // GetIconInfo() doesn't exist under Win16 and I don't know any other way
254 // to create a bitmap from icon there - but using this way we won't have
255 // the mask (FIXME)
256 #ifdef __WIN16__
257 int width = icon.GetWidth(),
258 height = icon.GetHeight();
259
260 // copy the icon to the bitmap
261 ScreenHDC hdcScreen;
262 HDC hdc = ::CreateCompatibleDC(hdcScreen);
263 HBITMAP hbitmap = ::CreateCompatibleBitmap(hdcScreen, width, height);
264 HBITMAP hbmpOld = (HBITMAP)::SelectObject(hdc, hbitmap);
265
266 ::DrawIcon(hdc, 0, 0, GetHiconOf(icon));
267
268 ::SelectObject(hdc, hbmpOld);
269 ::DeleteDC(hdc);
270
271 wxBitmapRefData *refData = new wxBitmapRefData;
272 m_refData = refData;
273
274 refData->m_width = width;
275 refData->m_height = height;
276 refData->m_depth = wxDisplayDepth();
277
278 refData->m_hBitmap = (WXHBITMAP)hbitmap;
279
280 #if WXWIN_COMPATIBILITY_2
281 refData->m_ok = TRUE;
282 #endif // WXWIN_COMPATIBILITY_2
283
284 return TRUE;
285 #else // Win32
286 return CopyFromIconOrCursor(icon);
287 #endif // Win16/Win32
288 }
289
290 wxBitmap::~wxBitmap()
291 {
292 }
293
294 wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
295 {
296 Init();
297
298 #ifndef __WXMICROWIN__
299 wxBitmapRefData *refData = new wxBitmapRefData;
300 m_refData = refData;
301
302 refData->m_width = width;
303 refData->m_height = height;
304 refData->m_depth = depth;
305 refData->m_numColors = 0;
306 refData->m_selectedInto = NULL;
307
308 char *data;
309 if ( depth == 1 )
310 {
311 // we assume that it is in XBM format which is not quite the same as
312 // the format CreateBitmap() wants because the order of bytes in the
313 // line is inversed!
314 const size_t bytesPerLine = (width + 7) / 8;
315 const size_t padding = bytesPerLine % 2;
316 const size_t len = height * ( padding + bytesPerLine );
317 data = (char *)malloc(len);
318 const char *src = bits;
319 char *dst = data;
320
321 for ( int rows = 0; rows < height; rows++ )
322 {
323 for ( size_t cols = 0; cols < bytesPerLine; cols++ )
324 {
325 unsigned char val = *src++;
326 unsigned char reversed = 0;
327
328 for ( int bits = 0; bits < 8; bits++)
329 {
330 reversed <<= 1;
331 reversed |= (val & 0x01);
332 val >>= 1;
333 }
334 *dst++ = reversed;
335 }
336
337 if ( padding )
338 *dst++ = 0;
339 }
340 }
341 else
342 {
343 // bits should already be in Windows standard format
344 data = (char *)bits; // const_cast is harmless
345 }
346
347 HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data);
348 if ( !hbmp )
349 {
350 wxLogLastError(wxT("CreateBitmap"));
351 }
352
353 if ( data != bits )
354 {
355 free(data);
356 }
357
358 SetHBITMAP((WXHBITMAP)hbmp);
359 #endif
360 }
361
362 // Create from XPM data
363 bool wxBitmap::CreateFromXpm(const char **data)
364 {
365 #if wxUSE_IMAGE && wxUSE_XPM
366 Init();
367
368 wxCHECK_MSG( data != NULL, FALSE, wxT("invalid bitmap data") )
369
370 wxXPMDecoder decoder;
371 wxImage img = decoder.ReadData(data);
372 wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid bitmap data") )
373
374 *this = wxBitmap(img);
375 return TRUE;
376 #else
377 return FALSE;
378 #endif
379 }
380
381 wxBitmap::wxBitmap(int w, int h, int d)
382 {
383 Init();
384
385 (void)Create(w, h, d);
386 }
387
388 wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth)
389 {
390 Init();
391
392 (void)Create(data, type, width, height, depth);
393 }
394
395 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
396 {
397 Init();
398
399 LoadFile(filename, (int)type);
400 }
401
402 bool wxBitmap::Create(int w, int h, int d)
403 {
404 UnRef();
405
406 m_refData = new wxBitmapRefData;
407
408 #if wxUSE_DIB_FOR_BITMAP
409 if ( w && h && d >= 16 )
410 {
411 if ( !CreateDIB(w, h, d) )
412 return FALSE;
413 }
414 else
415 #endif // wxUSE_DIB_FOR_BITMAP
416 {
417 GetBitmapData()->m_width = w;
418 GetBitmapData()->m_height = h;
419 GetBitmapData()->m_depth = d;
420
421 HBITMAP hbmp;
422 #ifndef __WXMICROWIN__
423 if ( d > 0 )
424 {
425 hbmp = ::CreateBitmap(w, h, 1, d, NULL);
426 if ( !hbmp )
427 {
428 wxLogLastError(wxT("CreateBitmap"));
429 }
430 }
431 else
432 #endif // !__WXMICROWIN__
433 {
434 ScreenHDC dc;
435 hbmp = ::CreateCompatibleBitmap(dc, w, h);
436 if ( !hbmp )
437 {
438 wxLogLastError(wxT("CreateCompatibleBitmap"));
439 }
440
441 GetBitmapData()->m_depth = wxDisplayDepth();
442 }
443
444 SetHBITMAP((WXHBITMAP)hbmp);
445
446 #if WXWIN_COMPATIBILITY_2
447 GetBitmapData()->m_ok = hbmp != 0;
448 #endif // WXWIN_COMPATIBILITY_2
449 }
450
451 return Ok();
452 }
453
454 #if wxUSE_DIB_FOR_BITMAP
455
456 void *wxBitmap::CreateDIB(int width, int height, int depth)
457 {
458 void *dibBits;
459 const int infosize = sizeof(BITMAPINFOHEADER);
460
461 BITMAPINFO *info = (BITMAPINFO *)malloc(infosize);
462 if ( info )
463 {
464 memset(info, 0, infosize);
465
466 info->bmiHeader.biSize = infosize;
467 info->bmiHeader.biWidth = width;
468 info->bmiHeader.biHeight = height;
469 info->bmiHeader.biPlanes = 1;
470 info->bmiHeader.biBitCount = depth;
471 info->bmiHeader.biCompression = BI_RGB;
472 info->bmiHeader.biSizeImage =
473 (((width * (depth/8)) + sizeof(DWORD) - 1) /
474 sizeof(DWORD) * sizeof(DWORD)) * height;
475 info->bmiHeader.biXPelsPerMeter = 0;
476 info->bmiHeader.biYPelsPerMeter = 0;
477 info->bmiHeader.biClrUsed = 0;
478 info->bmiHeader.biClrImportant = 0;
479 GetBitmapData()->m_hFileMap = ::CreateFileMapping
480 (
481 INVALID_HANDLE_VALUE,
482 0,
483 PAGE_READWRITE | SEC_COMMIT,
484 0,
485 info->bmiHeader.biSizeImage,
486 0
487 );
488
489 // No need to report an error here. If it fails, we just won't use a
490 // file mapping and CreateDIBSection will just allocate memory for us.
491 GetBitmapData()->m_handle =
492 (WXHANDLE)::CreateDIBSection
493 (
494 0,
495 info,
496 DIB_RGB_COLORS,
497 &dibBits,
498 GetBitmapData()->m_hFileMap,
499 0
500 );
501
502 if ( !GetBitmapData()->m_handle )
503 wxLogLastError(wxT("CreateDIBSection"));
504
505 SetWidth(width);
506 SetHeight(height);
507 SetDepth(depth);
508
509 free(info);
510 }
511 else
512 {
513 wxFAIL_MSG( wxT("could not allocate memory for DIB header") );
514
515 dibBits = NULL;
516 }
517
518 return dibBits;
519 }
520
521 #endif // wxUSE_DIB_FOR_BITMAP
522
523 // ----------------------------------------------------------------------------
524 // wxImage to/from conversions
525 // ----------------------------------------------------------------------------
526
527 #if wxUSE_IMAGE
528
529 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
530 {
531 #ifdef __WXMICROWIN__
532
533 // Set this to 1 to experiment with mask code,
534 // which currently doesn't work
535 #define USE_MASKS 0
536
537 m_refData = new wxBitmapRefData();
538
539 // Initial attempt at a simple-minded implementation.
540 // The bitmap will always be created at the screen depth,
541 // so the 'depth' argument is ignored.
542
543 HDC hScreenDC = ::GetDC(NULL);
544 int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL);
545
546 HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight());
547 HBITMAP hMaskBitmap = NULL;
548 HBITMAP hOldMaskBitmap = NULL;
549 HDC hMaskDC = NULL;
550 unsigned char maskR = 0;
551 unsigned char maskG = 0;
552 unsigned char maskB = 0;
553
554 // printf("Created bitmap %d\n", (int) hBitmap);
555 if (hBitmap == NULL)
556 {
557 ::ReleaseDC(NULL, hScreenDC);
558 return FALSE;
559 }
560 HDC hMemDC = ::CreateCompatibleDC(hScreenDC);
561
562 HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap);
563 ::ReleaseDC(NULL, hScreenDC);
564
565 // created an mono-bitmap for the possible mask
566 bool hasMask = image.HasMask();
567
568 if ( hasMask )
569 {
570 #if USE_MASKS
571 // FIXME: we should be able to pass bpp = 1, but
572 // GdBlit can't handle a different depth
573 #if 0
574 hMaskBitmap = ::CreateBitmap( (WORD)image.GetWidth(), (WORD)image.GetHeight(), 1, 1, NULL );
575 #else
576 hMaskBitmap = ::CreateCompatibleBitmap( hMemDC, (WORD)image.GetWidth(), (WORD)image.GetHeight());
577 #endif
578 maskR = image.GetMaskRed();
579 maskG = image.GetMaskGreen();
580 maskB = image.GetMaskBlue();
581
582 if (!hMaskBitmap)
583 {
584 hasMask = FALSE;
585 }
586 else
587 {
588 hScreenDC = ::GetDC(NULL);
589 hMaskDC = ::CreateCompatibleDC(hScreenDC);
590 ::ReleaseDC(NULL, hScreenDC);
591
592 hOldMaskBitmap = ::SelectObject( hMaskDC, hMaskBitmap);
593 }
594 #else
595 hasMask = FALSE;
596 #endif
597 }
598
599 int i, j;
600 for (i = 0; i < image.GetWidth(); i++)
601 {
602 for (j = 0; j < image.GetHeight(); j++)
603 {
604 unsigned char red = image.GetRed(i, j);
605 unsigned char green = image.GetGreen(i, j);
606 unsigned char blue = image.GetBlue(i, j);
607
608 ::SetPixel(hMemDC, i, j, PALETTERGB(red, green, blue));
609
610 if (hasMask)
611 {
612 // scan the bitmap for the transparent colour and set the corresponding
613 // pixels in the mask to BLACK and the rest to WHITE
614 if (maskR == red && maskG == green && maskB == blue)
615 ::SetPixel(hMaskDC, i, j, PALETTERGB(0, 0, 0));
616 else
617 ::SetPixel(hMaskDC, i, j, PALETTERGB(255, 255, 255));
618 }
619 }
620 }
621
622 ::SelectObject(hMemDC, hOldBitmap);
623 ::DeleteDC(hMemDC);
624 if (hasMask)
625 {
626 ::SelectObject(hMaskDC, hOldMaskBitmap);
627 ::DeleteDC(hMaskDC);
628
629 ((wxBitmapRefData*)m_refData)->SetMask(hMaskBitmap);
630 }
631
632 SetWidth(image.GetWidth());
633 SetHeight(image.GetHeight());
634 SetDepth(screenDepth);
635 SetHBITMAP( (WXHBITMAP) hBitmap );
636
637 #if wxUSE_PALETTE
638 // Copy the palette from the source image
639 SetPalette(image.GetPalette());
640 #endif // wxUSE_PALETTE
641
642 #if WXWIN_COMPATIBILITY_2
643 // check the wxBitmap object
644 GetBitmapData()->SetOk();
645 #endif // WXWIN_COMPATIBILITY_2
646
647 return TRUE;
648
649 #else // !__WXMICROWIN__
650 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
651
652 m_refData = new wxBitmapRefData();
653
654 #if wxUSE_DIB_FOR_BITMAP
655 int h = image.GetHeight();
656 int w = image.GetWidth();
657 unsigned char *dibBits = (unsigned char*)CreateDIB(w, h, 24);
658 if ( !dibBits )
659 return FALSE;
660
661 // DIBs are stored in bottom to top order so we need to copy bits line by
662 // line and starting from the end
663 const int srcBytesPerLine = w * 3;
664 const int dstBytesPerLine = (srcBytesPerLine + sizeof(DWORD) - 1) /
665 sizeof(DWORD) * sizeof(DWORD);
666 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
667 for ( int i = 0; i < h; i++ )
668 {
669 // copy one DIB line
670 int x = w;
671 const unsigned char *rgbBits = src;
672 while ( x-- )
673 {
674 // also, the order of RGB is inversed for DIBs
675 *dibBits++ = rgbBits[2];
676 *dibBits++ = rgbBits[1];
677 *dibBits++ = rgbBits[0];
678
679 rgbBits += 3;
680 }
681
682 // pass to the next line
683 src -= srcBytesPerLine;
684 dibBits += dstBytesPerLine - srcBytesPerLine;
685 }
686
687 if ( image.HasMask() )
688 {
689 SetMask(new wxMask(*this, wxColour(image.GetMaskRed(),
690 image.GetMaskGreen(),
691 image.GetMaskBlue())));
692 }
693 #else // wxUSE_DIB_FOR_BITMAP
694 // sizeLimit is the MS upper limit for the DIB size
695 #ifdef WIN32
696 int sizeLimit = 1024*768*3;
697 #else
698 int sizeLimit = 0x7fff;
699 #endif
700
701 // width and height of the device-dependent bitmap
702 int width = image.GetWidth();
703 int bmpHeight = image.GetHeight();
704
705 // calc the number of bytes per scanline and padding
706 int bytePerLine = width*3;
707 int sizeDWORD = sizeof( DWORD );
708 int lineBoundary = bytePerLine % sizeDWORD;
709 int padding = 0;
710 if( lineBoundary > 0 )
711 {
712 padding = sizeDWORD - lineBoundary;
713 bytePerLine += padding;
714 }
715 // calc the number of DIBs and heights of DIBs
716 int numDIB = 1;
717 int hRemain = 0;
718 int height = sizeLimit/bytePerLine;
719 if( height >= bmpHeight )
720 height = bmpHeight;
721 else
722 {
723 numDIB = bmpHeight / height;
724 hRemain = bmpHeight % height;
725 if( hRemain >0 ) numDIB++;
726 }
727
728 // set bitmap parameters
729 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") );
730 SetWidth( width );
731 SetHeight( bmpHeight );
732 if (depth == -1) depth = wxDisplayDepth();
733 SetDepth( depth );
734
735 #if wxUSE_PALETTE
736 // Copy the palette from the source image
737 SetPalette(image.GetPalette());
738 #endif // wxUSE_PALETTE
739
740 // create a DIB header
741 int headersize = sizeof(BITMAPINFOHEADER);
742 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
743 wxCHECK_MSG( lpDIBh, FALSE, wxT("could not allocate memory for DIB header") );
744 // Fill in the DIB header
745 lpDIBh->bmiHeader.biSize = headersize;
746 lpDIBh->bmiHeader.biWidth = (DWORD)width;
747 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
748 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
749 // the general formula for biSizeImage:
750 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
751 lpDIBh->bmiHeader.biPlanes = 1;
752 lpDIBh->bmiHeader.biBitCount = 24;
753 lpDIBh->bmiHeader.biCompression = BI_RGB;
754 lpDIBh->bmiHeader.biClrUsed = 0;
755 // These seem not really needed for our purpose here.
756 lpDIBh->bmiHeader.biClrImportant = 0;
757 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
758 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
759 // memory for DIB data
760 unsigned char *lpBits;
761 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
762 if( !lpBits )
763 {
764 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
765 free( lpDIBh );
766 return FALSE;
767 }
768
769 // create and set the device-dependent bitmap
770 HDC hdc = ::GetDC(NULL);
771 HDC memdc = ::CreateCompatibleDC( hdc );
772 HBITMAP hbitmap;
773 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
774 ::SelectObject( memdc, hbitmap);
775
776 #if wxUSE_PALETTE
777 HPALETTE hOldPalette = 0;
778 if (image.GetPalette().Ok())
779 {
780 hOldPalette = ::SelectPalette(memdc, (HPALETTE) image.GetPalette().GetHPALETTE(), FALSE);
781 ::RealizePalette(memdc);
782 }
783 #endif // wxUSE_PALETTE
784
785 // copy image data into DIB data and then into DDB (in a loop)
786 unsigned char *data = image.GetData();
787 int i, j, n;
788 int origin = 0;
789 unsigned char *ptdata = data;
790 unsigned char *ptbits;
791
792 for( n=0; n<numDIB; n++ )
793 {
794 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
795 {
796 // redefine height and size of the (possibly) last smaller DIB
797 // memory is not reallocated
798 height = hRemain;
799 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
800 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
801 }
802 ptbits = lpBits;
803
804 for( j=0; j<height; j++ )
805 {
806 for( i=0; i<width; i++ )
807 {
808 *(ptbits++) = *(ptdata+2);
809 *(ptbits++) = *(ptdata+1);
810 *(ptbits++) = *(ptdata );
811 ptdata += 3;
812 }
813 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
814 }
815 ::StretchDIBits( memdc, 0, origin, width, height,\
816 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
817 origin += height;
818 // if numDIB = 1, lines below can also be used
819 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
820 // The above line is equivalent to the following two lines.
821 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
822 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
823 // or the following lines
824 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
825 // HDC memdc = ::CreateCompatibleDC( hdc );
826 // ::SelectObject( memdc, hbitmap);
827 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
828 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
829 // ::SelectObject( memdc, 0 );
830 // ::DeleteDC( memdc );
831 }
832 SetHBITMAP( (WXHBITMAP) hbitmap );
833
834 #if wxUSE_PALETTE
835 if (hOldPalette)
836 SelectPalette(memdc, hOldPalette, FALSE);
837 #endif // wxUSE_PALETTE
838
839 // similarly, created an mono-bitmap for the possible mask
840 if( image.HasMask() )
841 {
842 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
843 HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap);
844 if( numDIB == 1 ) height = bmpHeight;
845 else height = sizeLimit/bytePerLine;
846 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
847 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
848 origin = 0;
849 unsigned char r = image.GetMaskRed();
850 unsigned char g = image.GetMaskGreen();
851 unsigned char b = image.GetMaskBlue();
852 unsigned char zero = 0, one = 255;
853 ptdata = data;
854 for( n=0; n<numDIB; n++ )
855 {
856 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
857 {
858 // redefine height and size of the (possibly) last smaller DIB
859 // memory is not reallocated
860 height = hRemain;
861 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
862 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
863 }
864 ptbits = lpBits;
865 for( int j=0; j<height; j++ )
866 {
867 for(i=0; i<width; i++ )
868 {
869 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
870 unsigned char cr = (*(ptdata++)) ;
871 unsigned char cg = (*(ptdata++)) ;
872 unsigned char cb = (*(ptdata++)) ;
873
874 if( ( cr !=r) || (cg!=g) || (cb!=b) )
875 {
876 *(ptbits++) = one;
877 *(ptbits++) = one;
878 *(ptbits++) = one;
879 }
880 else
881 {
882 *(ptbits++) = zero;
883 *(ptbits++) = zero;
884 *(ptbits++) = zero;
885 }
886 }
887 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
888 }
889 ::StretchDIBits( memdc, 0, origin, width, height,\
890 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
891 origin += height;
892 }
893 // create a wxMask object
894 wxMask *mask = new wxMask();
895 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
896 SetMask( mask );
897 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
898 /* The following can also be used but is slow to run
899 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
900 wxMask *mask = new wxMask( *this, colour );
901 SetMask( mask );
902 */
903
904 ::SelectObject( memdc, hbmpOld );
905 }
906
907 // free allocated resources
908 ::DeleteDC( memdc );
909 ::ReleaseDC(NULL, hdc);
910 free(lpDIBh);
911 free(lpBits);
912 #endif // wxUSE_DIB_FOR_BITMAP
913
914 #if WXWIN_COMPATIBILITY_2
915 // check the wxBitmap object
916 GetBitmapData()->SetOk();
917 #endif // WXWIN_COMPATIBILITY_2
918
919 return TRUE;
920 #endif // __WXMICROWIN__/!__WXMICROWIN__
921 }
922
923 wxImage wxBitmap::ConvertToImage() const
924 {
925 #ifdef __WXMICROWIN__
926 // Initial attempt at a simple-minded implementation.
927 // The bitmap will always be created at the screen depth,
928 // so the 'depth' argument is ignored.
929 // TODO: transparency (create a mask image)
930
931 if (!Ok())
932 {
933 wxFAIL_MSG( wxT("bitmap is invalid") );
934 return wxNullImage;
935 }
936
937 wxImage image;
938
939 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
940
941 // create an wxImage object
942 int width = GetWidth();
943 int height = GetHeight();
944 image.Create( width, height );
945 unsigned char *data = image.GetData();
946 if( !data )
947 {
948 wxFAIL_MSG( wxT("could not allocate data for image") );
949 return wxNullImage;
950 }
951
952 HDC hScreenDC = ::GetDC(NULL);
953
954 HDC hMemDC = ::CreateCompatibleDC(hScreenDC);
955 ::ReleaseDC(NULL, hScreenDC);
956
957 HBITMAP hBitmap = (HBITMAP) GetHBITMAP();
958
959 HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap);
960
961 int i, j;
962 for (i = 0; i < GetWidth(); i++)
963 {
964 for (j = 0; j < GetHeight(); j++)
965 {
966 COLORREF color = ::GetPixel(hMemDC, i, j);
967 unsigned char red = GetRValue(color);
968 unsigned char green = GetGValue(color);
969 unsigned char blue = GetBValue(color);
970
971 image.SetRGB(i, j, red, green, blue);
972 }
973 }
974
975 ::SelectObject(hMemDC, hOldBitmap);
976 ::DeleteDC(hMemDC);
977
978 #if wxUSE_PALETTE
979 // Copy the palette from the source image
980 if (GetPalette())
981 image.SetPalette(* GetPalette());
982 #endif // wxUSE_PALETTE
983
984 return image;
985
986 #else // !__WXMICROWIN__
987 wxImage image;
988
989 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
990
991 // create an wxImage object
992 int width = GetWidth();
993 int height = GetHeight();
994 image.Create( width, height );
995 unsigned char *data = image.GetData();
996 if( !data )
997 {
998 wxFAIL_MSG( wxT("could not allocate data for image") );
999 return wxNullImage;
1000 }
1001
1002 // calc the number of bytes per scanline and padding in the DIB
1003 int bytePerLine = width*3;
1004 int sizeDWORD = sizeof( DWORD );
1005 int lineBoundary = bytePerLine % sizeDWORD;
1006 int padding = 0;
1007 if( lineBoundary > 0 )
1008 {
1009 padding = sizeDWORD - lineBoundary;
1010 bytePerLine += padding;
1011 }
1012
1013 // create a DIB header
1014 int headersize = sizeof(BITMAPINFOHEADER);
1015 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
1016 if( !lpDIBh )
1017 {
1018 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1019 free( data );
1020 return wxNullImage;
1021 }
1022 // Fill in the DIB header
1023 lpDIBh->bmiHeader.biSize = headersize;
1024 lpDIBh->bmiHeader.biWidth = width;
1025 lpDIBh->bmiHeader.biHeight = -height;
1026 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1027 lpDIBh->bmiHeader.biPlanes = 1;
1028 lpDIBh->bmiHeader.biBitCount = 24;
1029 lpDIBh->bmiHeader.biCompression = BI_RGB;
1030 lpDIBh->bmiHeader.biClrUsed = 0;
1031 // These seem not really needed for our purpose here.
1032 lpDIBh->bmiHeader.biClrImportant = 0;
1033 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1034 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1035 // memory for DIB data
1036 unsigned char *lpBits;
1037 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1038 if( !lpBits )
1039 {
1040 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1041 free( data );
1042 free( lpDIBh );
1043 return wxNullImage;
1044 }
1045
1046 // copy data from the device-dependent bitmap to the DIB
1047 HDC hdc = ::GetDC(NULL);
1048 HBITMAP hbitmap;
1049 hbitmap = (HBITMAP) GetHBITMAP();
1050 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1051
1052 // copy DIB data into the wxImage object
1053 int i, j;
1054 unsigned char *ptdata = data;
1055 unsigned char *ptbits = lpBits;
1056 for( i=0; i<height; i++ )
1057 {
1058 for( j=0; j<width; j++ )
1059 {
1060 *(ptdata++) = *(ptbits+2);
1061 *(ptdata++) = *(ptbits+1);
1062 *(ptdata++) = *(ptbits );
1063 ptbits += 3;
1064 }
1065 ptbits += padding;
1066 }
1067
1068 // similarly, set data according to the possible mask bitmap
1069 if( GetMask() && GetMask()->GetMaskBitmap() )
1070 {
1071 hbitmap = (HBITMAP) GetMask()->GetMaskBitmap();
1072 // memory DC created, color set, data copied, and memory DC deleted
1073 HDC memdc = ::CreateCompatibleDC( hdc );
1074 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1075 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1076 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1077 ::DeleteDC( memdc );
1078 // background color set to RGB(16,16,16) in consistent with wxGTK
1079 unsigned char r=16, g=16, b=16;
1080 ptdata = data;
1081 ptbits = lpBits;
1082 for( i=0; i<height; i++ )
1083 {
1084 for( j=0; j<width; j++ )
1085 {
1086 if( *ptbits != 0 )
1087 ptdata += 3;
1088 else
1089 {
1090 *(ptdata++) = r;
1091 *(ptdata++) = g;
1092 *(ptdata++) = b;
1093 }
1094 ptbits += 3;
1095 }
1096 ptbits += padding;
1097 }
1098 image.SetMaskColour( r, g, b );
1099 image.SetMask( TRUE );
1100 }
1101 else
1102 {
1103 image.SetMask( FALSE );
1104 }
1105 // free allocated resources
1106 ::ReleaseDC(NULL, hdc);
1107 free(lpDIBh);
1108 free(lpBits);
1109
1110 return image;
1111 #endif // __WXMICROWIN__/!__WXMICROWIN__
1112 }
1113
1114 #endif // wxUSE_IMAGE
1115
1116 bool wxBitmap::LoadFile(const wxString& filename, long type)
1117 {
1118 UnRef();
1119
1120 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
1121
1122 if ( handler )
1123 {
1124 m_refData = new wxBitmapRefData;
1125
1126 return handler->LoadFile(this, filename, type, -1, -1);
1127 }
1128 #if wxUSE_IMAGE
1129 else
1130 {
1131 wxImage image;
1132 if ( image.LoadFile( filename, type ) && image.Ok() )
1133 {
1134 *this = wxBitmap(image);
1135
1136 return TRUE;
1137 }
1138 }
1139 #endif // wxUSE_IMAGE
1140
1141 return FALSE;
1142 }
1143
1144 bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
1145 {
1146 UnRef();
1147
1148 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
1149
1150 if ( !handler )
1151 {
1152 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type);
1153
1154 return FALSE;
1155 }
1156
1157 m_refData = new wxBitmapRefData;
1158
1159 return handler->Create(this, data, type, width, height, depth);
1160 }
1161
1162 bool wxBitmap::SaveFile(const wxString& filename,
1163 int type,
1164 const wxPalette *palette)
1165 {
1166 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
1167
1168 if ( handler )
1169 {
1170 return handler->SaveFile(this, filename, type, palette);
1171 }
1172 #if wxUSE_IMAGE
1173 else
1174 {
1175 // FIXME what about palette? shouldn't we use it?
1176 wxImage image = ConvertToImage();
1177 if ( image.Ok() )
1178 {
1179 return image.SaveFile(filename, type);
1180 }
1181 }
1182 #endif // wxUSE_IMAGE
1183
1184 return FALSE;
1185 }
1186
1187 // ----------------------------------------------------------------------------
1188 // sub bitmap extraction
1189 // ----------------------------------------------------------------------------
1190
1191 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
1192 {
1193 wxCHECK_MSG( Ok() &&
1194 (rect.x >= 0) && (rect.y >= 0) &&
1195 (rect.x+rect.width <= GetWidth()) &&
1196 (rect.y+rect.height <= GetHeight()),
1197 wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
1198
1199 wxBitmap ret( rect.width, rect.height, GetDepth() );
1200 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
1201
1202 #ifndef __WXMICROWIN__
1203 // copy bitmap data
1204 MemoryHDC dcSrc, dcDst;
1205
1206 {
1207 SelectInHDC selectSrc(dcSrc, GetHbitmap()),
1208 selectDst(dcDst, GetHbitmapOf(ret));
1209
1210 if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
1211 dcSrc, rect.x, rect.y, SRCCOPY) )
1212 {
1213 wxLogLastError(_T("BitBlt"));
1214 }
1215 }
1216
1217 // copy mask if there is one
1218 if ( GetMask() )
1219 {
1220 HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0);
1221
1222 SelectInHDC selectSrc(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()),
1223 selectDst(dcDst, hbmpMask);
1224
1225 if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
1226 dcSrc, rect.x, rect.y, SRCCOPY) )
1227 {
1228 wxLogLastError(_T("BitBlt"));
1229 }
1230
1231 wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
1232 ret.SetMask(mask);
1233 }
1234 #endif // !__WXMICROWIN__
1235
1236 return ret;
1237 }
1238
1239 // ----------------------------------------------------------------------------
1240 // wxBitmap accessors
1241 // ----------------------------------------------------------------------------
1242
1243 wxPalette* wxBitmap::GetPalette() const
1244 {
1245 return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette
1246 : (wxPalette *) NULL;
1247 }
1248
1249 wxMask *wxBitmap::GetMask() const
1250 {
1251 return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask *) NULL;
1252 }
1253
1254 wxDC *wxBitmap::GetSelectedInto() const
1255 {
1256 return GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC *) NULL;
1257 }
1258
1259 #if wxUSE_DIB_FOR_BITMAP
1260
1261 bool wxBitmap::IsDIB() const
1262 {
1263 return GetBitmapData() && GetBitmapData()->m_hFileMap != NULL;
1264 }
1265
1266 #endif // wxUSE_DIB_FOR_BITMAP
1267
1268 #if WXWIN_COMPATIBILITY_2_4
1269
1270 int wxBitmap::GetQuality() const
1271 {
1272 return 0;
1273 }
1274
1275 #endif // WXWIN_COMPATIBILITY_2_4
1276
1277 // ----------------------------------------------------------------------------
1278 // wxBitmap setters
1279 // ----------------------------------------------------------------------------
1280
1281 void wxBitmap::SetSelectedInto(wxDC *dc)
1282 {
1283 if ( GetBitmapData() )
1284 GetBitmapData()->m_selectedInto = dc;
1285 }
1286
1287 #if wxUSE_PALETTE
1288
1289 void wxBitmap::SetPalette(const wxPalette& palette)
1290 {
1291 EnsureHasData();
1292
1293 GetBitmapData()->m_bitmapPalette = palette;
1294 }
1295
1296 #endif // wxUSE_PALETTE
1297
1298 void wxBitmap::SetMask(wxMask *mask)
1299 {
1300 EnsureHasData();
1301
1302 GetBitmapData()->SetMask(mask);
1303 }
1304
1305 #if WXWIN_COMPATIBILITY_2
1306
1307 void wxBitmap::SetOk(bool isOk)
1308 {
1309 EnsureHasData();
1310
1311 GetBitmapData()->m_ok = isOk;
1312 }
1313
1314 #endif // WXWIN_COMPATIBILITY_2
1315
1316 #if WXWIN_COMPATIBILITY_2_4
1317
1318 void wxBitmap::SetQuality(int WXUNUSED(quality))
1319 {
1320 }
1321
1322 #endif // WXWIN_COMPATIBILITY_2_4
1323
1324 // ----------------------------------------------------------------------------
1325 // TODO: to be replaced by something better
1326 // ----------------------------------------------------------------------------
1327
1328 // Creates a bitmap that matches the device context, from
1329 // an arbitray bitmap. At present, the original bitmap must have an
1330 // associated palette. TODO: use a default palette if no palette exists.
1331 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
1332 wxBitmap wxBitmap::GetBitmapForDC(wxDC& dc) const
1333 {
1334 #ifdef __WXMICROWIN__
1335 return *this;
1336 #else
1337 wxMemoryDC memDC;
1338 wxBitmap tmpBitmap(GetWidth(), GetHeight(), dc.GetDepth());
1339 HPALETTE hPal = (HPALETTE) NULL;
1340 LPBITMAPINFO lpDib;
1341 void *lpBits = (void*) NULL;
1342
1343 #if wxUSE_PALETTE
1344 if( GetPalette() && GetPalette()->Ok() )
1345 {
1346 tmpBitmap.SetPalette(*GetPalette());
1347 memDC.SelectObject(tmpBitmap);
1348 memDC.SetPalette(*GetPalette());
1349 hPal = (HPALETTE)GetPalette()->GetHPALETTE();
1350 }
1351 else
1352 {
1353 hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE);
1354 wxPalette palette;
1355 palette.SetHPALETTE( (WXHPALETTE)hPal );
1356 tmpBitmap.SetPalette( palette );
1357 memDC.SelectObject(tmpBitmap);
1358 memDC.SetPalette( palette );
1359 }
1360 #else // !wxUSE_PALETTE
1361 hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE);
1362 #endif // wxUSE_PALETTE/!wxUSE_PALETTE
1363
1364 // set the height negative because in a DIB the order of the lines is
1365 // reversed
1366 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal, &lpDib) )
1367 {
1368 return wxNullBitmap;
1369 }
1370
1371 lpBits = malloc(lpDib->bmiHeader.biSizeImage);
1372
1373 ::GetBitmapBits(GetHbitmap(), lpDib->bmiHeader.biSizeImage, lpBits);
1374
1375 ::SetDIBitsToDevice(GetHdcOf(memDC), 0, 0,
1376 GetWidth(), GetHeight(),
1377 0, 0, 0, GetHeight(),
1378 lpBits, lpDib, DIB_RGB_COLORS);
1379
1380 free(lpBits);
1381
1382 wxFreeDIB(lpDib);
1383
1384 return tmpBitmap;
1385 #endif
1386 }
1387
1388 // ----------------------------------------------------------------------------
1389 // wxMask
1390 // ----------------------------------------------------------------------------
1391
1392 wxMask::wxMask()
1393 {
1394 m_maskBitmap = 0;
1395 }
1396
1397 // Construct a mask from a bitmap and a colour indicating
1398 // the transparent area
1399 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
1400 {
1401 m_maskBitmap = 0;
1402 Create(bitmap, colour);
1403 }
1404
1405 // Construct a mask from a bitmap and a palette index indicating
1406 // the transparent area
1407 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
1408 {
1409 m_maskBitmap = 0;
1410 Create(bitmap, paletteIndex);
1411 }
1412
1413 // Construct a mask from a mono bitmap (copies the bitmap).
1414 wxMask::wxMask(const wxBitmap& bitmap)
1415 {
1416 m_maskBitmap = 0;
1417 Create(bitmap);
1418 }
1419
1420 wxMask::~wxMask()
1421 {
1422 if ( m_maskBitmap )
1423 ::DeleteObject((HBITMAP) m_maskBitmap);
1424 }
1425
1426 // Create a mask from a mono bitmap (copies the bitmap).
1427 bool wxMask::Create(const wxBitmap& bitmap)
1428 {
1429 #ifndef __WXMICROWIN__
1430 wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, FALSE,
1431 _T("can't create mask from invalid or not monochrome bitmap") );
1432
1433 if ( m_maskBitmap )
1434 {
1435 ::DeleteObject((HBITMAP) m_maskBitmap);
1436 m_maskBitmap = 0;
1437 }
1438
1439 m_maskBitmap = (WXHBITMAP) CreateBitmap(
1440 bitmap.GetWidth(),
1441 bitmap.GetHeight(),
1442 1, 1, 0
1443 );
1444 HDC srcDC = CreateCompatibleDC(0);
1445 SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
1446 HDC destDC = CreateCompatibleDC(0);
1447 SelectObject(destDC, (HBITMAP) m_maskBitmap);
1448 BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY);
1449 SelectObject(srcDC, 0);
1450 DeleteDC(srcDC);
1451 SelectObject(destDC, 0);
1452 DeleteDC(destDC);
1453 return TRUE;
1454 #else
1455 return FALSE;
1456 #endif
1457 }
1458
1459 // Create a mask from a bitmap and a palette index indicating
1460 // the transparent area
1461 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
1462 {
1463 if ( m_maskBitmap )
1464 {
1465 ::DeleteObject((HBITMAP) m_maskBitmap);
1466 m_maskBitmap = 0;
1467 }
1468
1469 #if wxUSE_PALETTE
1470 if (bitmap.Ok() && bitmap.GetPalette()->Ok())
1471 {
1472 unsigned char red, green, blue;
1473 if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
1474 {
1475 wxColour transparentColour(red, green, blue);
1476 return Create(bitmap, transparentColour);
1477 }
1478 }
1479 #endif // wxUSE_PALETTE
1480
1481 return FALSE;
1482 }
1483
1484 // Create a mask from a bitmap and a colour indicating
1485 // the transparent area
1486 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1487 {
1488 #ifndef __WXMICROWIN__
1489 wxCHECK_MSG( bitmap.Ok(), FALSE, _T("invalid bitmap in wxMask::Create") );
1490
1491 if ( m_maskBitmap )
1492 {
1493 ::DeleteObject((HBITMAP) m_maskBitmap);
1494 m_maskBitmap = 0;
1495 }
1496
1497 int width = bitmap.GetWidth(),
1498 height = bitmap.GetHeight();
1499
1500 // scan the bitmap for the transparent colour and set the corresponding
1501 // pixels in the mask to BLACK and the rest to WHITE
1502 COLORREF maskColour = wxColourToPalRGB(colour);
1503 m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0);
1504
1505 HDC srcDC = ::CreateCompatibleDC(NULL);
1506 HDC destDC = ::CreateCompatibleDC(NULL);
1507 if ( !srcDC || !destDC )
1508 {
1509 wxLogLastError(wxT("CreateCompatibleDC"));
1510 }
1511
1512 bool ok = TRUE;
1513
1514 // SelectObject() will fail
1515 wxASSERT_MSG( !bitmap.GetSelectedInto(),
1516 _T("bitmap can't be selected in another DC") );
1517
1518 HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap));
1519 if ( !hbmpSrcOld )
1520 {
1521 wxLogLastError(wxT("SelectObject"));
1522
1523 ok = FALSE;
1524 }
1525
1526 HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap);
1527 if ( !hbmpDstOld )
1528 {
1529 wxLogLastError(wxT("SelectObject"));
1530
1531 ok = FALSE;
1532 }
1533
1534 if ( ok )
1535 {
1536 // this will create a monochrome bitmap with 0 points for the pixels
1537 // which have the same value as the background colour and 1 for the
1538 // others
1539 ::SetBkColor(srcDC, maskColour);
1540 ::BitBlt(destDC, 0, 0, width, height, srcDC, 0, 0, NOTSRCCOPY);
1541 }
1542
1543 ::SelectObject(srcDC, hbmpSrcOld);
1544 ::DeleteDC(srcDC);
1545 ::SelectObject(destDC, hbmpDstOld);
1546 ::DeleteDC(destDC);
1547
1548 return ok;
1549 #else // __WXMICROWIN__
1550 return FALSE;
1551 #endif // __WXMICROWIN__/!__WXMICROWIN__
1552 }
1553
1554 // ----------------------------------------------------------------------------
1555 // wxBitmapHandler
1556 // ----------------------------------------------------------------------------
1557
1558 bool wxBitmapHandler::Create(wxGDIImage *image,
1559 void *data,
1560 long flags,
1561 int width, int height, int depth)
1562 {
1563 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1564
1565 return bitmap ? Create(bitmap, data, flags, width, height, depth) : FALSE;
1566 }
1567
1568 bool wxBitmapHandler::Load(wxGDIImage *image,
1569 const wxString& name,
1570 long flags,
1571 int width, int height)
1572 {
1573 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1574
1575 return bitmap ? LoadFile(bitmap, name, flags, width, height) : FALSE;
1576 }
1577
1578 bool wxBitmapHandler::Save(wxGDIImage *image,
1579 const wxString& name,
1580 int type)
1581 {
1582 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1583
1584 return bitmap ? SaveFile(bitmap, name, type) : FALSE;
1585 }
1586
1587 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap),
1588 void *WXUNUSED(data),
1589 long WXUNUSED(type),
1590 int WXUNUSED(width),
1591 int WXUNUSED(height),
1592 int WXUNUSED(depth))
1593 {
1594 return FALSE;
1595 }
1596
1597 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap),
1598 const wxString& WXUNUSED(name),
1599 long WXUNUSED(type),
1600 int WXUNUSED(desiredWidth),
1601 int WXUNUSED(desiredHeight))
1602 {
1603 return FALSE;
1604 }
1605
1606 bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap),
1607 const wxString& WXUNUSED(name),
1608 int WXUNUSED(type),
1609 const wxPalette *WXUNUSED(palette))
1610 {
1611 return FALSE;
1612 }
1613
1614 // ----------------------------------------------------------------------------
1615 // DIB functions
1616 // ----------------------------------------------------------------------------
1617
1618 #ifndef __WXMICROWIN__
1619 bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel,
1620 HPALETTE hPal, LPBITMAPINFO* lpDIBHeader)
1621 {
1622 unsigned long i, headerSize;
1623 LPBITMAPINFO lpDIBheader = NULL;
1624 LPPALETTEENTRY lpPe = NULL;
1625
1626
1627 // Allocate space for a DIB header
1628 headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY)));
1629 lpDIBheader = (BITMAPINFO *) malloc(headerSize);
1630 lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER));
1631
1632 GetPaletteEntries(hPal, 0, 256, lpPe);
1633
1634 memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER));
1635
1636 // Fill in the static parts of the DIB header
1637 lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1638 lpDIBheader->bmiHeader.biWidth = xSize;
1639 lpDIBheader->bmiHeader.biHeight = ySize;
1640 lpDIBheader->bmiHeader.biPlanes = 1;
1641
1642 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
1643 lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel);
1644 lpDIBheader->bmiHeader.biCompression = BI_RGB;
1645 lpDIBheader->bmiHeader.biSizeImage = xSize * abs(ySize) * bitsPerPixel >> 3;
1646 lpDIBheader->bmiHeader.biClrUsed = 256;
1647
1648
1649 // Initialize the DIB palette
1650 for (i = 0; i < 256; i++) {
1651 lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags;
1652 lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed;
1653 lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen;
1654 lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue;
1655 }
1656
1657 *lpDIBHeader = lpDIBheader;
1658
1659 return TRUE;
1660 }
1661
1662 void wxFreeDIB(LPBITMAPINFO lpDIBHeader)
1663 {
1664 free(lpDIBHeader);
1665 }
1666 #endif
1667
1668 // ----------------------------------------------------------------------------
1669 // other helper functions
1670 // ----------------------------------------------------------------------------
1671
1672 extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h)
1673 {
1674 #ifndef __WXMICROWIN__
1675 wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") );
1676
1677 // get width/height from the bitmap if not given
1678 if ( !w || !h )
1679 {
1680 BITMAP bm;
1681 ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm);
1682 w = bm.bmWidth;
1683 h = bm.bmHeight;
1684 }
1685
1686 HDC hdcSrc = ::CreateCompatibleDC(NULL);
1687 HDC hdcDst = ::CreateCompatibleDC(NULL);
1688 if ( !hdcSrc || !hdcDst )
1689 {
1690 wxLogLastError(wxT("CreateCompatibleDC"));
1691 }
1692
1693 HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0);
1694 if ( !hbmpInvMask )
1695 {
1696 wxLogLastError(wxT("CreateBitmap"));
1697 }
1698
1699 ::SelectObject(hdcSrc, hbmpMask);
1700 ::SelectObject(hdcDst, hbmpInvMask);
1701 if ( !::BitBlt(hdcDst, 0, 0, w, h,
1702 hdcSrc, 0, 0,
1703 NOTSRCCOPY) )
1704 {
1705 wxLogLastError(wxT("BitBlt"));
1706 }
1707
1708 ::DeleteDC(hdcSrc);
1709 ::DeleteDC(hdcDst);
1710
1711 return hbmpInvMask;
1712 #else
1713 return 0;
1714 #endif
1715 }