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