]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/bitmap.cpp
started macosx compliant implementation
[wxWidgets.git] / src / mac / carbon / bitmap.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: bitmap.cpp
3// Purpose: wxBitmap
4// Author: AUTHOR
5// Modified by:
6// Created: ??/??/98
7// RCS-ID: $Id$
8// Copyright: (c) AUTHOR
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "bitmapbase.h"
14#pragma implementation "bitmap.h"
15#endif
16
17#include "wx/defs.h"
18
19#include "wx/bitmap.h"
20#include "wx/icon.h"
21#include "wx/log.h"
22#include "wx/image.h"
23#include "wx/xpmdecod.h"
24
25#if !USE_SHARED_LIBRARIES
26IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
27IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
28IMPLEMENT_ABSTRACT_CLASS(wxBitmapBase , wxGDIObject )
29IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandlerBase, wxObject )
30#endif
31
32#ifdef __DARWIN__
33 #include <ApplicationServices/ApplicationServices.h>
34#else
35 #include <PictUtils.h>
36#endif
37
38#include "wx/mac/uma.h"
39
40CTabHandle wxMacCreateColorTable( int numColors )
41{
42 CTabHandle newColors; /* Handle to the new color table */
43
44 /* Allocate memory for the color table */
45 newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) +
46 sizeof (ColorSpec) * (numColors - 1) );
47 if (newColors != nil)
48 {
49 /* Initialize the fields */
50 (**newColors).ctSeed = GetCTSeed();
51 (**newColors).ctFlags = 0;
52 (**newColors).ctSize = numColors - 1;
53 /* Initialize the table of colors */
54 }
55 return newColors ;
56}
57
58void wxMacDestroyColorTable( CTabHandle colors )
59{
60 DisposeHandle( (Handle) colors ) ;
61}
62
63void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue )
64{
65 (**newColors).ctTable[index].value = index;
66 (**newColors).ctTable[index].rgb.red = 0 ;// someRedValue;
67 (**newColors).ctTable[index].rgb.green = 0 ; // someGreenValue;
68 (**newColors).ctTable[index].rgb.blue = 0 ; // someBlueValue;
69}
70
71GWorldPtr wxMacCreateGWorld( int width , int height , int depth )
72{
73 OSErr err = noErr ;
74 GWorldPtr port ;
75 Rect rect = { 0 , 0 , height , width } ;
76
77 if ( depth < 0 )
78 {
79 depth = wxDisplayDepth() ;
80 }
81
82 err = NewGWorld( &port , depth , &rect , NULL , NULL , 0 ) ;
83 if ( err == noErr )
84 {
85 return port ;
86 }
87 return NULL ;
88}
89
90void wxMacDestroyGWorld( GWorldPtr gw )
91{
92 if ( gw )
93 DisposeGWorld( gw ) ;
94}
95
96#define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */
97
98OSErr SetupCIconHandlePixMap( CIconHandle icon , short depth , Rect *bounds , CTabHandle colors )
99{
100 CTabHandle newColors; /* Color table used for the off-screen PixMap */
101 Ptr offBaseAddr; /* Pointer to the off-screen pixel image */
102 OSErr error; /* Returns error code */
103 short bytesPerRow; /* Number of bytes per row in the PixMap */
104
105
106 error = noErr;
107 newColors = nil;
108 offBaseAddr = nil;
109
110 bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) / 32) * 4;
111
112 /* Clone the clut if indexed color; allocate a dummy clut if direct color*/
113 if (depth <= 8)
114 {
115 newColors = colors;
116 error = HandToHand((Handle *) &newColors);
117 }
118 else
119 {
120 newColors = (CTabHandle) NewHandle(sizeof(ColorTable) -
121 sizeof(CSpecArray));
122 error = MemError();
123 }
124 if (error == noErr)
125 {
126 /* Allocate pixel image; long integer multiplication avoids overflow */
127 (**icon).iconData = NewHandle((unsigned long) bytesPerRow * (bounds->bottom -
128 bounds->top));
129 if ((**icon).iconData != nil)
130 {
131 /* Initialize fields common to indexed and direct PixMaps */
132 (**icon).iconPMap.baseAddr = 0; /* Point to image */
133 (**icon).iconPMap.rowBytes = bytesPerRow | /* MSB set for PixMap */
134 0x8000;
135 (**icon).iconPMap.bounds = *bounds; /* Use given bounds */
136 (**icon).iconPMap.pmVersion = 0; /* No special stuff */
137 (**icon).iconPMap.packType = 0; /* Default PICT pack */
138 (**icon).iconPMap.packSize = 0; /* Always zero in mem */
139 (**icon).iconPMap.hRes = kDefaultRes; /* 72 DPI default res */
140 (**icon).iconPMap.vRes = kDefaultRes; /* 72 DPI default res */
141 (**icon).iconPMap.pixelSize = depth; /* Set # bits/pixel */
142
143 /* Initialize fields specific to indexed and direct PixMaps */
144 if (depth <= 8)
145 {
146 /* PixMap is indexed */
147 (**icon).iconPMap.pixelType = 0; /* Indicates indexed */
148 (**icon).iconPMap.cmpCount = 1; /* Have 1 component */
149 (**icon).iconPMap.cmpSize = depth; /* Component size=depth */
150 (**icon).iconPMap.pmTable = newColors; /* Handle to CLUT */
151 }
152 else
153 {
154 /* PixMap is direct */
155 (**icon).iconPMap.pixelType = RGBDirect; /* Indicates direct */
156 (**icon).iconPMap.cmpCount = 3; /* Have 3 components */
157 if (depth == 16)
158 (**icon).iconPMap.cmpSize = 5; /* 5 bits/component */
159 else
160 (**icon).iconPMap.cmpSize = 8; /* 8 bits/component */
161 (**newColors).ctSeed = 3 * (**icon).iconPMap.cmpSize;
162 (**newColors).ctFlags = 0;
163 (**newColors).ctSize = 0;
164 (**icon).iconPMap.pmTable = newColors;
165 }
166 }
167 else
168 error = MemError();
169 }
170 else
171 newColors = nil;
172
173 /* If no errors occured, return a handle to the new off-screen PixMap */
174 if (error != noErr)
175 {
176 if (newColors != nil)
177 DisposeCTable(newColors);
178 }
179
180 /* Return the error code */
181 return error;
182}
183
184CIconHandle wxMacCreateCIcon(GWorldPtr image , GWorldPtr mask , short dstDepth , short iconSize )
185{
186 GWorldPtr saveWorld;
187 GDHandle saveHandle;
188
189 GetGWorld(&saveWorld,&saveHandle); // save Graphics env state
190 SetGWorld(image,nil);
191
192 Rect frame = { 0 , 0 , iconSize , iconSize } ;
193 Rect imageBounds = frame ;
194 GetPortBounds( image , &imageBounds ) ;
195
196 int bwSize = iconSize / 8 * iconSize ;
197 CIconHandle icon = (CIconHandle) NewHandleClear( sizeof ( CIcon ) + 2 * bwSize) ;
198 HLock((Handle)icon) ;
199 SetupCIconHandlePixMap( icon , dstDepth , &frame,GetCTable(dstDepth)) ;
200 HLock( (**icon).iconData ) ;
201 (**icon).iconPMap.baseAddr = *(**icon).iconData ;
202
203 LockPixels(GetGWorldPixMap(image));
204
205 CopyBits(GetPortBitMapForCopyBits(image),
206 (BitMapPtr)&((**icon).iconPMap),
207 &imageBounds,
208 &imageBounds,
209 srcCopy | ditherCopy, nil);
210
211
212 UnlockPixels(GetGWorldPixMap(image));
213 HUnlock( (**icon).iconData ) ;
214
215 (**icon).iconMask.rowBytes = iconSize / 8 ;
216 (**icon).iconMask.bounds = frame ;
217
218 (**icon).iconBMap.rowBytes = iconSize / 8 ;
219 (**icon).iconBMap.bounds = frame ;
220 (**icon).iconMask.baseAddr = (char*) &(**icon).iconMaskData ;
221 (**icon).iconBMap.baseAddr = (char*) &(**icon).iconMaskData + bwSize ;
222
223 if ( mask )
224 {
225 LockPixels(GetGWorldPixMap(mask) ) ;
226 CopyBits(GetPortBitMapForCopyBits(mask) ,
227 &(**icon).iconBMap , &imageBounds , &imageBounds, srcCopy , nil ) ;
228 CopyBits(GetPortBitMapForCopyBits(mask) ,
229 &(**icon).iconMask , &imageBounds , &imageBounds, srcCopy , nil ) ;
230 UnlockPixels(GetGWorldPixMap( mask ) ) ;
231 }
232 else
233 {
234 LockPixels(GetGWorldPixMap(image));
235 CopyBits(GetPortBitMapForCopyBits(image) ,
236 &(**icon).iconBMap , &imageBounds , &imageBounds, srcCopy , nil ) ;
237 CopyBits(GetPortBitMapForCopyBits(image) ,
238 &(**icon).iconMask , &imageBounds , &imageBounds, srcCopy , nil ) ;
239 UnlockPixels(GetGWorldPixMap(image));
240 }
241
242 (**icon).iconMask.baseAddr = NULL ;
243 (**icon).iconBMap.baseAddr = NULL ;
244 (**icon).iconPMap.baseAddr = NULL ;
245 HUnlock((Handle)icon) ;
246 SetGWorld(saveWorld,saveHandle);
247
248 return icon;
249}
250
251PicHandle wxMacCreatePict(GWorldPtr wp, GWorldPtr mask)
252{
253 CGrafPtr origPort ;
254 GDHandle origDev ;
255
256 PicHandle pict;
257
258 RGBColor white = { 0xffff ,0xffff , 0xffff } ;
259 RGBColor black = { 0x0000 ,0x0000 , 0x0000 } ;
260
261 GetGWorld( &origPort , &origDev ) ;
262
263 RgnHandle clipRgn = NULL ;
264
265 if ( mask )
266 {
267 clipRgn = NewRgn() ;
268 LockPixels( GetGWorldPixMap( mask ) ) ;
269 BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( mask ) ) ;
270 UnlockPixels( GetGWorldPixMap( mask ) ) ;
271 }
272
273 SetGWorld( wp , NULL ) ;
274 Rect portRect ;
275 GetPortBounds( wp , &portRect ) ;
276
277 pict = OpenPicture(&portRect);
278 if(pict)
279 {
280 RGBForeColor( &black ) ;
281 RGBBackColor( &white ) ;
282
283 LockPixels( GetGWorldPixMap( wp ) ) ;
284 CopyBits(GetPortBitMapForCopyBits(wp),
285 GetPortBitMapForCopyBits(wp),
286 &portRect,
287 &portRect,
288 srcCopy,clipRgn);
289 UnlockPixels( GetGWorldPixMap( wp ) ) ;
290 ClosePicture();
291 }
292 SetGWorld( origPort , origDev ) ;
293 return pict;
294}
295
296wxBitmapRefData::wxBitmapRefData()
297{
298 m_ok = FALSE;
299 m_width = 0;
300 m_height = 0;
301 m_depth = 0;
302 m_quality = 0;
303 m_numColors = 0;
304 m_bitmapMask = NULL;
305 m_hBitmap = NULL ;
306 m_hPict = NULL ;
307 m_hIcon = NULL ;
308 m_bitmapType = kMacBitmapTypeUnknownType ;
309}
310
311// TODO move this do a public function of Bitmap Ref
312static void DisposeBitmapRefData(wxBitmapRefData *data)
313{
314 switch (data->m_bitmapType)
315 {
316 case kMacBitmapTypePict :
317 {
318 if ( data->m_hPict )
319 {
320 KillPicture( data->m_hPict ) ;
321 data->m_hPict = NULL ;
322 }
323 }
324 break ;
325 case kMacBitmapTypeGrafWorld :
326 {
327 if ( data->m_hBitmap )
328 {
329 wxMacDestroyGWorld( data->m_hBitmap ) ;
330 data->m_hBitmap = NULL ;
331 }
332 }
333 break ;
334 case kMacBitmapTypeIcon :
335 if ( data->m_hIcon )
336 {
337 DisposeCIcon( data->m_hIcon ) ;
338 data->m_hIcon = NULL ;
339 }
340
341 default :
342 // unkown type ?
343 break ;
344 }
345
346 if (data->m_bitmapMask)
347 {
348 delete data->m_bitmapMask;
349 data->m_bitmapMask = NULL;
350 }
351}
352
353wxBitmapRefData::~wxBitmapRefData()
354{
355 DisposeBitmapRefData( this ) ;
356}
357
358wxList wxBitmapBase::sm_handlers;
359
360
361bool wxBitmap::CopyFromIcon(const wxIcon& icon)
362{
363 Ref(icon) ;
364 return true;
365}
366
367wxBitmap::wxBitmap()
368{
369 m_refData = NULL;
370}
371
372wxBitmap::~wxBitmap()
373{
374}
375
376wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
377{
378 m_refData = new wxBitmapRefData;
379
380 M_BITMAPDATA->m_width = the_width ;
381 M_BITMAPDATA->m_height = the_height ;
382 M_BITMAPDATA->m_depth = no_bits ;
383 M_BITMAPDATA->m_numColors = 0;
384 if ( no_bits == 1 )
385 {
386 M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ;
387 M_BITMAPDATA->m_hBitmap = wxMacCreateGWorld( the_width , the_height , no_bits ) ;
388 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_hBitmap != NULL ) ;
389
390 CGrafPtr origPort ;
391 GDHandle origDevice ;
392
393 GetGWorld( &origPort , &origDevice ) ;
394 SetGWorld( M_BITMAPDATA->m_hBitmap , NULL ) ;
395 LockPixels( GetGWorldPixMap( M_BITMAPDATA->m_hBitmap ) ) ;
396
397 // bits is a char array
398
399 unsigned char* linestart = (unsigned char*) bits ;
400 int linesize = ( the_width / (sizeof(unsigned char) * 8)) ;
401 if ( the_width % (sizeof(unsigned char) * 8) ) {
402 linesize += sizeof(unsigned char);
403 }
404
405 RGBColor colors[2] = {
406 { 0xFFFF , 0xFFFF , 0xFFFF } ,
407 { 0, 0 , 0 }
408 } ;
409
410 for ( int y = 0 ; y < the_height ; ++y , linestart += linesize )
411 {
412 for ( int x = 0 ; x < the_width ; ++x )
413 {
414 int index = x / 8 ;
415 int bit = x % 8 ;
416 int mask = 1 << bit ;
417 if ( linestart[index] & mask )
418 {
419 SetCPixel( x , y , &colors[1] ) ;
420 }
421 else
422 {
423 SetCPixel( x , y , &colors[0] ) ;
424 }
425 }
426 }
427 UnlockPixels( GetGWorldPixMap( M_BITMAPDATA->m_hBitmap ) ) ;
428
429 SetGWorld( origPort , origDevice ) ;
430 }
431 else
432 {
433 wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented"));
434 }
435}
436
437wxBitmap::wxBitmap(int w, int h, int d)
438{
439 (void)Create(w, h, d);
440}
441
442wxBitmap::wxBitmap(void *data, wxBitmapType type, int width, int height, int depth)
443{
444 (void) Create(data, type, width, height, depth);
445}
446
447wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
448{
449 LoadFile(filename, type);
450}
451
452bool wxBitmap::CreateFromXpm(const char **bits)
453{
454 wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid bitmap data") )
455 wxXPMDecoder decoder;
456 wxImage img = decoder.ReadData(bits);
457 wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid bitmap data") )
458 *this = wxBitmap(img);
459 return TRUE;
460}
461
462wxBitmap::wxBitmap(const char **bits)
463{
464 (void) CreateFromXpm(bits);
465}
466
467wxBitmap::wxBitmap(char **bits)
468{
469 (void) CreateFromXpm((const char **)bits);
470}
471
472wxBitmap wxBitmap::GetSubBitmap(const wxRect &rect) const
473{
474 wxCHECK_MSG( Ok() &&
475 (rect.x >= 0) && (rect.y >= 0) &&
476 (rect.x+rect.width <= GetWidth()) &&
477 (rect.y+rect.height <= GetHeight()),
478 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
479
480
481 wxBitmap ret( rect.width, rect.height, GetDepth() );
482 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
483
484 WXHBITMAP origPort;
485 GDHandle origDevice;
486
487 GetGWorld( &origPort, &origDevice );
488
489 // Update the subbitmaps reference data
490 wxBitmapRefData *ref = (wxBitmapRefData *)ret.GetRefData();
491
492 ref->m_numColors = M_BITMAPDATA->m_numColors;
493 ref->m_bitmapPalette = M_BITMAPDATA->m_bitmapPalette;
494 ref->m_bitmapType = M_BITMAPDATA->m_bitmapType;
495
496 // Copy sub region of this bitmap
497 if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict)
498 {
499 printf("GetSubBitmap: Copy a region of a Pict structure - TODO\n");
500 }
501 else if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypeGrafWorld)
502 {
503 // Copy mask
504 if(GetMask())
505 {
506 WXHBITMAP submask, mask;
507 RGBColor color;
508
509 mask = GetMask()->GetMaskBitmap();
510 submask = wxMacCreateGWorld(rect.width, rect.height, 1);
511 LockPixels(GetGWorldPixMap(mask));
512 LockPixels(GetGWorldPixMap(submask));
513
514 for(int yy = 0; yy < rect.height; yy++)
515 {
516 for(int xx = 0; xx < rect.width; xx++)
517 {
518 SetGWorld(mask, NULL);
519 GetCPixel(rect.x + xx, rect.y + yy, &color);
520 SetGWorld(submask, NULL);
521 SetCPixel(xx,yy, &color);
522 }
523 }
524 UnlockPixels(GetGWorldPixMap(mask));
525 UnlockPixels(GetGWorldPixMap(submask));
526 ref->m_bitmapMask = new wxMask;
527 ref->m_bitmapMask->SetMaskBitmap(submask);
528 }
529
530 // Copy bitmap
531 if(GetHBITMAP())
532 {
533 WXHBITMAP subbitmap, bitmap;
534 RGBColor color;
535
536 bitmap = GetHBITMAP();
537 subbitmap = ref->m_hBitmap ;
538 LockPixels(GetGWorldPixMap(bitmap));
539 LockPixels(GetGWorldPixMap(subbitmap));
540
541 for(int yy = 0; yy < rect.height; yy++)
542 {
543 for(int xx = 0; xx < rect.width; xx++)
544 {
545 SetGWorld(bitmap, NULL);
546 GetCPixel(rect.x + xx, rect.y + yy, &color);
547 SetGWorld(subbitmap, NULL);
548 SetCPixel(xx, yy, &color);
549 }
550 }
551 UnlockPixels(GetGWorldPixMap(bitmap));
552 UnlockPixels(GetGWorldPixMap(subbitmap));
553 }
554 }
555 SetGWorld( origPort, origDevice );
556
557 return ret;
558}
559
560bool wxBitmap::Create(int w, int h, int d)
561{
562 UnRef();
563
564 m_refData = new wxBitmapRefData;
565
566 M_BITMAPDATA->m_width = w;
567 M_BITMAPDATA->m_height = h;
568 M_BITMAPDATA->m_depth = d;
569
570 M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ;
571 M_BITMAPDATA->m_hBitmap = wxMacCreateGWorld( w , h , d ) ;
572 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_hBitmap != NULL ) ;
573 return M_BITMAPDATA->m_ok;
574}
575
576int wxBitmap::GetBitmapType() const
577{
578 wxCHECK_MSG( Ok(), kMacBitmapTypeUnknownType, wxT("invalid bitmap") );
579
580 return M_BITMAPDATA->m_bitmapType;
581}
582
583void wxBitmap::SetHBITMAP(WXHBITMAP bmp)
584{
585 DisposeBitmapRefData( M_BITMAPDATA ) ;
586
587 M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ;
588 M_BITMAPDATA->m_hBitmap = bmp ;
589 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_hBitmap != NULL ) ;
590}
591
592bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
593{
594 UnRef();
595
596 wxBitmapHandler *handler = FindHandler(type);
597
598 if ( handler )
599 {
600 m_refData = new wxBitmapRefData;
601
602 return handler->LoadFile(this, filename, type, -1, -1);
603 }
604 else
605 {
606 wxImage loadimage(filename, type);
607 if (loadimage.Ok()) {
608 *this = loadimage;
609 return true;
610 }
611 }
612 wxLogWarning("no bitmap handler for type %d defined.", type);
613 return false;
614}
615
616bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth)
617{
618 UnRef();
619
620 m_refData = new wxBitmapRefData;
621
622 wxBitmapHandler *handler = FindHandler(type);
623
624 if ( handler == NULL ) {
625 wxLogWarning("no bitmap handler for type %d defined.", type);
626
627 return FALSE;
628 }
629
630 return handler->Create(this, data, type, width, height, depth);
631}
632
633wxBitmap::wxBitmap(const wxImage& image, int depth)
634{
635 wxCHECK_RET( image.Ok(), wxT("invalid image") )
636 wxCHECK_RET( depth == -1, wxT("invalid bitmap depth") )
637
638 m_refData = new wxBitmapRefData();
639
640 // width and height of the device-dependent bitmap
641 int width = image.GetWidth();
642 int height = image.GetHeight();
643
644 // Create picture
645
646 Create( width , height , 32 ) ;
647
648 CGrafPtr origPort ;
649 GDHandle origDevice ;
650
651 PixMapHandle pixMap = GetGWorldPixMap(GetHBITMAP()) ;
652 LockPixels( pixMap );
653
654 GetGWorld( &origPort , &origDevice ) ;
655 SetGWorld( GetHBITMAP() , NULL ) ;
656
657 // Render image
658 RGBColor colorRGB ;
659
660 register unsigned char* data = image.GetData();
661 char* destinationBase = GetPixBaseAddr( pixMap );
662 register unsigned char* destination = (unsigned char*) destinationBase ;
663 for (int y = 0; y < height; y++)
664 {
665 for (int x = 0; x < width; x++)
666 {
667 *destination++ = 0 ;
668 *destination++ = *data++ ;
669 *destination++ = *data++ ;
670 *destination++ = *data++ ;
671 }
672 destinationBase += ((**pixMap).rowBytes & 0x7fff);
673 destination = (unsigned char*) destinationBase ;
674 }
675 if ( image.HasMask() )
676 {
677 data = image.GetData();
678
679 wxColour maskcolor(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue());
680 RGBColor white = { 0xffff, 0xffff, 0xffff };
681 RGBColor black = { 0 , 0 , 0 };
682 wxBitmap maskBitmap ;
683
684 maskBitmap.Create( width, height, 1);
685 LockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
686 SetGWorld(maskBitmap.GetHBITMAP(), NULL);
687
688 for (int y = 0; y < height; y++)
689 {
690 for (int x = 0; x < width; x++)
691 {
692 if ( data[0] == image.GetMaskRed() && data[1] == image.GetMaskGreen() && data[2] == image.GetMaskBlue() )
693 {
694 SetCPixel(x,y, &white);
695 }
696 else {
697 SetCPixel(x,y, &black);
698 }
699 data += 3 ;
700 }
701 } // for height
702 SetGWorld(GetHBITMAP(), NULL);
703 SetMask(new wxMask( maskBitmap ));
704 UnlockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
705 }
706
707 UnlockPixels( GetGWorldPixMap(GetHBITMAP()) );
708 SetGWorld( origPort, origDevice );
709}
710
711wxImage wxBitmap::ConvertToImage() const
712{
713 wxImage image;
714
715 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
716
717 // create an wxImage object
718 int width = GetWidth();
719 int height = GetHeight();
720 image.Create( width, height );
721
722 unsigned char *data = image.GetData();
723
724 wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") );
725
726 WXHBITMAP origPort;
727 GDHandle origDevice;
728 int index;
729 RGBColor color;
730 // background color set to RGB(16,16,16) in consistent with wxGTK
731 unsigned char mask_r=16, mask_g=16, mask_b=16;
732 SInt16 r,g,b;
733 wxMask *mask = GetMask();
734
735 GetGWorld( &origPort, &origDevice );
736 LockPixels(GetGWorldPixMap(GetHBITMAP()));
737 SetGWorld( GetHBITMAP(), NULL);
738
739 // Copy data into image
740 index = 0;
741 for (int yy = 0; yy < height; yy++)
742 {
743 for (int xx = 0; xx < width; xx++)
744 {
745 GetCPixel(xx,yy, &color);
746 r = ((color.red ) >> 8);
747 g = ((color.green ) >> 8);
748 b = ((color.blue ) >> 8);
749 data[index ] = r;
750 data[index + 1] = g;
751 data[index + 2] = b;
752 if (mask)
753 {
754 if (mask->PointMasked(xx,yy))
755 {
756 data[index ] = mask_r;
757 data[index + 1] = mask_g;
758 data[index + 2] = mask_b;
759 }
760 }
761 index += 3;
762 }
763 }
764 if (mask)
765 {
766 image.SetMaskColour( mask_r, mask_g, mask_b );
767 image.SetMask( true );
768 }
769
770 // Free resources
771 UnlockPixels(GetGWorldPixMap(GetHBITMAP()));
772 SetGWorld(origPort, origDevice);
773
774 return image;
775}
776
777
778bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type,
779 const wxPalette *palette) const
780{
781 wxBitmapHandler *handler = FindHandler(type);
782
783 if ( handler )
784 {
785 return handler->SaveFile(this, filename, type, palette);
786 }
787 else
788 {
789 wxImage image = ConvertToImage();
790
791 return image.SaveFile(filename, type);
792 }
793
794 wxLogWarning("no bitmap handler for type %d defined.", type);
795 return false;
796}
797
798bool wxBitmap::Ok() const
799{
800 return (M_BITMAPDATA && M_BITMAPDATA->m_ok);
801}
802
803int wxBitmap::GetHeight() const
804{
805 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
806
807 return M_BITMAPDATA->m_height;
808}
809
810int wxBitmap::GetWidth() const
811{
812 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
813
814 return M_BITMAPDATA->m_width;
815}
816
817int wxBitmap::GetDepth() const
818{
819 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
820
821 return M_BITMAPDATA->m_depth;
822}
823
824int wxBitmap::GetQuality() const
825{
826 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
827
828 return M_BITMAPDATA->m_quality;
829}
830
831wxMask *wxBitmap::GetMask() const
832{
833 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
834
835 return M_BITMAPDATA->m_bitmapMask;
836}
837
838void wxBitmap::SetWidth(int w)
839{
840 if (!M_BITMAPDATA)
841 m_refData = new wxBitmapRefData;
842
843 M_BITMAPDATA->m_width = w;
844}
845
846void wxBitmap::SetHeight(int h)
847{
848 if (!M_BITMAPDATA)
849 m_refData = new wxBitmapRefData;
850
851 M_BITMAPDATA->m_height = h;
852}
853
854void wxBitmap::SetDepth(int d)
855{
856 if (!M_BITMAPDATA)
857 m_refData = new wxBitmapRefData;
858
859 M_BITMAPDATA->m_depth = d;
860}
861
862void wxBitmap::SetQuality(int q)
863{
864 if (!M_BITMAPDATA)
865 m_refData = new wxBitmapRefData;
866
867 M_BITMAPDATA->m_quality = q;
868}
869
870void wxBitmap::SetOk(bool isOk)
871{
872 if (!M_BITMAPDATA)
873 m_refData = new wxBitmapRefData;
874
875 M_BITMAPDATA->m_ok = isOk;
876}
877
878wxPalette *wxBitmap::GetPalette() const
879{
880 wxCHECK_MSG( Ok(), NULL, wxT("Invalid bitmap GetPalette()") );
881
882 return &M_BITMAPDATA->m_bitmapPalette;
883}
884
885void wxBitmap::SetPalette(const wxPalette& palette)
886{
887 if (!M_BITMAPDATA)
888 m_refData = new wxBitmapRefData;
889
890 M_BITMAPDATA->m_bitmapPalette = palette ;
891}
892
893void wxBitmap::SetMask(wxMask *mask)
894{
895 if (!M_BITMAPDATA)
896 m_refData = new wxBitmapRefData;
897
898 // Remove existing mask if there is one.
899 if (M_BITMAPDATA->m_bitmapMask)
900 delete M_BITMAPDATA->m_bitmapMask;
901
902 M_BITMAPDATA->m_bitmapMask = mask ;
903}
904
905WXHBITMAP wxBitmap::GetHBITMAP() const
906{
907 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
908
909 return M_BITMAPDATA->m_hBitmap;
910}
911
912PicHandle wxBitmap::GetPict() const
913{
914 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
915
916 PicHandle picture; // This is the returned picture
917
918 // If bitmap already in Pict format return pointer
919 if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict) {
920 return M_BITMAPDATA->m_hPict;
921 }
922 else if(M_BITMAPDATA->m_bitmapType != kMacBitmapTypeGrafWorld) {
923 // Invalid bitmap
924 return NULL;
925 }
926
927 RGBColor gray = { 0xCCCC ,0xCCCC , 0xCCCC } ;
928 RGBColor white = { 0xffff ,0xffff , 0xffff } ;
929 RGBColor black = { 0x0000 ,0x0000 , 0x0000 } ;
930 CGrafPtr origPort;
931 GDHandle origDev ;
932 wxMask *mask;
933 Rect portRect ;
934
935 GetPortBounds( GetHBITMAP() , &portRect ) ;
936 int width = portRect.right - portRect.left ;
937 int height = portRect.bottom - portRect.top ;
938
939 LockPixels( GetGWorldPixMap( GetHBITMAP() ) ) ;
940 GetGWorld( &origPort , &origDev ) ;
941
942 mask = GetMask();
943
944 SetGWorld( GetHBITMAP() , NULL ) ;
945
946 picture = OpenPicture(&portRect); // open a picture, this disables drawing
947 if(!picture) {
948 return NULL;
949 }
950
951 if( mask )
952 {
953#ifdef __DARWIN__
954 RGBColor trans = white;
955#else
956 RGBBackColor( &gray );
957 EraseRect( &portRect );
958 RGBColor trans = gray;
959#endif
960 RGBForeColor( &black ) ;
961 RGBBackColor( &white ) ;
962 PenMode(transparent);
963
964 for ( int y = 0 ; y < height ; ++y )
965 {
966 for( int x = 0 ; x < width ; ++x )
967 {
968 if ( !mask->PointMasked(x,y) )
969 {
970 RGBColor col ;
971
972 GetCPixel( x + portRect.left , y + portRect.top , &col ) ;
973 SetCPixel( x + portRect.left , y + portRect.top , &col ) ;
974 }
975 else {
976 // With transparency this sets a blank pixel
977 SetCPixel( x + portRect.left , y + portRect.top , &trans);
978 }
979 }
980 }
981 }
982 else
983 {
984 RGBBackColor( &gray ) ;
985 EraseRect(&portRect);
986 RGBForeColor( &black ) ;
987 RGBBackColor( &white ) ;
988
989 CopyBits(GetPortBitMapForCopyBits(GetHBITMAP()),
990 // src PixMap - we copy image over itself -
991 GetPortBitMapForCopyBits(GetHBITMAP()),
992 // dst PixMap - no drawing occurs
993 &portRect, // srcRect - it will be recorded and compressed -
994 &portRect, // dstRect - into the picture that is open -
995 srcCopy,NULL); // copyMode and no clip region
996 }
997 ClosePicture(); // We are done recording the picture
998 UnlockPixels( GetGWorldPixMap( GetHBITMAP() ) ) ;
999 SetGWorld( origPort , origDev ) ;
1000
1001 return picture; // return our groovy pict handle
1002}
1003
1004void wxBitmap::AddHandler(wxBitmapHandler *handler)
1005{
1006 sm_handlers.Append(handler);
1007}
1008
1009void wxBitmap::InsertHandler(wxBitmapHandler *handler)
1010{
1011 sm_handlers.Insert(handler);
1012}
1013
1014bool wxBitmap::RemoveHandler(const wxString& name)
1015{
1016 wxBitmapHandler *handler = FindHandler(name);
1017 if ( handler )
1018 {
1019 sm_handlers.DeleteObject(handler);
1020 return TRUE;
1021 }
1022 else
1023 return FALSE;
1024}
1025
1026wxBitmapHandler *wxBitmap::FindHandler(const wxString& name)
1027{
1028 wxNode *node = sm_handlers.First();
1029 while ( node )
1030 {
1031 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1032 if ( handler->GetName() == name )
1033 return handler;
1034 node = node->Next();
1035 }
1036 return NULL;
1037}
1038
1039wxBitmapHandler *wxBitmap::FindHandler(const wxString& extension, wxBitmapType type)
1040{
1041 wxNode *node = sm_handlers.First();
1042 while ( node )
1043 {
1044 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1045 if ( handler->GetExtension() == extension &&
1046 (type == -1 || handler->GetType() == type) )
1047 return handler;
1048 node = node->Next();
1049 }
1050 return NULL;
1051}
1052
1053wxBitmapHandler *wxBitmap::FindHandler(wxBitmapType type)
1054{
1055 wxNode *node = sm_handlers.First();
1056 while ( node )
1057 {
1058 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1059 if (handler->GetType() == type)
1060 return handler;
1061 node = node->Next();
1062 }
1063 return NULL;
1064}
1065
1066/*
1067 * wxMask
1068 */
1069
1070wxMask::wxMask()
1071{
1072 m_maskBitmap = 0;
1073}
1074
1075// Construct a mask from a bitmap and a colour indicating
1076// the transparent area
1077wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
1078{
1079 m_maskBitmap = 0;
1080 Create(bitmap, colour);
1081}
1082
1083// Construct a mask from a bitmap and a palette index indicating
1084// the transparent area
1085wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
1086{
1087 m_maskBitmap = 0;
1088 Create(bitmap, paletteIndex);
1089}
1090
1091// Construct a mask from a mono bitmap (copies the bitmap).
1092wxMask::wxMask(const wxBitmap& bitmap)
1093{
1094 m_maskBitmap = 0;
1095 Create(bitmap);
1096}
1097
1098wxMask::~wxMask()
1099{
1100 if ( m_maskBitmap )
1101 {
1102 wxMacDestroyGWorld( m_maskBitmap ) ;
1103 m_maskBitmap = NULL ;
1104 }
1105}
1106
1107// Create a mask from a mono bitmap (copies the bitmap).
1108bool wxMask::Create(const wxBitmap& bitmap)
1109{
1110 if ( m_maskBitmap )
1111 {
1112 wxMacDestroyGWorld( m_maskBitmap ) ;
1113 m_maskBitmap = NULL ;
1114 }
1115 wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false,
1116 wxT("Cannot create mask from this bitmap type (TODO)"));
1117 // other types would require a temporary bitmap. not yet implemented
1118
1119 wxCHECK_MSG( bitmap.Ok(), false, wxT("Invalid bitmap"));
1120
1121 wxCHECK_MSG(bitmap.GetDepth() == 1, false,
1122 wxT("Cannot create mask from colour bitmap"));
1123
1124 m_maskBitmap = wxMacCreateGWorld(bitmap.GetWidth(), bitmap.GetHeight(), 1);
1125 Rect rect = { 0,0, bitmap.GetHeight(), bitmap.GetWidth() };
1126
1127 LockPixels( GetGWorldPixMap(m_maskBitmap) );
1128 LockPixels( GetGWorldPixMap(bitmap.GetHBITMAP()) );
1129 CopyBits(GetPortBitMapForCopyBits(bitmap.GetHBITMAP()),
1130 GetPortBitMapForCopyBits(m_maskBitmap),
1131 &rect, &rect, srcCopy, 0);
1132 UnlockPixels( GetGWorldPixMap(m_maskBitmap) );
1133 UnlockPixels( GetGWorldPixMap(bitmap.GetHBITMAP()) );
1134
1135 return FALSE;
1136}
1137
1138// Create a mask from a bitmap and a palette index indicating
1139// the transparent area
1140bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
1141{
1142// TODO
1143 wxCHECK_MSG( 0, false, wxT("Not implemented"));
1144 return FALSE;
1145}
1146
1147// Create a mask from a bitmap and a colour indicating
1148// the transparent area
1149bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1150{
1151 if ( m_maskBitmap )
1152 {
1153 wxMacDestroyGWorld( m_maskBitmap ) ;
1154 m_maskBitmap = NULL ;
1155 }
1156 wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false,
1157 wxT("Cannot create mask from this bitmap type (TODO)"));
1158 // other types would require a temporary bitmap. not yet implemented
1159
1160 wxCHECK_MSG( bitmap.Ok(), false, wxT("Illigal bitmap"));
1161
1162 m_maskBitmap = wxMacCreateGWorld( bitmap.GetWidth() , bitmap.GetHeight() , 1 );
1163 LockPixels( GetGWorldPixMap( m_maskBitmap ) );
1164 LockPixels( GetGWorldPixMap( bitmap.GetHBITMAP() ) );
1165 RGBColor maskColor = colour.GetPixel();
1166
1167 // this is not very efficient, but I can't think
1168 // of a better way of doing it
1169 CGrafPtr origPort ;
1170 GDHandle origDevice ;
1171 RGBColor col;
1172 RGBColor colors[2] = {
1173 { 0xFFFF, 0xFFFF, 0xFFFF },
1174 { 0, 0, 0 }};
1175
1176 GetGWorld( &origPort , &origDevice ) ;
1177 for (int w = 0; w < bitmap.GetWidth(); w++)
1178 {
1179 for (int h = 0; h < bitmap.GetHeight(); h++)
1180 {
1181 SetGWorld( bitmap.GetHBITMAP(), NULL ) ;
1182 GetCPixel( w , h , &col ) ;
1183 SetGWorld( m_maskBitmap , NULL ) ;
1184 if (col.red == maskColor.red && col.green == maskColor.green && col.blue == maskColor.blue)
1185 {
1186 SetCPixel( w , h , &colors[0] ) ;
1187 }
1188 else
1189 {
1190 SetCPixel( w , h , &colors[1] ) ;
1191 }
1192 }
1193 }
1194 UnlockPixels( GetGWorldPixMap( (CGrafPtr) m_maskBitmap ) ) ;
1195 UnlockPixels( GetGWorldPixMap( bitmap.GetHBITMAP() ) ) ;
1196 SetGWorld( origPort , origDevice ) ;
1197
1198 return TRUE;
1199}
1200
1201bool wxMask::PointMasked(int x, int y)
1202{
1203 WXHBITMAP origPort;
1204 GDHandle origDevice;
1205 RGBColor color;
1206 bool masked = true;
1207
1208 GetGWorld( &origPort, &origDevice);
1209
1210 //Set port to mask and see if it masked (1) or not ( 0 )
1211 SetGWorld(m_maskBitmap, NULL);
1212 LockPixels(GetGWorldPixMap(m_maskBitmap));
1213 GetCPixel(x,y, &color);
1214 masked = !(color.red == 0 && color.green == 0 && color.blue == 0);
1215 UnlockPixels(GetGWorldPixMap(m_maskBitmap));
1216
1217 SetGWorld( origPort, origDevice);
1218
1219 return masked;
1220}
1221
1222/*
1223 * wxBitmapHandler
1224 */
1225
1226IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
1227
1228bool wxBitmapHandler::Create(wxBitmap *bitmap, void *data, long type, int width, int height, int depth)
1229{
1230 return FALSE;
1231}
1232
1233bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1234 int desiredWidth, int desiredHeight)
1235{
1236 return FALSE;
1237}
1238
1239bool wxBitmapHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette)
1240{
1241 return FALSE;
1242}
1243
1244/*
1245 * Standard handlers
1246 */
1247
1248class WXDLLEXPORT wxPICTResourceHandler: public wxBitmapHandler
1249{
1250 DECLARE_DYNAMIC_CLASS(wxPICTResourceHandler)
1251public:
1252 inline wxPICTResourceHandler()
1253 {
1254 m_name = "Macintosh Pict resource";
1255 m_extension = "";
1256 m_type = wxBITMAP_TYPE_PICT_RESOURCE;
1257 };
1258
1259 virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1260 int desiredWidth, int desiredHeight);
1261};
1262IMPLEMENT_DYNAMIC_CLASS(wxPICTResourceHandler, wxBitmapHandler)
1263
1264bool wxPICTResourceHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1265 int desiredWidth, int desiredHeight)
1266{
1267 Str255 theName ;
1268
1269#if TARGET_CARBON
1270 c2pstrcpy( (StringPtr) theName , name ) ;
1271#else
1272 strcpy( (char *) theName , name ) ;
1273 c2pstr( (char *)theName ) ;
1274#endif
1275
1276 PicHandle thePict = (PicHandle ) GetNamedResource( 'PICT' , theName ) ;
1277 if ( thePict )
1278 {
1279 PictInfo theInfo ;
1280
1281 GetPictInfo( thePict , &theInfo , 0 , 0 , systemMethod , 0 ) ;
1282 DetachResource( (Handle) thePict ) ;
1283 M_BITMAPHANDLERDATA->m_bitmapType = kMacBitmapTypePict ;
1284 M_BITMAPHANDLERDATA->m_hPict = thePict ;
1285 M_BITMAPHANDLERDATA->m_width = theInfo.sourceRect.right - theInfo.sourceRect.left ;
1286 M_BITMAPHANDLERDATA->m_height = theInfo.sourceRect.bottom - theInfo.sourceRect.top ;
1287
1288 M_BITMAPHANDLERDATA->m_depth = theInfo.depth ;
1289 M_BITMAPHANDLERDATA->m_ok = true ;
1290 M_BITMAPHANDLERDATA->m_numColors = theInfo.uniqueColors ;
1291// M_BITMAPHANDLERDATA->m_bitmapPalette;
1292// M_BITMAPHANDLERDATA->m_quality;
1293 return TRUE ;
1294 }
1295 return FALSE ;
1296}
1297
1298#if 0 // The following is an example for creating a bitmap handler
1299
1300// TODO: bitmap handlers, a bit like this:
1301class WXDLLEXPORT wxBMPResourceHandler: public wxBitmapHandler
1302{
1303 DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler)
1304public:
1305 inline wxBMPResourceHandler()
1306 {
1307 m_name = "Windows bitmap resource";
1308 m_extension = "";
1309 m_type = wxBITMAP_TYPE_BMP_RESOURCE;
1310 };
1311
1312 virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1313 int desiredWidth, int desiredHeight);
1314};
1315IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler)
1316
1317#endif
1318
1319void wxBitmap::CleanUpHandlers()
1320{
1321 wxNode *node = sm_handlers.First();
1322 while ( node )
1323 {
1324 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1325 wxNode *next = node->Next();
1326 delete handler;
1327 delete node;
1328 node = next;
1329 }
1330}
1331
1332void wxBitmap::InitStandardHandlers()
1333{
1334 AddHandler(new wxPICTResourceHandler) ;
1335 AddHandler(new wxICONResourceHandler) ;
1336}