Fix Ok/IsOk() mess in wxGDIObject-derived classes; also added
[wxWidgets.git] / src / cocoa / bitmap.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/bitmap.mm
3 // Purpose:     wxBitmap
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/07/19
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2003 David Elliott
9 // Licence:     wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/bitmap.h"
15
16 #ifndef WX_PRECOMP
17     #include "wx/log.h"
18     #include "wx/utils.h"
19     #include "wx/palette.h"
20     #include "wx/icon.h"
21     #include "wx/colour.h"
22     #include "wx/image.h"
23 #endif //WX_PRECOMP
24
25 #include "wx/xpmdecod.h"
26 #include "wx/rawbmp.h"
27
28 #include "wx/cocoa/autorelease.h"
29 #include "wx/cocoa/string.h"
30
31 #import <AppKit/NSBitmapImageRep.h>
32 #import <AppKit/NSGraphics.h>
33 #import <AppKit/NSImage.h>
34 #import <AppKit/NSColor.h>
35
36 IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandler, wxBitmapHandlerBase)
37
38 // ========================================================================
39 // wxBitmapRefData
40 // ========================================================================
41 class wxBitmapRefData: public wxGDIRefData
42 {
43     friend class wxBitmap;
44 public:
45     wxBitmapRefData();
46     wxBitmapRefData( const wxBitmapRefData& data );
47     virtual ~wxBitmapRefData();
48
49     virtual bool IsOk() const { return m_ok; }
50
51 protected:
52     int                 m_width;
53     int                 m_height;
54     int                 m_depth;
55     bool                m_ok;
56     int                 m_numColors;
57     wxPalette           m_bitmapPalette;
58     int                 m_quality;
59     WX_NSBitmapImageRep m_cocoaNSBitmapImageRep;
60     wxMask             *m_bitmapMask; // Optional mask
61 };
62
63 #define M_BITMAPDATA ((wxBitmapRefData *)m_refData)
64
65 wxBitmapRefData::wxBitmapRefData()
66 {
67     m_ok = FALSE;
68     m_width = 0;
69     m_height = 0;
70     m_depth = 0;
71     m_quality = 0;
72     m_numColors = 0;
73     m_cocoaNSBitmapImageRep = nil;
74     m_bitmapMask = NULL;
75 }
76
77 wxBitmapRefData::wxBitmapRefData( const wxBitmapRefData& data)
78 {
79     m_width = data.m_width;
80     m_height = data.m_height;
81     m_depth = data.m_depth;
82     m_ok = data.m_ok;
83     m_numColors = data.m_numColors;
84     m_bitmapPalette = data.m_bitmapPalette;
85     m_quality = data.m_quality;
86     m_cocoaNSBitmapImageRep = [data.m_cocoaNSBitmapImageRep copyWithZone:nil];
87     m_bitmapMask = data.m_bitmapMask?new wxMask(*data.m_bitmapMask):NULL;
88 }
89
90 wxBitmapRefData::~wxBitmapRefData()
91 {
92     [m_cocoaNSBitmapImageRep release];
93     m_cocoaNSBitmapImageRep = NULL;
94
95     delete m_bitmapMask;
96     m_bitmapMask = NULL;
97 }
98
99 // ========================================================================
100 // wxBitmap
101 // ========================================================================
102 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
103
104 wxBitmap::wxBitmap()
105 {
106     m_refData = NULL;
107 }
108
109 wxBitmap::~wxBitmap()
110 {
111 }
112
113 wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
114 {
115     m_refData = new wxBitmapRefData;
116
117     M_BITMAPDATA->m_width = the_width ;
118     M_BITMAPDATA->m_height = the_height ;
119     M_BITMAPDATA->m_depth = no_bits ;
120     M_BITMAPDATA->m_numColors = 0;
121
122     /* TODO: create the bitmap from data */
123 }
124
125 wxBitmap::wxBitmap(int w, int h, int d)
126 {
127     (void)Create(w, h, d);
128 }
129
130 wxBitmap::wxBitmap(NSImage* cocoaNSImage)
131 {
132     (void) Create(cocoaNSImage);
133 }
134
135 wxBitmap::wxBitmap(NSBitmapImageRep* cocoaNSBitmapImageRep)
136 {
137     (void) Create(cocoaNSBitmapImageRep);
138 }
139
140 wxBitmap::wxBitmap(const void* data, wxBitmapType type, int width, int height, int depth)
141 {
142     (void) Create(data, type, width, height, depth);
143 }
144
145 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
146 {
147     LoadFile(filename, type);
148 }
149
150 wxGDIRefData *wxBitmap::CreateGDIRefData() const
151 {
152     return new wxBitmapRefData;
153 }
154
155 wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const
156 {
157     return new wxBitmapRefData(*(wxBitmapRefData*)data);
158 }
159
160 WX_NSBitmapImageRep wxBitmap::GetNSBitmapImageRep()
161 {
162     if(!M_BITMAPDATA)
163         return NULL;
164     return M_BITMAPDATA->m_cocoaNSBitmapImageRep;
165 }
166
167 WX_NSImage wxBitmap::GetNSImage(bool useMask) const
168 {
169     if(!Ok())
170         return nil;
171     NSImage *nsimage = [[[NSImage alloc]
172             initWithSize:NSMakeSize(GetWidth(), GetHeight())] autorelease];
173     if(!nsimage)
174         return nil;
175     [nsimage addRepresentation: M_BITMAPDATA->m_cocoaNSBitmapImageRep];
176     if(useMask && GetMask())
177     {
178         // Show before/after to prove that the bitmap itself is not changed
179         // even though we just composited onto the NSImage
180         wxLogTrace(wxTRACE_COCOA,wxT("Before: bpp=%d"),[M_BITMAPDATA->m_cocoaNSBitmapImageRep bitsPerPixel]);
181         NSImage *maskImage = [[NSImage alloc]
182                 initWithSize:NSMakeSize(GetWidth(), GetHeight())];
183         [maskImage addRepresentation: GetMask()->GetNSBitmapImageRep()];
184         [nsimage lockFocus];
185         [maskImage compositeToPoint:NSZeroPoint operation:NSCompositeDestinationIn];
186         [nsimage unlockFocus];
187         [maskImage release];
188         wxLogTrace(wxTRACE_COCOA,wxT("After: bpp=%d"),[M_BITMAPDATA->m_cocoaNSBitmapImageRep bitsPerPixel]);
189     }
190     return nsimage;
191 }
192
193 void wxBitmap::SetNSBitmapImageRep(WX_NSBitmapImageRep bitmapImageRep)
194 {
195     if(!M_BITMAPDATA)
196         return;
197     // NOTE: No checking is done to make sure width/height agree
198     [bitmapImageRep retain];
199     [M_BITMAPDATA->m_cocoaNSBitmapImageRep release];
200     M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImageRep;
201 }
202
203 void wxBitmap::SetWidth(int w)
204 {
205     if (!M_BITMAPDATA)
206         m_refData = new wxBitmapRefData;
207
208     M_BITMAPDATA->m_width = w;
209 }
210
211 void wxBitmap::SetHeight(int h)
212 {
213     if (!M_BITMAPDATA)
214         m_refData = new wxBitmapRefData;
215
216     M_BITMAPDATA->m_height = h;
217 }
218
219 void wxBitmap::SetDepth(int d)
220 {
221     if (!M_BITMAPDATA)
222         m_refData = new wxBitmapRefData;
223
224     M_BITMAPDATA->m_depth = d;
225 }
226
227 void wxBitmap::SetQuality(int q)
228 {
229     if (!M_BITMAPDATA)
230         m_refData = new wxBitmapRefData;
231
232     M_BITMAPDATA->m_quality = q;
233 }
234
235 void wxBitmap::SetOk(bool isOk)
236 {
237     if (!M_BITMAPDATA)
238         m_refData = new wxBitmapRefData;
239
240     M_BITMAPDATA->m_ok = isOk;
241 }
242
243 void wxBitmap::SetPalette(const wxPalette& palette)
244 {
245     if (!M_BITMAPDATA)
246         m_refData = new wxBitmapRefData;
247
248     M_BITMAPDATA->m_bitmapPalette = palette ;
249 }
250
251 void wxBitmap::SetMask(wxMask *mask)
252 {
253     if (!M_BITMAPDATA)
254         m_refData = new wxBitmapRefData;
255
256     M_BITMAPDATA->m_bitmapMask = mask ;
257 }
258
259 wxPalette* wxBitmap::GetPalette() const
260 {
261     if(!m_refData)
262         return NULL;
263     return &M_BITMAPDATA->m_bitmapPalette;
264 }
265
266 wxMask* wxBitmap::GetMask() const
267 {
268     if(!m_refData)
269         return NULL;
270     return M_BITMAPDATA->m_bitmapMask;
271 }
272
273 int wxBitmap::GetDepth() const
274 {
275     if(!m_refData)
276         return 0;
277     return M_BITMAPDATA->m_depth;
278 }
279
280 int wxBitmap::GetWidth() const
281 {
282     if(!m_refData)
283         return 0;
284     return M_BITMAPDATA->m_width;
285 }
286
287 int wxBitmap::GetHeight() const
288 {
289     if(!m_refData)
290         return 0;
291     return M_BITMAPDATA->m_height;
292 }
293
294 bool wxBitmap::Create(int w, int h, int d)
295 {
296     UnRef();
297
298     m_refData = new wxBitmapRefData;
299
300     M_BITMAPDATA->m_width = w;
301     M_BITMAPDATA->m_height = h;
302     M_BITMAPDATA->m_depth = d;
303
304     /* TODO: create new bitmap */
305     M_BITMAPDATA->m_cocoaNSBitmapImageRep = [[NSBitmapImageRep alloc]
306             initWithBitmapDataPlanes: NULL
307             pixelsWide: w
308             pixelsHigh: h
309             bitsPerSample: 8
310             samplesPerPixel: 3
311             hasAlpha: NO
312             isPlanar: NO
313             colorSpaceName: NSCalibratedRGBColorSpace
314             bytesPerRow: 0  // NOTE: Contrary to Apple documentation Mac OS
315                             // 10.4 will add padding bytes when 0 is used here
316             bitsPerPixel: 0];
317
318     wxLogTrace(wxTRACE_COCOA,wxT("M_BITMAPDATA=%p NSBitmapImageRep bitmapData=%p"), M_BITMAPDATA, [M_BITMAPDATA->m_cocoaNSBitmapImageRep bitmapData]);
319     M_BITMAPDATA->m_ok = true;
320     M_BITMAPDATA->m_numColors = 0;
321     M_BITMAPDATA->m_quality = 0;
322     M_BITMAPDATA->m_bitmapMask = NULL;
323
324     return M_BITMAPDATA->m_ok;
325 }
326
327 bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
328 {
329     wxAutoNSAutoreleasePool pool;
330     UnRef();
331
332     m_refData = new wxBitmapRefData;
333
334     NSBitmapImageRep *imageRep = [NSBitmapImageRep
335         imageRepWithContentsOfFile:wxNSStringWithWxString(filename)];
336
337     if(imageRep)
338     {
339         M_BITMAPDATA->m_width = [imageRep pixelsWide];
340         M_BITMAPDATA->m_height = [imageRep pixelsHigh];
341         M_BITMAPDATA->m_depth = 24; // FIXME
342         M_BITMAPDATA->m_ok = true;
343         M_BITMAPDATA->m_numColors = 0;
344         M_BITMAPDATA->m_quality = 0;
345         M_BITMAPDATA->m_cocoaNSBitmapImageRep = [imageRep retain];
346         M_BITMAPDATA->m_bitmapMask = NULL;
347         return true;
348     }
349     wxImage image;
350     if(!image.LoadFile(filename,type))
351         return false;
352     if(!image.Ok())
353         return false;
354     *this = wxBitmap(image);
355     return true;
356 }
357
358 bool wxBitmap::Create(NSImage* cocoaNSImage)
359 {
360     wxAutoNSAutoreleasePool pool;
361     NSBitmapImageRep *bitmapImageRep = [NSBitmapImageRep imageRepWithData:[cocoaNSImage TIFFRepresentation]];
362     return Create(bitmapImageRep);
363 }
364
365 bool wxBitmap::Create(NSBitmapImageRep *imageRep)
366 {
367     UnRef();
368     m_refData = new wxBitmapRefData;
369     if(imageRep != nil)
370     {
371         M_BITMAPDATA->m_width = [imageRep pixelsWide];
372         M_BITMAPDATA->m_height = [imageRep pixelsHigh];
373         M_BITMAPDATA->m_depth = [imageRep bitsPerPixel];
374         M_BITMAPDATA->m_ok = true;
375         M_BITMAPDATA->m_numColors = 0;
376         M_BITMAPDATA->m_quality = 0;
377         M_BITMAPDATA->m_cocoaNSBitmapImageRep = [imageRep retain];
378         M_BITMAPDATA->m_bitmapMask = NULL;
379         return true;
380     }
381     else
382         return false;
383 }
384
385 bool wxBitmap::Create(const void* data, wxBitmapType type, int width, int height, int depth)
386 {
387     UnRef();
388
389     m_refData = new wxBitmapRefData;
390
391     return false;
392 }
393
394 bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, const wxPalette *palette) const
395 {
396     return false;
397 }
398
399 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
400 {
401     // Pool here due to lack of one during wx init phase
402     wxAutoNSAutoreleasePool pool;
403
404     UnRef();
405     if(!icon.GetNSImage());
406     [icon.GetNSImage() lockFocus];
407     NSRect imageRect;
408     imageRect.origin.x = imageRect.origin.y = 0.0;
409     imageRect.size = [icon.GetNSImage() size];
410     NSBitmapImageRep *newBitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect];
411     [icon.GetNSImage() unlockFocus];
412     if(!newBitmapRep)
413         return false;
414     m_refData = new wxBitmapRefData;
415     M_BITMAPDATA->m_cocoaNSBitmapImageRep = newBitmapRep;
416     M_BITMAPDATA->m_width = [newBitmapRep pixelsWide];
417     M_BITMAPDATA->m_height = [newBitmapRep pixelsHigh];
418     M_BITMAPDATA->m_depth = [newBitmapRep bitsPerSample]*[newBitmapRep samplesPerPixel];
419     M_BITMAPDATA->m_ok = true;
420     M_BITMAPDATA->m_numColors = 0;
421     M_BITMAPDATA->m_quality = 0;
422     M_BITMAPDATA->m_bitmapMask = NULL;
423     return true;
424 }
425
426 wxBitmap wxBitmap::GetSubBitmap(const wxRect& rect) const
427 {
428     wxAutoNSAutoreleasePool pool;
429     if(!Ok())
430         return wxNullBitmap;
431     NSImage *nsimage = GetNSImage(false);
432
433     [nsimage lockFocus];
434     NSRect imageRect = {{0,0}, [nsimage size]};
435     imageRect.origin.x = imageRect.size.width * rect.x / GetWidth();
436     imageRect.origin.y = imageRect.size.height * rect.y / GetHeight();
437     imageRect.size.width *= wx_static_cast(CGFloat, rect.width) / GetWidth();
438     imageRect.size.height *= wx_static_cast(CGFloat, rect.height) / GetHeight();
439
440     NSBitmapImageRep *newBitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect];
441     [nsimage unlockFocus];
442
443     wxBitmap newBitmap(newBitmapRep);
444
445     return (newBitmap);
446 }
447
448 wxImage wxBitmap::ConvertToImage() const
449 {
450     wxAutoNSAutoreleasePool pool;
451     if(!Ok())
452         return /*wxImage(5,5)*/wxNullImage;
453     NSImage *nsimage = GetNSImage(false /* don't use mask */);
454     wxImage newImage(M_BITMAPDATA->m_width,M_BITMAPDATA->m_height);
455     [nsimage lockFocus];
456     for(int i=0; i < M_BITMAPDATA->m_width; i++)
457     {
458         // Don't let the pool get too big as you'll notice we're creating
459         // two autoreleased NSColor objects with every iteration.
460         wxAutoNSAutoreleasePool loopPool;
461         for(int j=0; j < M_BITMAPDATA->m_height; j++)
462         {
463             NSColor *pixelColor = NSReadPixel(NSMakePoint(i,M_BITMAPDATA->m_height - j - 1));
464             NSColor *color = [pixelColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
465             newImage.SetRGB(i,j,int([color redComponent]*255.0), int([color greenComponent]*255.0), int([color blueComponent]*255.0));
466         }
467     }
468     [nsimage unlockFocus];
469     return newImage;
470 }
471
472 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
473 {
474     UnRef();
475
476     wxCHECK_MSG(image.Ok(), false, wxT("invalid image"));
477     wxCHECK_MSG(depth == -1 || depth == 1, false, wxT("invalid bitmap depth"));
478
479     m_refData = new wxBitmapRefData();
480
481     M_BITMAPDATA->m_width = image.GetWidth();
482     M_BITMAPDATA->m_height = image.GetHeight();
483     NSBitmapImageRep *bitmapImage = [[NSBitmapImageRep alloc]
484             initWithBitmapDataPlanes: NULL
485             pixelsWide: image.GetWidth()
486             pixelsHigh: image.GetHeight()
487             bitsPerSample: 8
488             samplesPerPixel: 3
489             hasAlpha: NO
490             isPlanar: NO
491             colorSpaceName: NSCalibratedRGBColorSpace
492             bytesPerRow: image.GetWidth()*3
493             bitsPerPixel: 0];
494
495     // TODO: Specify bytesPerRow:0 and then use [bitmapImage bytesPerRow]
496     // so that the rows are aligned suitably for altivec by the OS (Tiger)
497     const int numBytes = image.GetWidth()*image.GetHeight()*3;
498     memcpy([bitmapImage bitmapData], image.GetData(), numBytes);
499     // TODO: Alpha and convert to desired depth
500     M_BITMAPDATA->m_depth = 24;
501     M_BITMAPDATA->m_ok = true;
502     M_BITMAPDATA->m_numColors = 0;
503     M_BITMAPDATA->m_quality = 0;
504     M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImage;
505     M_BITMAPDATA->m_bitmapMask = new wxMask(*this,wxColour(image.GetMaskRed(),image.GetMaskGreen(),image.GetMaskBlue()));
506     return true;
507 }
508
509 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
510 {
511     if(!Ok())
512         return NULL;
513
514     NSBitmapImageRep *bitmapRep = M_BITMAPDATA->m_cocoaNSBitmapImageRep;
515     if(!bitmapRep)
516         return NULL;
517
518     if([bitmapRep bitsPerPixel]!=bpp)
519     {
520         wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") );
521         return NULL;
522     }
523     data.m_width = [bitmapRep pixelsWide];
524     data.m_height = [bitmapRep pixelsHigh];
525     data.m_stride = [bitmapRep bytesPerRow];
526     return [bitmapRep bitmapData];
527
528     // NOTE: It is up to the user to make sure they used the proper
529     // pixel format class that details what is actually inside the pixels
530     // We can only check to make sure that the total number of bits per
531     // pixel are being iterated over properly
532     // NSBitmapImageRep can contain grayscale or CMYK data and
533     // wxPixelDataBase doesn't really define the color format
534 }
535
536 void wxBitmap::UngetRawData(wxPixelDataBase& data)
537 {   // TODO
538 }
539
540 // ========================================================================
541 // wxMask
542 // ========================================================================
543
544 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
545
546 wxMask::wxMask()
547 {
548     m_cocoaNSBitmapImageRep = nil;
549 }
550
551 // Construct a mask from a bitmap and a colour indicating
552 // the transparent area
553 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
554 {
555     m_cocoaNSBitmapImageRep = nil;
556     Create(bitmap, colour);
557 }
558
559 // Construct a mask from a bitmap and a palette index indicating
560 // the transparent area
561 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
562 {
563     m_cocoaNSBitmapImageRep = nil;
564
565     Create(bitmap, paletteIndex);
566 }
567
568 // Construct a mask from a mono bitmap (copies the bitmap).
569 wxMask::wxMask(const wxBitmap& bitmap)
570 {
571     m_cocoaNSBitmapImageRep = nil;
572
573     Create(bitmap);
574 }
575
576 // Copy constructor
577 wxMask::wxMask(const wxMask& src)
578 :   wxObject(src)
579 ,   m_cocoaNSBitmapImageRep([src.m_cocoaNSBitmapImageRep retain])
580 {
581 }
582
583 wxMask::~wxMask()
584 {
585     [m_cocoaNSBitmapImageRep release];
586 }
587
588 // Create a mask from a mono bitmap (copies the bitmap).
589 bool wxMask::Create(const wxBitmap& bitmap)
590 {
591 // TODO
592     wxLogDebug(wxT("Cannot yet create a mask from a mono bitmap"));
593     return FALSE;
594 }
595
596 // Create a mask from a bitmap and a palette index indicating
597 // the transparent area
598 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
599 {
600 // TODO
601     wxLogDebug(wxT("Cannot yet create a mask from a palette bitmap"));
602     return FALSE;
603 }
604
605 template <typename PixelData>
606 static bool wxMask_CreateFromBitmapData(PixelData srcData, const wxColour& colour, unsigned char *dstData)
607 {
608     wxCHECK_MSG(dstData,false,wxT("Couldn't access mask data"));
609     typename PixelData::Iterator p(srcData);
610     const int nRows = srcData.GetHeight();
611     const int nCols = srcData.GetWidth();
612     // Total number of bytes per destination column
613     const int dstRowLength = (nCols+7)/8;
614     // Number of source columns that fit into a byte in the destination
615     const int width_aligned = nCols/8*8;
616     for(int y=0; y<nRows; ++y)
617     {
618         typename PixelData::Iterator rowStart(p);
619         unsigned char *dstRow = dstData + y*dstRowLength;
620         for(int x=0; x<width_aligned; x+=8)
621         {
622             unsigned char *dstByte = dstRow + x/8;
623             *dstByte = 0;
624             // Take source RGB, compare it with the wxColour
625             for(int j=0; j<8; ++j, ++p)
626             {
627                 *dstByte +=
628                 (   p.Red()!=colour.Red()
629                 ||  p.Green()!=colour.Green()
630                 ||  p.Blue()!=colour.Blue()
631                 )   << (7-j);
632             }
633         }
634         // Handle the remaining 0-7 pixels in the row
635         unsigned char *dstByte = dstRow + width_aligned/8;
636         if(nCols%8>0)
637             *dstByte = 0;
638         for(int j=0; j<(nCols%8); ++j, ++p)
639         {
640             *dstByte +=
641             (   p.Red()!=colour.Red()
642             ||  p.Green()!=colour.Green()
643             ||  p.Blue()!=colour.Blue()
644             )   << (7-j);
645         }
646         p = rowStart;
647         p.OffsetY(srcData,1);
648     }
649     return true;
650 }
651
652 // Create a mask from a bitmap and a colour indicating
653 // the transparent area
654 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
655 {
656     wxAutoNSAutoreleasePool pool;
657     if(!bitmap.Ok())
658         return false;
659     int bmpWidth = bitmap.GetWidth();
660     int bmpHeight = bitmap.GetHeight();
661     int dstRowLength = (bmpWidth+7)/8;
662
663     // Create a bitmap image rep with 1-bit per pixel data representing
664     // the alpha channel padded such that rows end on byte boundaries
665     // Since NSBitmapImageRep doesn't have any sort of NSNullColorSpace
666     // we must have at least one channel of non-alpha data.  In order to
667     // make our life easy, we use planar data which results in two
668     // separate arrays.  We don't need to touch the first because it
669     // should never be used.  The second is the 1-bit "alpha" data.
670     NSBitmapImageRep *maskRep = [[[NSBitmapImageRep alloc]
671         initWithBitmapDataPlanes:NULL pixelsWide:bmpWidth
672         pixelsHigh:bmpHeight bitsPerSample:1
673         samplesPerPixel:2 hasAlpha:YES isPlanar:YES
674         colorSpaceName:NSCalibratedWhiteColorSpace
675         bytesPerRow:dstRowLength bitsPerPixel:1] autorelease];
676     wxCHECK(maskRep,false);
677
678     // We need the source NSBitmapImageRep to detemine its pixel format
679     NSBitmapImageRep *srcBitmapRep = const_cast<wxBitmap&>(bitmap).GetNSBitmapImageRep();
680     wxCHECK_MSG(srcBitmapRep,false,wxT("Can't create mask for an uninitialized bitmap"));
681
682     // Get a pointer to the destination data
683     unsigned char *dstPlanes[5] = {NULL,NULL,NULL,NULL,NULL};
684     [maskRep getBitmapDataPlanes:dstPlanes];
685     unsigned char *dstData = dstPlanes[1];
686     // The wxImage format (which we use whenever we imported from wxImage)
687     if([srcBitmapRep bitsPerPixel]==24 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==3 && [srcBitmapRep hasAlpha]==NO)
688     {
689         wxPixelData<wxBitmap,wxNativePixelFormat> pixelData(const_cast<wxBitmap&>(bitmap));
690         wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData),
691             false, wxT("Unable to access raw data"));
692     }
693     // 32-bpp RGBx (x=throw away, no alpha)
694     else if([srcBitmapRep bitsPerPixel]==32 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==3 && [srcBitmapRep hasAlpha]==NO)
695     {
696         typedef wxPixelFormat<unsigned char,32,0,1,2> PixelFormat;
697         wxPixelData<wxBitmap,PixelFormat> pixelData(const_cast<wxBitmap&>(bitmap));
698         wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData),
699             false, wxT("Unable to access raw data"));
700     }
701     // 32-bpp RGBA
702     else if([srcBitmapRep bitsPerPixel]==32 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==4 && [srcBitmapRep hasAlpha]==YES)
703     {
704         wxPixelData<wxBitmap,wxAlphaPixelFormat> pixelData(const_cast<wxBitmap&>(bitmap));
705         wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData),
706             false, wxT("Unable to access raw data"));
707     }
708     else if([srcBitmapRep bitsPerPixel]==8 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==1 && [srcBitmapRep hasAlpha]==NO)
709     // 8-bpp Grayscale, no alpha
710     {   // Force all RGB to access the same grayscale component
711         typedef wxPixelFormat<unsigned char,8,0,0,0> PixelFormat;
712         wxPixelData<wxBitmap,PixelFormat> pixelData(const_cast<wxBitmap&>(bitmap));
713         wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData),
714             false, wxT("Unable to access raw data"));
715     }
716     else
717     {   wxCHECK_MSG(false,false,wxT("Unimplemented pixel format")); }
718
719     // maskRep was autoreleased in case we had to exit quickly
720     m_cocoaNSBitmapImageRep = [maskRep retain];
721     return true;
722 }