]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/bitmap.cpp
Committing in .
[wxWidgets.git] / src / msw / bitmap.cpp
... / ...
CommitLineData
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
68wxBitmapRefData::wxBitmapRefData()
69{
70 m_quality = 0;
71 m_selectedInto = NULL;
72 m_numColors = 0;
73 m_bitmapMask = NULL;
74}
75
76void 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
98void 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
108bool 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
140bool 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
156bool 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
200wxBitmap::~wxBitmap()
201{
202 if (wxTheBitmapList)
203 wxTheBitmapList->DeleteObject(this);
204}
205
206wxBitmap::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
229wxBitmap::wxBitmap(char **data, wxControl *WXUNUSED(anItem))
230{
231 Init();
232
233 (void)Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0);
234}
235
236wxBitmap::wxBitmap(int w, int h, int d)
237{
238 Init();
239
240 (void)Create(w, h, d);
241}
242
243wxBitmap::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
250wxBitmap::wxBitmap(const wxString& filename, long type)
251{
252 Init();
253
254 LoadFile(filename, (int)type);
255}
256
257bool 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
298bool 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
322bool 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
341bool 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
364void wxBitmap::SetQuality(int q)
365{
366 EnsureHasData();
367
368 GetBitmapData()->m_quality = q;
369}
370
371#if WXWIN_COMPATIBILITY_2
372void wxBitmap::SetOk(bool isOk)
373{
374 EnsureHasData();
375
376 GetBitmapData()->m_ok = isOk;
377}
378#endif // WXWIN_COMPATIBILITY_2
379
380void wxBitmap::SetPalette(const wxPalette& palette)
381{
382 EnsureHasData();
383
384 GetBitmapData()->m_bitmapPalette = palette;
385}
386
387void 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>
398wxBitmap 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
450wxMask::wxMask()
451{
452 m_maskBitmap = 0;
453}
454
455// Construct a mask from a bitmap and a colour indicating
456// the transparent area
457wxMask::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
465wxMask::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).
472wxMask::wxMask(const wxBitmap& bitmap)
473{
474 m_maskBitmap = 0;
475 Create(bitmap);
476}
477
478wxMask::~wxMask()
479{
480 if ( m_maskBitmap )
481 ::DeleteObject((HBITMAP) m_maskBitmap);
482}
483
484// Create a mask from a mono bitmap (copies the bitmap).
485bool 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
515bool 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
536bool 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
590bool 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
600bool 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
610bool 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
619bool 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
629bool 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
638bool 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
650bool 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
693void wxFreeDIB(LPBITMAPINFO lpDIBHeader)
694{
695 free(lpDIBHeader);
696}
697
698