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