Added simple implementation of (Get|Unget)RawData.
[wxWidgets.git] / src / cocoa / bitmap.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/bitmap.cpp
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:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13 #ifndef WX_PRECOMP
14     #include "wx/log.h"
15     #include "wx/utils.h"
16     #include "wx/palette.h"
17     #include "wx/icon.h"
18 #endif //WX_PRECOMP
19 #include "wx/bitmap.h"
20 #include "wx/image.h"
21 #include "wx/xpmdecod.h"
22 #include "wx/rawbmp.h"
23
24 #include "wx/cocoa/autorelease.h"
25 #include "wx/cocoa/string.h"
26
27 #import <AppKit/NSBitmapImageRep.h>
28 #import <AppKit/NSGraphics.h>
29
30 // ========================================================================
31 // wxBitmapRefData
32 // ========================================================================
33 class wxBitmapRefData: public wxGDIRefData
34 {
35     friend class wxBitmap;
36 public:
37     wxBitmapRefData();
38     wxBitmapRefData( const wxBitmapRefData& data );
39     virtual ~wxBitmapRefData();
40
41 protected:
42     int                 m_width;
43     int                 m_height;
44     int                 m_depth;
45     bool                m_ok;
46     int                 m_numColors;
47     wxPalette           m_bitmapPalette;
48     int                 m_quality;
49     WX_NSBitmapImageRep m_cocoaNSBitmapImageRep;
50     wxMask             *m_bitmapMask; // Optional mask
51 };
52
53 #define M_BITMAPDATA ((wxBitmapRefData *)m_refData)
54
55 wxBitmapRefData::wxBitmapRefData()
56 {
57     m_ok = FALSE;
58     m_width = 0;
59     m_height = 0;
60     m_depth = 0;
61     m_quality = 0;
62     m_numColors = 0;
63     m_cocoaNSBitmapImageRep = nil;
64     m_bitmapMask = NULL;
65 }
66
67 wxBitmapRefData::wxBitmapRefData( const wxBitmapRefData& data)
68 {
69     m_width = data.m_width;
70     m_height = data.m_height;
71     m_depth = data.m_depth;
72     m_ok = data.m_ok;
73     m_numColors = data.m_numColors;
74     m_bitmapPalette = data.m_bitmapPalette;
75     m_quality = data.m_quality;
76     m_cocoaNSBitmapImageRep = [data.m_cocoaNSBitmapImageRep copyWithZone:nil];
77     m_bitmapMask = data.m_bitmapMask?new wxMask(*data.m_bitmapMask):NULL;
78 }
79
80 wxBitmapRefData::~wxBitmapRefData()
81 {
82     [m_cocoaNSBitmapImageRep release];
83     m_cocoaNSBitmapImageRep = NULL;
84
85     delete m_bitmapMask;
86     m_bitmapMask = NULL;
87 }
88
89 // ========================================================================
90 // wxBitmap
91 // ========================================================================
92 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
93
94 wxBitmap::wxBitmap()
95 {
96     m_refData = NULL;
97 }
98
99 wxBitmap::~wxBitmap()
100 {
101 }
102
103 wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
104 {
105     m_refData = new wxBitmapRefData;
106
107     M_BITMAPDATA->m_width = the_width ;
108     M_BITMAPDATA->m_height = the_height ;
109     M_BITMAPDATA->m_depth = no_bits ;
110     M_BITMAPDATA->m_numColors = 0;
111
112     /* TODO: create the bitmap from data */
113 }
114
115 wxBitmap::wxBitmap(int w, int h, int d)
116 {
117     (void)Create(w, h, d);
118 }
119
120 wxBitmap::wxBitmap(void *data, wxBitmapType type, int width, int height, int depth)
121 {
122     (void) Create(data, type, width, height, depth);
123 }
124
125 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
126 {
127     LoadFile(filename, type);
128 }
129
130 wxObjectRefData *wxBitmap::CreateRefData() const
131 {
132     return new wxBitmapRefData;
133 }
134
135 wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *data) const
136 {
137     return new wxBitmapRefData(*(wxBitmapRefData*)data);
138 }
139
140 WX_NSBitmapImageRep wxBitmap::GetNSBitmapImageRep()
141 {
142     if(!M_BITMAPDATA)
143         return NULL;
144     return M_BITMAPDATA->m_cocoaNSBitmapImageRep;
145 }
146
147 void wxBitmap::SetNSBitmapImageRep(WX_NSBitmapImageRep bitmapImageRep)
148 {
149     if(!M_BITMAPDATA)
150         return;
151     // NOTE: No checking is done to make sure width/height agree
152     [bitmapImageRep retain];
153     [M_BITMAPDATA->m_cocoaNSBitmapImageRep release];
154     M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImageRep;
155 }
156
157 void wxBitmap::SetWidth(int w)
158 {
159     if (!M_BITMAPDATA)
160         m_refData = new wxBitmapRefData;
161
162     M_BITMAPDATA->m_width = w;
163 }
164
165 void wxBitmap::SetHeight(int h)
166 {
167     if (!M_BITMAPDATA)
168         m_refData = new wxBitmapRefData;
169
170     M_BITMAPDATA->m_height = h;
171 }
172
173 void wxBitmap::SetDepth(int d)
174 {
175     if (!M_BITMAPDATA)
176         m_refData = new wxBitmapRefData;
177
178     M_BITMAPDATA->m_depth = d;
179 }
180
181 void wxBitmap::SetQuality(int q)
182 {
183     if (!M_BITMAPDATA)
184         m_refData = new wxBitmapRefData;
185
186     M_BITMAPDATA->m_quality = q;
187 }
188
189 void wxBitmap::SetOk(bool isOk)
190 {
191     if (!M_BITMAPDATA)
192         m_refData = new wxBitmapRefData;
193
194     M_BITMAPDATA->m_ok = isOk;
195 }
196
197 void wxBitmap::SetPalette(const wxPalette& palette)
198 {
199     if (!M_BITMAPDATA)
200         m_refData = new wxBitmapRefData;
201
202     M_BITMAPDATA->m_bitmapPalette = palette ;
203 }
204
205 void wxBitmap::SetMask(wxMask *mask)
206 {
207     if (!M_BITMAPDATA)
208         m_refData = new wxBitmapRefData;
209
210     M_BITMAPDATA->m_bitmapMask = mask ;
211 }
212
213 bool wxBitmap::Ok() const
214 {
215     return m_refData && M_BITMAPDATA->m_ok;
216 }
217
218 wxPalette* wxBitmap::GetPalette() const
219 {
220     if(!m_refData)
221         return NULL;
222     return &M_BITMAPDATA->m_bitmapPalette;
223 }
224
225 wxMask* wxBitmap::GetMask() const
226 {
227     if(!m_refData)
228         return NULL;
229     return M_BITMAPDATA->m_bitmapMask;
230 }
231
232 int wxBitmap::GetDepth() const
233 {
234     if(!m_refData)
235         return 0;
236     return M_BITMAPDATA->m_depth;
237 }
238
239 int wxBitmap::GetWidth() const
240 {
241     if(!m_refData)
242         return 0;
243     return M_BITMAPDATA->m_width;
244 }
245
246 int wxBitmap::GetHeight() const
247 {
248     if(!m_refData)
249         return 0;
250     return M_BITMAPDATA->m_height;
251 }
252
253 bool wxBitmap::Create(int w, int h, int d)
254 {
255     UnRef();
256
257     m_refData = new wxBitmapRefData;
258
259     M_BITMAPDATA->m_width = w;
260     M_BITMAPDATA->m_height = h;
261     M_BITMAPDATA->m_depth = d;
262
263     /* TODO: create new bitmap */
264     M_BITMAPDATA->m_cocoaNSBitmapImageRep = [[NSBitmapImageRep alloc]
265             initWithBitmapDataPlanes: NULL
266             pixelsWide: w
267             pixelsHigh: h
268             bitsPerSample: 8
269             samplesPerPixel: 3
270             hasAlpha: NO
271             isPlanar: NO
272             colorSpaceName: NSCalibratedRGBColorSpace
273             bytesPerRow: 0
274             bitsPerPixel: 0];
275
276     wxLogDebug("M_BITMAPDATA=%p NSBitmapImageRep bitmapData=%p", M_BITMAPDATA, [M_BITMAPDATA->m_cocoaNSBitmapImageRep bitmapData]);
277     M_BITMAPDATA->m_ok = true;
278     M_BITMAPDATA->m_numColors = 0;
279     M_BITMAPDATA->m_quality = 0;
280     M_BITMAPDATA->m_bitmapMask = NULL;
281
282     return M_BITMAPDATA->m_ok;
283 }
284
285 bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
286 {
287     wxAutoNSAutoreleasePool pool;
288     UnRef();
289
290     m_refData = new wxBitmapRefData;
291
292     NSBitmapImageRep *imageRep = [NSBitmapImageRep
293         imageRepWithContentsOfFile:wxNSStringWithWxString(filename)];
294
295     if(imageRep)
296     {
297         M_BITMAPDATA->m_width = [imageRep pixelsWide];
298         M_BITMAPDATA->m_height = [imageRep pixelsHigh];
299         M_BITMAPDATA->m_depth = 24; // FIXME
300         M_BITMAPDATA->m_ok = true;
301         M_BITMAPDATA->m_numColors = 0;
302         M_BITMAPDATA->m_quality = 0;
303         M_BITMAPDATA->m_cocoaNSBitmapImageRep = [imageRep retain];
304         M_BITMAPDATA->m_bitmapMask = NULL;
305         return true;
306     }
307     wxImage image;
308     if(!image.LoadFile(filename,type))
309         return false;
310     if(!image.Ok())
311         return false;
312     *this = wxBitmap(image);
313     return true;
314 }
315
316 bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth)
317 {
318     UnRef();
319
320     m_refData = new wxBitmapRefData;
321
322     return false;
323 }
324
325 bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, const wxPalette *palette) const
326 {
327     return false;
328 }
329
330 bool wxBitmap::CopyFromIcon(const wxIcon& icno)
331 {
332     return false;
333 }
334
335 wxBitmap wxBitmap::GetSubBitmap(wxRect const&) const
336 {
337     return wxNullBitmap;
338 }
339
340 wxImage wxBitmap::ConvertToImage() const
341 {
342     if(!M_BITMAPDATA->m_ok)
343         return wxImage(5,5)/*wxNullImage*/;
344     return wxImage(M_BITMAPDATA->m_width,M_BITMAPDATA->m_height);
345 }
346
347 bool wxBitmap::CreateFromXpm(const char **xpm)
348 {
349 #if wxUSE_IMAGE && wxUSE_XPM
350     UnRef();
351
352     wxCHECK_MSG( xpm, false, wxT("invalid XPM data") )
353
354     wxXPMDecoder decoder;
355     wxImage img = decoder.ReadData(xpm);
356     wxCHECK_MSG( img.Ok(), false, wxT("invalid XPM data") )
357
358     *this = wxBitmap(img);
359     return true;
360 #else
361     return false;
362 #endif
363 }
364
365 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
366 {
367     UnRef();
368
369     wxCHECK_MSG(image.Ok(), false, wxT("invalid image"));
370     wxCHECK_MSG(depth == -1 || depth == 1, false, wxT("invalid bitmap depth"));
371
372     m_refData = new wxBitmapRefData();
373
374     M_BITMAPDATA->m_width = image.GetWidth();
375     M_BITMAPDATA->m_height = image.GetHeight();
376     NSBitmapImageRep *bitmapImage = [[NSBitmapImageRep alloc]
377             initWithBitmapDataPlanes: NULL
378             pixelsWide: image.GetWidth()
379             pixelsHigh: image.GetHeight()
380             bitsPerSample: 8
381             samplesPerPixel: 3
382             hasAlpha: NO
383             isPlanar: NO
384             colorSpaceName: NSCalibratedRGBColorSpace
385             bytesPerRow: 0
386             bitsPerPixel: 0];
387
388     const int numBytes = image.GetWidth()*image.GetHeight()*3;
389     memcpy([bitmapImage bitmapData], image.GetData(), numBytes);
390     // TODO: Alpha and convert to desired depth
391     M_BITMAPDATA->m_depth = 24;
392     M_BITMAPDATA->m_ok = true;
393     M_BITMAPDATA->m_numColors = 0;
394     M_BITMAPDATA->m_quality = 0;
395     M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImage;
396     M_BITMAPDATA->m_bitmapMask = NULL;
397     return true;
398 }
399
400 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
401 {
402     if(!Ok())
403         return NULL;
404
405     NSBitmapImageRep *bitmapRep = M_BITMAPDATA->m_cocoaNSBitmapImageRep;
406     if(!bitmapRep)
407         return NULL;
408
409     if([bitmapRep bitsPerPixel]!=bpp)
410     {
411         wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") );
412         return NULL;
413     }
414     data.m_width = [bitmapRep pixelsWide];
415     data.m_height = [bitmapRep pixelsHigh];
416     data.m_stride = [bitmapRep bytesPerRow];
417     return [bitmapRep bitmapData];
418
419     // NOTE: It is up to the user to make sure they used the proper
420     // pixel format class that details what is actually inside the pixels
421     // We can only check to make sure that the total number of bits per
422     // pixel are being iterated over properly
423     // NSBitmapImageRep can contain grayscale or CMYK data and
424     // wxPixelDataBase doesn't really define the color format
425 }
426
427 void wxBitmap::UngetRawData(wxPixelDataBase& data)
428 {   // TODO
429 }
430
431 // ========================================================================
432 // wxMask
433 // ========================================================================
434
435 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
436
437 wxMask::wxMask()
438 {
439 /* TODO
440     m_maskBitmap = 0;
441 */
442 }
443
444 // Construct a mask from a bitmap and a colour indicating
445 // the transparent area
446 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
447 {
448 /* TODO
449     m_maskBitmap = 0;
450 */
451     Create(bitmap, colour);
452 }
453
454 // Construct a mask from a bitmap and a palette index indicating
455 // the transparent area
456 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
457 {
458 /* TODO
459     m_maskBitmap = 0;
460 */
461
462     Create(bitmap, paletteIndex);
463 }
464
465 // Construct a mask from a mono bitmap (copies the bitmap).
466 wxMask::wxMask(const wxBitmap& bitmap)
467 {
468 /* TODO
469     m_maskBitmap = 0;
470 */
471
472     Create(bitmap);
473 }
474
475 wxMask::~wxMask()
476 {
477 // TODO: delete mask bitmap
478 }
479
480 // Create a mask from a mono bitmap (copies the bitmap).
481 bool wxMask::Create(const wxBitmap& bitmap)
482 {
483 // TODO
484     return FALSE;
485 }
486
487 // Create a mask from a bitmap and a palette index indicating
488 // the transparent area
489 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
490 {
491 // TODO
492     return FALSE;
493 }
494
495 // Create a mask from a bitmap and a colour indicating
496 // the transparent area
497 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
498 {
499 // TODO
500     return FALSE;
501 }
502