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