]> git.saurik.com Git - wxWidgets.git/blob - src/msw/bitmap.cpp
fixed to correctly use #if wxUSE_SPINCTRL
[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 #include "wx/msw/dib.h"
47 #include "wx/image.h"
48
49 // ----------------------------------------------------------------------------
50 // macros
51 // ----------------------------------------------------------------------------
52
53 #if !USE_SHARED_LIBRARIES
54 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
55 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
56
57 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
58 #endif
59
60 // ============================================================================
61 // implementation
62 // ============================================================================
63
64 // ----------------------------------------------------------------------------
65 // wxBitmapRefData
66 // ----------------------------------------------------------------------------
67
68 wxBitmapRefData::wxBitmapRefData()
69 {
70 m_quality = 0;
71 m_selectedInto = NULL;
72 m_numColors = 0;
73 m_bitmapMask = NULL;
74 }
75
76 void wxBitmapRefData::Free()
77 {
78 wxASSERT_MSG( !m_selectedInto,
79 wxT("deleting bitmap still selected into wxMemoryDC") );
80
81 if ( m_hBitmap)
82 {
83 if ( !::DeleteObject((HBITMAP)m_hBitmap) )
84 {
85 wxLogLastError("DeleteObject(hbitmap)");
86 }
87 }
88
89 delete m_bitmapMask;
90 m_bitmapMask = NULL;
91 }
92
93 // ----------------------------------------------------------------------------
94 // wxBitmap creation
95 // ----------------------------------------------------------------------------
96
97 // this function should be called from all wxBitmap ctors
98 void wxBitmap::Init()
99 {
100 // m_refData = NULL; done in the base class ctor
101
102 if ( wxTheBitmapList )
103 wxTheBitmapList->AddBitmap(this);
104 }
105
106 #ifdef __WIN32__
107
108 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon)
109 {
110 // it may be either HICON or HCURSOR
111 HICON hicon = (HICON)icon.GetHandle();
112
113 ICONINFO iconInfo;
114 if ( !::GetIconInfo(hicon, &iconInfo) )
115 {
116 wxLogLastError("GetIconInfo");
117
118 return FALSE;
119 }
120
121 wxBitmapRefData *refData = new wxBitmapRefData;
122 m_refData = refData;
123
124 refData->m_width = icon.GetWidth();
125 refData->m_height = icon.GetHeight();
126 refData->m_depth = wxDisplayDepth();
127
128 refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor;
129 refData->m_bitmapMask = new wxMask((WXHBITMAP)iconInfo.hbmMask);
130
131 #if WXWIN_COMPATIBILITY_2
132 refData->m_ok = TRUE;
133 #endif // WXWIN_COMPATIBILITY_2
134
135 return TRUE;
136 }
137
138 #endif // Win32
139
140 bool wxBitmap::CopyFromCursor(const wxCursor& cursor)
141 {
142 UnRef();
143
144 if ( !cursor.Ok() )
145 return FALSE;
146
147 #ifdef __WIN16__
148 wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") );
149
150 return FALSE;
151 #endif // Win16
152
153 return CopyFromIconOrCursor(cursor);
154 }
155
156 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
157 {
158 UnRef();
159
160 if ( !icon.Ok() )
161 return FALSE;
162
163 // GetIconInfo() doesn't exist under Win16 and I don't know any other way
164 // to create a bitmap from icon there - but using this way we won't have
165 // the mask (FIXME)
166 #ifdef __WIN16__
167 int width = icon.GetWidth(),
168 height = icon.GetHeight();
169
170 // copy the icon to the bitmap
171 ScreenHDC hdcScreen;
172 HDC hdc = ::CreateCompatibleDC(hdcScreen);
173 HBITMAP hbitmap = ::CreateCompatibleBitmap(hdcScreen, width, height);
174 HBITMAP hbmpOld = (HBITMAP)::SelectObject(hdc, hbitmap);
175
176 ::DrawIcon(hdc, 0, 0, GetHiconOf(icon));
177
178 ::SelectObject(hdc, hbmpOld);
179 ::DeleteDC(hdc);
180
181 wxBitmapRefData *refData = new wxBitmapRefData;
182 m_refData = refData;
183
184 refData->m_width = width;
185 refData->m_height = height;
186 refData->m_depth = wxDisplayDepth();
187
188 refData->m_hBitmap = (WXHBITMAP)hbitmap;
189
190 #if WXWIN_COMPATIBILITY_2
191 refData->m_ok = TRUE;
192 #endif // WXWIN_COMPATIBILITY_2
193
194 return TRUE;
195 #else // Win32
196 return CopyFromIconOrCursor(icon);
197 #endif // Win16/Win32
198 }
199
200 wxBitmap::~wxBitmap()
201 {
202 if (wxTheBitmapList)
203 wxTheBitmapList->DeleteObject(this);
204 }
205
206 wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
207 {
208 Init();
209
210 wxBitmapRefData *refData = new wxBitmapRefData;
211 m_refData = refData;
212
213 refData->m_width = the_width;
214 refData->m_height = the_height;
215 refData->m_depth = no_bits;
216 refData->m_numColors = 0;
217 refData->m_selectedInto = NULL;
218
219 HBITMAP hbmp = ::CreateBitmap(the_width, the_height, 1, no_bits, bits);
220 if ( !hbmp )
221 {
222 wxLogLastError("CreateBitmap");
223 }
224
225 SetHBITMAP((WXHBITMAP)hbmp);
226 }
227
228 // Create from XPM data
229 wxBitmap::wxBitmap(char **data, wxControl *WXUNUSED(anItem))
230 {
231 Init();
232
233 (void)Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0);
234 }
235
236 wxBitmap::wxBitmap(int w, int h, int d)
237 {
238 Init();
239
240 (void)Create(w, h, d);
241 }
242
243 wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth)
244 {
245 Init();
246
247 (void)Create(data, type, width, height, depth);
248 }
249
250 wxBitmap::wxBitmap(const wxString& filename, long type)
251 {
252 Init();
253
254 LoadFile(filename, (int)type);
255 }
256
257 bool wxBitmap::Create(int w, int h, int d)
258 {
259 UnRef();
260
261 m_refData = new wxBitmapRefData;
262
263 GetBitmapData()->m_width = w;
264 GetBitmapData()->m_height = h;
265 GetBitmapData()->m_depth = d;
266
267 HBITMAP hbmp;
268
269 if ( d > 0 )
270 {
271 hbmp = ::CreateBitmap(w, h, 1, d, NULL);
272 if ( !hbmp )
273 {
274 wxLogLastError("CreateBitmap");
275 }
276 }
277 else
278 {
279 ScreenHDC dc;
280 hbmp = ::CreateCompatibleBitmap(dc, w, h);
281 if ( !hbmp )
282 {
283 wxLogLastError("CreateCompatibleBitmap");
284 }
285
286 GetBitmapData()->m_depth = wxDisplayDepth();
287 }
288
289 SetHBITMAP((WXHBITMAP)hbmp);
290
291 #if WXWIN_COMPATIBILITY_2
292 GetBitmapData()->m_ok = hbmp != 0;
293 #endif // WXWIN_COMPATIBILITY_2
294
295 return Ok();
296 }
297
298 bool wxBitmap::LoadFile(const wxString& filename, long type)
299 {
300 UnRef();
301
302 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
303
304 if ( handler )
305 {
306 m_refData = new wxBitmapRefData;
307
308 return handler->LoadFile(this, filename, type, -1, -1);
309 }
310 else
311 {
312 wxImage image;
313 if ( !image.LoadFile( filename, type ) || !image.Ok() )
314 return FALSE;
315
316 *this = image.ConvertToBitmap();
317
318 return TRUE;
319 }
320 }
321
322 bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
323 {
324 UnRef();
325
326 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
327
328 if ( !handler )
329 {
330 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for "
331 "type %d defined."), type);
332
333 return FALSE;
334 }
335
336 m_refData = new wxBitmapRefData;
337
338 return handler->Create(this, data, type, width, height, depth);
339 }
340
341 bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette)
342 {
343 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
344
345 if ( handler )
346 {
347 return handler->SaveFile(this, filename, type, palette);
348 }
349 else
350 {
351 // FIXME what about palette? shouldn't we use it?
352 wxImage image( *this );
353 if (!image.Ok())
354 return FALSE;
355
356 return image.SaveFile( filename, type );
357 }
358 }
359
360 // ----------------------------------------------------------------------------
361 // wxBitmap accessors
362 // ----------------------------------------------------------------------------
363
364 void wxBitmap::SetQuality(int q)
365 {
366 EnsureHasData();
367
368 GetBitmapData()->m_quality = q;
369 }
370
371 #if WXWIN_COMPATIBILITY_2
372 void wxBitmap::SetOk(bool isOk)
373 {
374 EnsureHasData();
375
376 GetBitmapData()->m_ok = isOk;
377 }
378 #endif // WXWIN_COMPATIBILITY_2
379
380 void wxBitmap::SetPalette(const wxPalette& palette)
381 {
382 EnsureHasData();
383
384 GetBitmapData()->m_bitmapPalette = palette;
385 }
386
387 void wxBitmap::SetMask(wxMask *mask)
388 {
389 EnsureHasData();
390
391 GetBitmapData()->m_bitmapMask = mask;
392 }
393
394 // Creates a bitmap that matches the device context, from
395 // an arbitray bitmap. At present, the original bitmap must have an
396 // associated palette. TODO: use a default palette if no palette exists.
397 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
398 wxBitmap wxBitmap::GetBitmapForDC(wxDC& dc) const
399 {
400 wxMemoryDC memDC;
401 wxBitmap tmpBitmap(this->GetWidth(), this->GetHeight(), dc.GetDepth());
402 HPALETTE hPal = (HPALETTE) NULL;
403 LPBITMAPINFO lpDib;
404 void *lpBits = (void*) NULL;
405
406 if( GetPalette() && GetPalette()->Ok() )
407 {
408 tmpBitmap.SetPalette(*GetPalette());
409 memDC.SelectObject(tmpBitmap);
410 memDC.SetPalette(*GetPalette());
411 hPal = (HPALETTE)GetPalette()->GetHPALETTE();
412 }
413 else
414 {
415 hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE);
416 wxPalette palette;
417 palette.SetHPALETTE( (WXHPALETTE)hPal );
418 tmpBitmap.SetPalette( palette );
419 memDC.SelectObject(tmpBitmap);
420 memDC.SetPalette( palette );
421 }
422
423 // set the height negative because in a DIB the order of the lines is
424 // reversed
425 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal, &lpDib) )
426 {
427 return wxNullBitmap;
428 }
429
430 lpBits = malloc(lpDib->bmiHeader.biSizeImage);
431
432 ::GetBitmapBits(GetHbitmap(), lpDib->bmiHeader.biSizeImage, lpBits);
433
434 ::SetDIBitsToDevice(GetHdcOf(memDC), 0, 0,
435 GetWidth(), GetHeight(),
436 0, 0, 0, GetHeight(),
437 lpBits, lpDib, DIB_RGB_COLORS);
438
439 free(lpBits);
440
441 wxFreeDIB(lpDib);
442
443 return tmpBitmap;
444 }
445
446 // ----------------------------------------------------------------------------
447 // wxMask
448 // ----------------------------------------------------------------------------
449
450 wxMask::wxMask()
451 {
452 m_maskBitmap = 0;
453 }
454
455 // Construct a mask from a bitmap and a colour indicating
456 // the transparent area
457 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
458 {
459 m_maskBitmap = 0;
460 Create(bitmap, colour);
461 }
462
463 // Construct a mask from a bitmap and a palette index indicating
464 // the transparent area
465 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
466 {
467 m_maskBitmap = 0;
468 Create(bitmap, paletteIndex);
469 }
470
471 // Construct a mask from a mono bitmap (copies the bitmap).
472 wxMask::wxMask(const wxBitmap& bitmap)
473 {
474 m_maskBitmap = 0;
475 Create(bitmap);
476 }
477
478 wxMask::~wxMask()
479 {
480 if ( m_maskBitmap )
481 ::DeleteObject((HBITMAP) m_maskBitmap);
482 }
483
484 // Create a mask from a mono bitmap (copies the bitmap).
485 bool wxMask::Create(const wxBitmap& bitmap)
486 {
487 if ( m_maskBitmap )
488 {
489 ::DeleteObject((HBITMAP) m_maskBitmap);
490 m_maskBitmap = 0;
491 }
492 if (!bitmap.Ok() || bitmap.GetDepth() != 1)
493 {
494 return FALSE;
495 }
496 m_maskBitmap = (WXHBITMAP) CreateBitmap(
497 bitmap.GetWidth(),
498 bitmap.GetHeight(),
499 1, 1, 0
500 );
501 HDC srcDC = CreateCompatibleDC(0);
502 SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
503 HDC destDC = CreateCompatibleDC(0);
504 SelectObject(destDC, (HBITMAP) m_maskBitmap);
505 BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY);
506 SelectObject(srcDC, 0);
507 DeleteDC(srcDC);
508 SelectObject(destDC, 0);
509 DeleteDC(destDC);
510 return TRUE;
511 }
512
513 // Create a mask from a bitmap and a palette index indicating
514 // the transparent area
515 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
516 {
517 if ( m_maskBitmap )
518 {
519 ::DeleteObject((HBITMAP) m_maskBitmap);
520 m_maskBitmap = 0;
521 }
522 if (bitmap.Ok() && bitmap.GetPalette()->Ok())
523 {
524 unsigned char red, green, blue;
525 if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
526 {
527 wxColour transparentColour(red, green, blue);
528 return Create(bitmap, transparentColour);
529 }
530 }
531 return FALSE;
532 }
533
534 // Create a mask from a bitmap and a colour indicating
535 // the transparent area
536 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
537 {
538 if ( m_maskBitmap )
539 {
540 ::DeleteObject((HBITMAP) m_maskBitmap);
541 m_maskBitmap = 0;
542 }
543 if (!bitmap.Ok())
544 {
545 return FALSE;
546 }
547
548 // scan the bitmap for the transparent colour and set
549 // the corresponding pixels in the mask to BLACK and
550 // the rest to WHITE
551 COLORREF maskColour = RGB(colour.Red(), colour.Green(), colour.Blue());
552 m_maskBitmap = (WXHBITMAP) ::CreateBitmap(
553 bitmap.GetWidth(),
554 bitmap.GetHeight(),
555 1, 1, 0
556 );
557 HDC srcDC = ::CreateCompatibleDC(0);
558 ::SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
559 HDC destDC = ::CreateCompatibleDC(0);
560 ::SelectObject(destDC, (HBITMAP) m_maskBitmap);
561
562 // this is not very efficient, but I can't think
563 // of a better way of doing it
564 for (int w = 0; w < bitmap.GetWidth(); w++)
565 {
566 for (int h = 0; h < bitmap.GetHeight(); h++)
567 {
568 COLORREF col = GetPixel(srcDC, w, h);
569 if (col == maskColour)
570 {
571 ::SetPixel(destDC, w, h, RGB(0, 0, 0));
572 }
573 else
574 {
575 ::SetPixel(destDC, w, h, RGB(255, 255, 255));
576 }
577 }
578 }
579 ::SelectObject(srcDC, 0);
580 ::DeleteDC(srcDC);
581 ::SelectObject(destDC, 0);
582 ::DeleteDC(destDC);
583 return TRUE;
584 }
585
586 // ----------------------------------------------------------------------------
587 // wxBitmapHandler
588 // ----------------------------------------------------------------------------
589
590 bool wxBitmapHandler::Create(wxGDIImage *image,
591 void *data,
592 long flags,
593 int width, int height, int depth)
594 {
595 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
596
597 return bitmap ? Create(bitmap, data, width, height, depth) : FALSE;
598 }
599
600 bool wxBitmapHandler::Load(wxGDIImage *image,
601 const wxString& name,
602 long flags,
603 int width, int height)
604 {
605 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
606
607 return bitmap ? LoadFile(bitmap, name, flags, width, height) : FALSE;
608 }
609
610 bool wxBitmapHandler::Save(wxGDIImage *image,
611 const wxString& name,
612 int type)
613 {
614 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
615
616 return bitmap ? SaveFile(bitmap, name, type) : FALSE;
617 }
618
619 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap),
620 void *WXUNUSED(data),
621 long WXUNUSED(type),
622 int WXUNUSED(width),
623 int WXUNUSED(height),
624 int WXUNUSED(depth))
625 {
626 return FALSE;
627 }
628
629 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap),
630 const wxString& WXUNUSED(name),
631 long WXUNUSED(type),
632 int WXUNUSED(desiredWidth),
633 int WXUNUSED(desiredHeight))
634 {
635 return FALSE;
636 }
637
638 bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap),
639 const wxString& WXUNUSED(name),
640 int WXUNUSED(type),
641 const wxPalette *WXUNUSED(palette))
642 {
643 return FALSE;
644 }
645
646 // ----------------------------------------------------------------------------
647 // DIB functions
648 // ----------------------------------------------------------------------------
649
650 bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel,
651 HPALETTE hPal, LPBITMAPINFO* lpDIBHeader)
652 {
653 unsigned long i, headerSize;
654 LPBITMAPINFO lpDIBheader = NULL;
655 LPPALETTEENTRY lpPe = NULL;
656
657
658 // Allocate space for a DIB header
659 headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY)));
660 lpDIBheader = (BITMAPINFO *) malloc(headerSize);
661 lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER));
662
663 GetPaletteEntries(hPal, 0, 256, lpPe);
664
665 memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER));
666
667 // Fill in the static parts of the DIB header
668 lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
669 lpDIBheader->bmiHeader.biWidth = xSize;
670 lpDIBheader->bmiHeader.biHeight = ySize;
671 lpDIBheader->bmiHeader.biPlanes = 1;
672
673 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
674 lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel);
675 lpDIBheader->bmiHeader.biCompression = BI_RGB;
676 lpDIBheader->bmiHeader.biSizeImage = xSize * abs(ySize) * bitsPerPixel >> 3;
677 lpDIBheader->bmiHeader.biClrUsed = 256;
678
679
680 // Initialize the DIB palette
681 for (i = 0; i < 256; i++) {
682 lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags;
683 lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed;
684 lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen;
685 lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue;
686 }
687
688 *lpDIBHeader = lpDIBheader;
689
690 return TRUE;
691 }
692
693 void wxFreeDIB(LPBITMAPINFO lpDIBHeader)
694 {
695 free(lpDIBHeader);
696 }
697
698