Bitmap coding
[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 hPs = ::GpiCreatePS(habMain, hdc, &vSize, GPIA_ASSOC | PU_PELS);
186 if (hPs == 0)
187 {
188 wxLogLastError("GpiCreatePS Failure");
189 }
190
191 m_hDc = hDc;
192 m_hPs = hPs;
193
194 m_refData = pRefData;
195
196 refData->m_width = nTheWidth;
197 refData->m_height = nTheHeight;
198 refData->m_depth = nNoBits;
199 refData->m_numColors = 0;
200 refData->m_selectedInto = NULL;
201
202 HBITMAP hBmp = ::GpiCreateBitmap(hPs, &vHeader, 0L, NULL, &vInfo);
203 if ( !hbmp )
204 {
205 wxLogLastError("CreateBitmap");
206 }
207 SetHBITMAP((WXHBITMAP)hbmp);
208 }
209
210 // Create from XPM data
211 wxBitmap::wxBitmap(
212 char** ppData
213 , wxControl* WXUNUSED(pAnItem))
214 {
215 Init();
216
217 F (void)Create( (void *)ppData
218 ,wxBITMAP_TYPE_XPM_DATA
219 ,0
220 ,0
221 ,0
222 );
223 }
224
225 wxBitmap::wxBitmap(
226 int nW
227 , int nH
228 , int nD
229 )
230 {
231 Init();
232
233 (void)Create( nW
234 ,nH
235 ,nD
236 );
237 }
238
239 wxBitmap::wxBitmap(
240 void* pData
241 , long lType
242 , int nWidth
243 , int nHeight
244 , int nDepth
245 )
246 {
247 Init();
248
249 (void)Create( pData
250 ,lType
251 ,nWidth
252 ,nHeight
253 ,nDepth
254 );
255 }
256
257 wxBitmap::wxBitmap(
258 const wxString& rFilename
259 , long lType
260 )
261 {
262 Init();
263
264 LoadFile( rFilename
265 ,(int)lType
266 );
267 }
268
269 bool wxBitmap::Create(
270 int nW
271 , int nH
272 , int nD
273 )
274 {
275 HBITMAP hBmp;
276 BITMAPINFOHEADER2 vHeader;
277 BITMAPINFO2 vInfo;
278 HPS hpsScreen;
279 HDC hdcScreen;
280 DEVOPENSTRUCT vDop = { NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
281 SIZEL vSize = {0, 0};
282 LONG lBitCount;
283
284 wxAssert(vHabmain != NULL);
285
286 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
287 hdcScreen = ::GpiQueryDevice(hpsScreen);
288 ::DevQueryCaps(hdcScreen, CAPS_COLOR_BITCOUNT, &lBitCount);
289
290 vHeader.cbFix = sizeof(vHeader);
291 vHeader.cx = (USHORT)nW;
292 vHeader.cy = (USHORT)nH;
293 vHeader.cPlanes = (USHORT)nD;
294 vHeader.cBitCount = lBitCount;
295 vHeader.ulCompression = BCA_UNCOMP;
296 vHeader.cxResolution = 0;
297 vHeader.cyResolution = 0;
298 vHeader.cclrUsed = 0;
299 vHeader.cclrImportant = 0;
300 vHeader.usUnits = BRU_METRIC;
301 vHeader.usRecording = BRA_BOTTOMUP;
302 vHeader.usRendering = BRH_NOTHALFTONED;
303 vHeader.cSize1 = 0;
304 vHeader.cSize2 = 0;
305 vHeader.ulColorEncoding = 0;
306 vHeader.ulIdentifier = 0;
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(hpsScreen, &vHeader, 0L, NULL, &vInfo);
319 if (!hBmp)
320 {
321 wxLogLastError("CreateBitmap");
322 }
323 }
324 else
325 {
326 LONG lPlanes;
327
328 ::DevQueryCaps(hdcScreen, CAPS_COLOR_PLANES, &lPlanes);
329 hBmp = ::GpiCreateBitmap(hpsScreen, &vHeader, 0L, NULL, &vInfo);
330 if (!hBmp)
331 {
332 wxLogLastError("CreateBitmap");
333 }
334 GetBitmapData()->m_depth = wxDisplayDepth();
335 }
336 SetHBITMAP((WXHBITMAP)hBmp);
337
338 #if WXWIN_COMPATIBILITY_2
339 GetBitmapData()->m_bOk = hBmp != 0;
340 #endif // WXWIN_COMPATIBILITY_2
341
342 return Ok();
343 }
344
345 bool wxBitmap::LoadFile(
346 const wxString& rFilename
347 , long lType
348 )
349 {
350 UnRef();
351
352 wxBitmapHandler* pHandler = wxDynamicCast( FindHandler(lType)
353 ,wxBitmapHandler
354 );
355
356 if (pHandler)
357 {
358 m_refData = new wxBitmapRefData;
359
360 return(pHandler->LoadFile( this
361 ,rFilename
362 ,lType
363 , -1
364 , -1
365 );
366 }
367 else
368 {
369 wxImage vImage;
370
371 if (!vImage.LoadFile(rFilename, lType) || !image.Ok() )
372 return(FALSE);
373
374 *this = vImage.ConvertToBitmap();
375
376 return(TRUE);
377 }
378 }
379
380 bool wxBitmap::Create(
381 void* pData
382 , long lType
383 , int nWidth
384 , int nHeight
385 , int nDepth
386 )
387 {
388 UnRef();
389
390 wxBitmapHandler* pHandler = wxDynamicCast( FindHandler(lType)
391 ,wxBitmapHandler
392 );
393
394 if (!pHandler)
395 {
396 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for "
397 "type %d defined."), type);
398
399 return(FALSE);
400 }
401
402 m_refData = new wxBitmapRefData;
403
404 return(handler->Create( this
405 ,pData
406 ,lType
407 ,nWidth
408 ,nHeight
409 ,nDepth
410 ));
411 }
412
413 bool wxBitmap::SaveFile(
414 const wxString& rFilename
415 , int lType
416 , const wxPalette* pPalette
417 )
418 {
419 wxBitmapHandler* pHandler = wxDynamicCast( FindHandler(lType)
420 ,wxBitmapHandler
421 );
422
423 if (pHandler)
424 {
425 return pHandler->SaveFile( this
426 ,rFilename
427 ,lType
428 ,pPalette
429 );
430 }
431 else
432 {
433 // FIXME what about palette? shouldn't we use it?
434 wxImage vImage(*this);
435
436 if (!vImage.Ok())
437 return(FALSE);
438
439 return(vImage.SaveFile( rFilename
440 ,lType
441 ));
442 }
443 }
444
445 // ----------------------------------------------------------------------------
446 // wxBitmap accessors
447 // ----------------------------------------------------------------------------
448
449 void wxBitmap::SetQuality(
450 int nQ
451 )
452 {
453 EnsureHasData();
454
455 GetBitmapData()->m_nQuality = nQ;
456 }
457
458 #if WXWIN_COMPATIBILITY_2
459 void wxBitmap::SetOk(
460 bool bOk
461 )
462 {
463 EnsureHasData();
464
465 GetBitmapData()->m_bOk = bOk;
466 }
467 #endif // WXWIN_COMPATIBILITY_2
468
469 void wxBitmap::SetPalette(
470 const wxPalette& rPalette
471 )
472 {
473 EnsureHasData();
474
475 GetBitmapData()->m_vBitmapPalette = rPalette;
476 }
477
478 void wxBitmap::SetMask(
479 wxMask* pMask
480 )
481 {
482 EnsureHasData();
483
484 GetBitmapData()->m_pBitmapMask = pMask;
485 }
486
487 // Will try something for OS/2 but not really sure how close
488 // to the msw intent this is.
489 wxBitmap wxBitmap::GetBitmapForDC(
490 wxDC& rDc
491 ) const
492 {
493 wxMemoryDC vMemDC;
494 wxBitmap vTmpBitmap( this->GetWidth()
495 ,this->GetHeight()
496 ,rDc.GetDepth()
497 );
498 HPS hMemoryPS;
499 HPS hPs;
500 POINTL vPoint[4];
501 SIZEL vSize = {0,0}
502
503 hMemoryPS = ::GpiCreatePS(habMain, (HDC)vMemDC.m_hDc, &vSize, PU_PELS | GPIT_MICRO | GPI_ASSOC);
504 hPs = ::GpiCreatePS(habMain, (HDC)rDc.m_hDc, &vSize, PU_PELS | GPIT_MICRO | GPI_ASSOC);
505
506 // TODO: Set the points
507
508 rDc.m_oldBitmap = (WXHBITMAP)::GpiSetBitMap(hPs, (HBITMAP)vTmpBitmap.GetHBITMAP());
509 :GpiBitBlt(hPs, hMemoryPS, 4L, vPoint, &vSize, PU_PELS | GPI_ASSOC);
510
511 return tmpBitmap;
512 }
513
514 // ----------------------------------------------------------------------------
515 // wxMask
516 // ----------------------------------------------------------------------------
517
518 wxMask::wxMask()
519 {
520 m_hMaskBitmap = 0;
521 }
522
523 // Construct a mask from a bitmap and a colour indicating
524 // the transparent area
525 wxMask::wxMask(
526 const wxBitmap& rBitmap
527 , const wxColour& rColour
528 )
529 {
530 m_hMaskBitmap = 0;
531 Create( rBitmap
532 ,rColour
533 );
534 }
535
536 // Construct a mask from a bitmap and a palette index indicating
537 // the transparent area
538 wxMask::wxMask(
539 const wxBitmap& rBitmap
540 , int nPaletteIndex
541 )
542 {
543 m_hMaskBitmap = 0;
544 Create( rBitmap
545 ,nPaletteIndex
546 );
547 }
548
549 // Construct a mask from a mono bitmap (copies the bitmap).
550 wxMask::wxMask(
551 const wxBitmap& rBitmap
552 )
553 {
554 m_hMaskBitmap = 0;
555 Create(rBitmap);
556 }
557
558 wxMask::~wxMask()
559 {
560 if (m_hMaskBitmap)
561 ::GpiDeleteBitmap((HBITMAP)m_hMaskBitmap);
562 }
563
564 // Create a mask from a mono bitmap (copies the bitmap).
565 bool wxMask::Create(const wxBitmap& bitmap)
566 {
567 if ( m_maskBitmap )
568 {
569 ::DeleteObject((HBITMAP) m_maskBitmap);
570 m_maskBitmap = 0;
571 }
572 if (!bitmap.Ok() || bitmap.GetDepth() != 1)
573 {
574 return FALSE;
575 }
576 m_maskBitmap = (WXHBITMAP) CreateBitmap(
577 bitmap.GetWidth(),
578 bitmap.GetHeight(),
579 1, 1, 0
580 );
581 HDC srcDC = CreateCompatibleDC(0);
582 SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
583 HDC destDC = CreateCompatibleDC(0);
584 SelectObject(destDC, (HBITMAP) m_maskBitmap);
585 BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY);
586 SelectObject(srcDC, 0);
587 DeleteDC(srcDC);
588 SelectObject(destDC, 0);
589 DeleteDC(destDC);
590 return TRUE;
591 }
592
593 // Create a mask from a bitmap and a palette index indicating
594 // the transparent area
595 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
596 {
597 if ( m_maskBitmap )
598 {
599 ::DeleteObject((HBITMAP) m_maskBitmap);
600 m_maskBitmap = 0;
601 }
602 if (bitmap.Ok() && bitmap.GetPalette()->Ok())
603 {
604 unsigned char red, green, blue;
605 if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
606 {
607 wxColour transparentColour(red, green, blue);
608 return Create(bitmap, transparentColour);
609 }
610 }
611 return FALSE;
612 }
613
614 // Create a mask from a bitmap and a colour indicating
615 // the transparent area
616 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
617 {
618 if ( m_maskBitmap )
619 {
620 ::DeleteObject((HBITMAP) m_maskBitmap);
621 m_maskBitmap = 0;
622 }
623 if (!bitmap.Ok())
624 {
625 return FALSE;
626 }
627
628 // scan the bitmap for the transparent colour and set
629 // the corresponding pixels in the mask to BLACK and
630 // the rest to WHITE
631 COLORREF maskColour = RGB(colour.Red(), colour.Green(), colour.Blue());
632 m_maskBitmap = (WXHBITMAP) ::CreateBitmap(
633 bitmap.GetWidth(),
634 bitmap.GetHeight(),
635 1, 1, 0
636 );
637 HDC srcDC = ::CreateCompatibleDC(0);
638 ::SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
639 HDC destDC = ::CreateCompatibleDC(0);
640 ::SelectObject(destDC, (HBITMAP) m_maskBitmap);
641
642 // this is not very efficient, but I can't think
643 // of a better way of doing it
644 for (int w = 0; w < bitmap.GetWidth(); w++)
645 {
646 for (int h = 0; h < bitmap.GetHeight(); h++)
647 {
648 COLORREF col = GetPixel(srcDC, w, h);
649 if (col == maskColour)
650 {
651 ::SetPixel(destDC, w, h, RGB(0, 0, 0));
652 }
653 else
654 {
655 ::SetPixel(destDC, w, h, RGB(255, 255, 255));
656 }
657 }
658 }
659 ::SelectObject(srcDC, 0);
660 ::DeleteDC(srcDC);
661 ::SelectObject(destDC, 0);
662 ::DeleteDC(destDC);
663 return TRUE;
664 }
665
666 // ----------------------------------------------------------------------------
667 // wxBitmapHandler
668 // ----------------------------------------------------------------------------
669
670 bool wxBitmapHandler::Create(wxGDIImage *image,
671 void *data,
672 long flags,
673 int width, int height, int depth)
674 {
675 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
676
677 return bitmap ? Create(bitmap, data, width, height, depth) : FALSE;
678 }
679
680 bool wxBitmapHandler::Load(wxGDIImage *image,
681 const wxString& name,
682 long flags,
683 int width, int height)
684 {
685 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
686
687 return bitmap ? LoadFile(bitmap, name, flags, width, height) : FALSE;
688 }
689
690 bool wxBitmapHandler::Save(wxGDIImage *image,
691 const wxString& name,
692 int type)
693 {
694 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
695
696 return bitmap ? SaveFile(bitmap, name, type) : FALSE;
697 }
698
699 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap),
700 void *WXUNUSED(data),
701 long WXUNUSED(type),
702 int WXUNUSED(width),
703 int WXUNUSED(height),
704 int WXUNUSED(depth))
705 {
706 return FALSE;
707 }
708
709 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap),
710 const wxString& WXUNUSED(name),
711 long WXUNUSED(type),
712 int WXUNUSED(desiredWidth),
713 int WXUNUSED(desiredHeight))
714 {
715 return FALSE;
716 }
717
718 bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap),
719 const wxString& WXUNUSED(name),
720 int WXUNUSED(type),
721 const wxPalette *WXUNUSED(palette))
722 {
723 return FALSE;
724 }
725
726 // ----------------------------------------------------------------------------
727 // DIB functions
728 // ----------------------------------------------------------------------------
729
730 bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel,
731 HPALETTE hPal, LPBITMAPINFO* lpDIBHeader)
732 {
733 unsigned long i, headerSize;
734 LPBITMAPINFO lpDIBheader = NULL;
735 LPPALETTEENTRY lpPe = NULL;
736
737
738 // Allocate space for a DIB header
739 headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY)));
740 lpDIBheader = (BITMAPINFO *) malloc(headerSize);
741 lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER));
742
743 GetPaletteEntries(hPal, 0, 256, lpPe);
744
745 memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER));
746
747 // Fill in the static parts of the DIB header
748 lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
749 lpDIBheader->bmiHeader.biWidth = xSize;
750 lpDIBheader->bmiHeader.biHeight = ySize;
751 lpDIBheader->bmiHeader.biPlanes = 1;
752
753 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
754 lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel);
755 lpDIBheader->bmiHeader.biCompression = BI_RGB;
756 lpDIBheader->bmiHeader.biSizeImage = xSize * abs(ySize) * bitsPerPixel >> 3;
757 lpDIBheader->bmiHeader.biClrUsed = 256;
758
759
760 // Initialize the DIB palette
761 for (i = 0; i < 256; i++) {
762 lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags;
763 lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed;
764 lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen;
765 lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue;
766 }
767
768 *lpDIBHeader = lpDIBheader;
769
770 return TRUE;
771 }
772
773 void wxFreeDIB(LPBITMAPINFO lpDIBHeader)
774 {
775 free(lpDIBHeader);
776 }
777
778