Always create the pixmap with an alpha channel
[wxWidgets.git] / src / gtk / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/bitmap.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #include "wx/bitmap.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/app.h"
17 #include "wx/palette.h"
18 #include "wx/icon.h"
19 #include "wx/math.h"
20 #include "wx/image.h"
21 #endif
22
23 #include "wx/rawbmp.h"
24
25 #include <gtk/gtk.h>
26
27 //-----------------------------------------------------------------------------
28 // data
29 //-----------------------------------------------------------------------------
30
31 extern GtkWidget *wxGetRootWindow();
32
33 //-----------------------------------------------------------------------------
34 // wxMask
35 //-----------------------------------------------------------------------------
36
37 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
38
39 wxMask::wxMask()
40 {
41 m_bitmap = (GdkBitmap *) NULL;
42 }
43
44 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
45 {
46 m_bitmap = (GdkBitmap *) NULL;
47 Create( bitmap, colour );
48 }
49
50 #if wxUSE_PALETTE
51 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
52 {
53 m_bitmap = (GdkBitmap *) NULL;
54 Create( bitmap, paletteIndex );
55 }
56 #endif // wxUSE_PALETTE
57
58 wxMask::wxMask( const wxBitmap& bitmap )
59 {
60 m_bitmap = (GdkBitmap *) NULL;
61 Create( bitmap );
62 }
63
64 wxMask::~wxMask()
65 {
66 if (m_bitmap)
67 g_object_unref (m_bitmap);
68 }
69
70 bool wxMask::Create( const wxBitmap& bitmap,
71 const wxColour& colour )
72 {
73 if (m_bitmap)
74 {
75 g_object_unref (m_bitmap);
76 m_bitmap = (GdkBitmap*) NULL;
77 }
78
79 const int w = bitmap.GetWidth();
80 const int h = bitmap.GetHeight();
81
82 // create mask as XBM format bitmap
83
84 // one bit per pixel, each row starts on a byte boundary
85 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
86 wxByte* out = new wxByte[out_size];
87 // set bits are white
88 memset(out, 0xff, out_size);
89 unsigned bit_index = 0;
90 if (bitmap.HasPixbuf())
91 {
92 const wxByte r_mask = colour.Red();
93 const wxByte g_mask = colour.Green();
94 const wxByte b_mask = colour.Blue();
95 GdkPixbuf* pixbuf = bitmap.GetPixbuf();
96 const wxByte* in = gdk_pixbuf_get_pixels(pixbuf);
97 const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
98 const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
99 for (int y = 0; y < h; y++, in += rowpadding)
100 {
101 for (int x = 0; x < w; x++, in += inc, bit_index++)
102 if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
103 out[bit_index >> 3] ^= 1 << (bit_index & 7);
104 // move index to next byte boundary
105 bit_index = (bit_index + 7) & ~7u;
106 }
107 }
108 else
109 {
110 GdkImage* image = gdk_drawable_get_image(bitmap.GetPixmap(), 0, 0, w, h);
111 GdkColormap* colormap = gdk_image_get_colormap(image);
112 guint32 mask_pixel = 1;
113 if (colormap != NULL)
114 {
115 wxColor c(colour);
116 c.CalcPixel(colormap);
117 mask_pixel = c.GetPixel();
118 }
119 for (int y = 0; y < h; y++)
120 {
121 for (int x = 0; x < w; x++, bit_index++)
122 if (gdk_image_get_pixel(image, x, y) == mask_pixel)
123 out[bit_index >> 3] ^= 1 << (bit_index & 7);
124 bit_index = (bit_index + 7) & ~7u;
125 }
126 g_object_unref(image);
127 }
128 m_bitmap = gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h);
129 delete[] out;
130 return true;
131 }
132
133 #if wxUSE_PALETTE
134 bool wxMask::Create( const wxBitmap& bitmap, int paletteIndex )
135 {
136 unsigned char r,g,b;
137 wxPalette *pal = bitmap.GetPalette();
138
139 wxCHECK_MSG( pal, false, wxT("Cannot create mask from bitmap without palette") );
140
141 pal->GetRGB(paletteIndex, &r, &g, &b);
142
143 return Create(bitmap, wxColour(r, g, b));
144 }
145 #endif // wxUSE_PALETTE
146
147 bool wxMask::Create( const wxBitmap& bitmap )
148 {
149 if (m_bitmap)
150 {
151 g_object_unref (m_bitmap);
152 m_bitmap = (GdkBitmap*) NULL;
153 }
154
155 if (!bitmap.Ok()) return false;
156
157 wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
158
159 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
160
161 if (!m_bitmap) return false;
162
163 GdkGC *gc = gdk_gc_new( m_bitmap );
164 gdk_gc_set_function(gc, GDK_COPY_INVERT);
165 gdk_draw_drawable(m_bitmap, gc, bitmap.GetPixmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight());
166 g_object_unref (gc);
167
168 return true;
169 }
170
171 GdkBitmap *wxMask::GetBitmap() const
172 {
173 return m_bitmap;
174 }
175
176 //-----------------------------------------------------------------------------
177 // wxBitmap
178 //-----------------------------------------------------------------------------
179
180 class wxBitmapRefData: public wxObjectRefData
181 {
182 public:
183 wxBitmapRefData();
184 ~wxBitmapRefData();
185
186 GdkPixmap *m_pixmap;
187 GdkPixbuf *m_pixbuf;
188 wxMask *m_mask;
189 int m_width;
190 int m_height;
191 int m_bpp;
192 wxPalette *m_palette;
193 };
194
195 wxBitmapRefData::wxBitmapRefData()
196 {
197 m_pixmap = (GdkPixmap *) NULL;
198 m_pixbuf = (GdkPixbuf *) NULL;
199 m_mask = (wxMask *) NULL;
200 m_width = 0;
201 m_height = 0;
202 m_bpp = 0;
203 m_palette = (wxPalette *) NULL;
204 }
205
206 wxBitmapRefData::~wxBitmapRefData()
207 {
208 if (m_pixmap)
209 g_object_unref (m_pixmap);
210 if (m_pixbuf)
211 g_object_unref (m_pixbuf);
212 delete m_mask;
213 #if wxUSE_PALETTE
214 delete m_palette;
215 #endif // wxUSE_PALETTE
216 }
217
218 //-----------------------------------------------------------------------------
219
220 #define M_BMPDATA wx_static_cast(wxBitmapRefData*, m_refData)
221
222 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
223
224 wxBitmap::wxBitmap()
225 {
226 }
227
228 wxBitmap::wxBitmap( int width, int height, int depth )
229 {
230 Create( width, height, depth );
231 }
232
233 bool wxBitmap::Create( int width, int height, int depth )
234 {
235 UnRef();
236
237 if ( width <= 0 || height <= 0 )
238 {
239 return false;
240 }
241
242 if (depth == 32)
243 {
244 SetPixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height));
245 M_BMPDATA->m_bpp = 32;
246 }
247 else
248 {
249 if (depth != 1)
250 {
251 const GdkVisual* visual = wxTheApp->GetGdkVisual();
252 if (depth == -1)
253 depth = visual->depth;
254
255 wxCHECK_MSG(depth == visual->depth, false, wxT("invalid bitmap depth"));
256 }
257
258 SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, width, height, depth));
259 }
260
261 return Ok();
262 }
263
264 bool wxBitmap::CreateFromXpm( const char **bits )
265 {
266 UnRef();
267
268 wxCHECK_MSG( bits != NULL, false, wxT("invalid bitmap data") );
269
270 GdkBitmap *mask = (GdkBitmap*) NULL;
271 SetPixmap(gdk_pixmap_create_from_xpm_d(wxGetRootWindow()->window, &mask, NULL, (gchar**)bits));
272
273 wxCHECK_MSG( M_BMPDATA->m_pixmap, false, wxT("couldn't create pixmap") );
274
275 if (mask)
276 {
277 M_BMPDATA->m_mask = new wxMask;
278 M_BMPDATA->m_mask->m_bitmap = mask;
279 }
280
281 return true;
282 }
283
284 wxBitmap wxBitmap::Rescale( int clipx, int clipy, int clipwidth, int clipheight, int newx, int newy )
285 {
286 wxBitmap bmp;
287
288 wxCHECK_MSG(Ok(), bmp, wxT("invalid bitmap"));
289
290 if (newy==M_BMPDATA->m_width && newy==M_BMPDATA->m_height)
291 return *this;
292
293 int width = wxMax(newx, 1);
294 int height = wxMax(newy, 1);
295 width = wxMin(width, clipwidth);
296 height = wxMin(height, clipheight);
297
298 if (HasPixbuf())
299 {
300 bmp.SetDepth(GetDepth());
301 bmp.SetPixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB,
302 true, //gdk_pixbuf_get_has_alpha(GetPixbuf()),
303 8, width, height));
304 gdk_pixbuf_scale(GetPixbuf(), bmp.GetPixbuf(),
305 0, 0, width, height,
306 clipx, clipy,
307 (double)newx/GetWidth(), (double)newy/GetHeight(),
308 GDK_INTERP_BILINEAR);
309 }
310 else
311 {
312 GdkImage* img = gdk_drawable_get_image(GetPixmap(), 0, 0, GetWidth(), GetHeight());
313
314 wxCHECK_MSG(img, bmp, wxT("couldn't create image"));
315
316 GdkGC *gc = NULL;
317 GdkPixmap *dstpix = NULL;
318 char *dst = NULL;
319 long dstbyteperline = 0;
320
321 if (GetDepth() != 1)
322 {
323 GdkVisual *visual = gdk_drawable_get_visual( GetPixmap() );
324 if (visual == NULL)
325 visual = wxTheApp->GetGdkVisual();
326
327 bmp = wxBitmap(width, height, visual->depth);
328 dstpix = bmp.GetPixmap();
329 gc = gdk_gc_new( dstpix );
330 }
331 else
332 {
333 dstbyteperline = (width + 7) / 8;
334 dst = (char*) malloc(dstbyteperline*height);
335 }
336
337 // be careful to use the right scaling factor
338 float scx = (float)M_BMPDATA->m_width/(float)newx;
339 float scy = (float)M_BMPDATA->m_height/(float)newy;
340 // prepare accel-tables
341 int *tablex = (int *)calloc(width,sizeof(int));
342 int *tabley = (int *)calloc(height,sizeof(int));
343
344 // accel table filled with clipped values
345 for (int x = 0; x < width; x++)
346 tablex[x] = (int) (scx * (x+clipx));
347 for (int y = 0; y < height; y++)
348 tabley[y] = (int) (scy * (y+clipy));
349
350 // Main rescaling routine starts here
351 for (int h = 0; h < height; h++)
352 {
353 char outbyte = 0;
354 int old_x = -1;
355 guint32 old_pixval = 0;
356
357 for (int w = 0; w < width; w++)
358 {
359 guint32 pixval;
360 int x = tablex[w];
361 if (x == old_x)
362 pixval = old_pixval;
363 else
364 {
365 pixval = gdk_image_get_pixel( img, x, tabley[h] );
366 old_pixval = pixval;
367 old_x = x;
368 }
369
370 if ( dst )
371 {
372 if (!pixval)
373 {
374 char bit=1;
375 char shift = bit << (w % 8);
376 outbyte |= shift;
377 }
378
379 if ((w+1)%8==0)
380 {
381 dst[h*dstbyteperline+w/8] = outbyte;
382 outbyte = 0;
383 }
384 }
385 else
386 {
387 GdkColor col;
388 col.pixel = pixval;
389 gdk_gc_set_foreground( gc, &col );
390 gdk_draw_point( dstpix, gc, w, h);
391 }
392 }
393
394 // do not forget the last byte
395 if ( dst && (width % 8 != 0) )
396 dst[h*dstbyteperline+width/8] = outbyte;
397 }
398
399 g_object_unref (img);
400 if (gc) g_object_unref (gc);
401
402 if ( dst )
403 {
404 bmp = wxBitmap( (const char *)dst, width, height, 1 );
405 free( dst );
406 }
407
408 if (GetMask())
409 {
410 dstbyteperline = (width + 7) / 8;
411 dst = (char*) malloc(dstbyteperline*height);
412 img = gdk_drawable_get_image(GetMask()->GetBitmap(), 0, 0, GetWidth(), GetHeight());
413
414 for (int h = 0; h < height; h++)
415 {
416 char outbyte = 0;
417 int old_x = -1;
418 guint32 old_pixval = 0;
419
420 for (int w = 0; w < width; w++)
421 {
422 guint32 pixval;
423 int x = tablex[w];
424 if (x == old_x)
425 pixval = old_pixval;
426 else
427 {
428 pixval = gdk_image_get_pixel( img, x, tabley[h] );
429 old_pixval = pixval;
430 old_x = x;
431 }
432
433 if (pixval)
434 {
435 char bit=1;
436 char shift = bit << (w % 8);
437 outbyte |= shift;
438 }
439
440 if ((w+1)%8 == 0)
441 {
442 dst[h*dstbyteperline+w/8] = outbyte;
443 outbyte = 0;
444 }
445 }
446
447 // do not forget the last byte
448 if (width % 8 != 0)
449 dst[h*dstbyteperline+width/8] = outbyte;
450 }
451 wxMask* mask = new wxMask;
452 mask->m_bitmap = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) dst, width, height );
453 bmp.SetMask(mask);
454
455 free( dst );
456 g_object_unref (img);
457 }
458
459 free( tablex );
460 free( tabley );
461 }
462
463 return bmp;
464 }
465
466 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
467 {
468 UnRef();
469
470 wxCHECK_MSG( image.Ok(), false, wxT("invalid image") );
471 wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") );
472
473 if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
474 return false;
475
476 if (depth == 1)
477 return CreateFromImageAsPixmap(image, depth);
478
479 if (image.HasAlpha())
480 return CreateFromImageAsPixbuf(image);
481
482 return CreateFromImageAsPixmap(image, depth);
483 }
484
485 bool wxBitmap::CreateFromImageAsPixmap(const wxImage& image, int depth)
486 {
487 const int w = image.GetWidth();
488 const int h = image.GetHeight();
489 if (depth == 1)
490 {
491 // create XBM format bitmap
492
493 // one bit per pixel, each row starts on a byte boundary
494 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
495 wxByte* out = new wxByte[out_size];
496 // set bits are white
497 memset(out, 0xff, out_size);
498 const wxByte* in = image.GetData();
499 unsigned bit_index = 0;
500 for (int y = 0; y < h; y++)
501 {
502 for (int x = 0; x < w; x++, in += 3, bit_index++)
503 if (in[0] == 255 && in[1] == 255 && in[2] == 255)
504 out[bit_index >> 3] ^= 1 << (bit_index & 7);
505 // move index to next byte boundary
506 bit_index = (bit_index + 7) & ~7u;
507 }
508 SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h));
509 delete[] out;
510 }
511 else
512 {
513 SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, w, h, depth));
514 GdkGC* gc = gdk_gc_new(M_BMPDATA->m_pixmap);
515 gdk_draw_rgb_image(
516 M_BMPDATA->m_pixmap, gc,
517 0, 0, w, h,
518 GDK_RGB_DITHER_NONE, image.GetData(), w * 3);
519 g_object_unref(gc);
520 }
521
522 const wxByte* alpha = image.GetAlpha();
523 if (alpha != NULL || image.HasMask())
524 {
525 // create mask as XBM format bitmap
526
527 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
528 wxByte* out = new wxByte[out_size];
529 memset(out, 0xff, out_size);
530 unsigned bit_index = 0;
531 if (alpha != NULL)
532 {
533 for (int y = 0; y < h; y++)
534 {
535 for (int x = 0; x < w; x++, bit_index++)
536 if (*alpha++ < wxIMAGE_ALPHA_THRESHOLD)
537 out[bit_index >> 3] ^= 1 << (bit_index & 7);
538 bit_index = (bit_index + 7) & ~7u;
539 }
540 }
541 else
542 {
543 const wxByte r_mask = image.GetMaskRed();
544 const wxByte g_mask = image.GetMaskGreen();
545 const wxByte b_mask = image.GetMaskBlue();
546 const wxByte* in = image.GetData();
547 for (int y = 0; y < h; y++)
548 {
549 for (int x = 0; x < w; x++, in += 3, bit_index++)
550 if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
551 out[bit_index >> 3] ^= 1 << (bit_index & 7);
552 bit_index = (bit_index + 7) & ~7u;
553 }
554 }
555 wxMask* mask = new wxMask;
556 mask->m_bitmap = gdk_bitmap_create_from_data(M_BMPDATA->m_pixmap, (char*)out, w, h);
557 SetMask(mask);
558 delete[] out;
559 }
560 return true;
561 }
562
563 bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
564 {
565 int width = image.GetWidth();
566 int height = image.GetHeight();
567
568 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
569 true, //image.HasAlpha(),
570 8 /* bits per sample */,
571 width, height);
572 if (!pixbuf)
573 return false;
574
575 wxASSERT( image.HasAlpha() ); // for now
576 wxASSERT( gdk_pixbuf_get_n_channels(pixbuf) == 4 );
577 wxASSERT( gdk_pixbuf_get_width(pixbuf) == width );
578 wxASSERT( gdk_pixbuf_get_height(pixbuf) == height );
579
580 SetDepth(wxTheApp->GetGdkVisual()->depth);
581 SetPixbuf(pixbuf);
582
583 // Copy the data:
584 unsigned char *in = image.GetData();
585 unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
586 unsigned char *alpha = image.GetAlpha();
587
588 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
589
590 for (int y = 0; y < height; y++, out += rowinc)
591 {
592 for (int x = 0; x < width; x++, alpha++, out += 4, in += 3)
593 {
594 out[0] = in[0];
595 out[1] = in[1];
596 out[2] = in[2];
597 out[3] = *alpha;
598 }
599 }
600
601 return true;
602 }
603
604 wxImage wxBitmap::ConvertToImage() const
605 {
606 wxImage image;
607
608 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
609
610 const int w = GetWidth();
611 const int h = GetHeight();
612 image.Create(w, h);
613 unsigned char *data = image.GetData();
614
615 wxCHECK_MSG(data != NULL, wxNullImage, wxT("couldn't create image") );
616
617 if (HasPixbuf())
618 {
619 GdkPixbuf *pixbuf = GetPixbuf();
620 wxASSERT( gdk_pixbuf_get_has_alpha(pixbuf) );
621
622 image.SetAlpha();
623
624 unsigned char *alpha = image.GetAlpha();
625 unsigned char *in = gdk_pixbuf_get_pixels(pixbuf);
626 unsigned char *out = data;
627 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * w;
628
629 for (int y = 0; y < h; y++, in += rowinc)
630 {
631 for (int x = 0; x < w; x++, in += 4, out += 3, alpha++)
632 {
633 out[0] = in[0];
634 out[1] = in[1];
635 out[2] = in[2];
636 *alpha = in[3];
637 }
638 }
639 }
640 else
641 {
642 GdkPixmap* pixmap = GetPixmap();
643 GdkPixmap* pixmap_invert = NULL;
644 if (GetDepth() == 1)
645 {
646 // mono bitmaps are inverted
647 pixmap_invert = gdk_pixmap_new(pixmap, w, h, 1);
648 GdkGC* gc = gdk_gc_new(pixmap_invert);
649 gdk_gc_set_function(gc, GDK_COPY_INVERT);
650 gdk_draw_drawable(pixmap_invert, gc, pixmap, 0, 0, 0, 0, w, h);
651 g_object_unref(gc);
652 pixmap = pixmap_invert;
653 }
654 // create a pixbuf which shares data with the wxImage
655 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
656 data, GDK_COLORSPACE_RGB, false, 8, w, h, 3 * w, NULL, NULL);
657
658 gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
659
660 g_object_unref(pixbuf);
661 if (pixmap_invert != NULL)
662 g_object_unref(pixmap_invert);
663
664 if (GetMask())
665 {
666 // the colour used as transparent one in wxImage and the one it is
667 // replaced with when it really occurs in the bitmap
668 const int MASK_RED = 1;
669 const int MASK_GREEN = 2;
670 const int MASK_BLUE = 3;
671 const int MASK_BLUE_REPLACEMENT = 2;
672
673 image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
674 GdkImage* image_mask = gdk_drawable_get_image(GetMask()->GetBitmap(), 0, 0, w, h);
675
676 for (int y = 0; y < h; y++)
677 {
678 for (int x = 0; x < w; x++, data += 3)
679 {
680 if (gdk_image_get_pixel(image_mask, x, y) == 0)
681 {
682 data[0] = MASK_RED;
683 data[1] = MASK_GREEN;
684 data[2] = MASK_BLUE;
685 }
686 else if (data[0] == MASK_RED && data[1] == MASK_GREEN && data[2] == MASK_BLUE)
687 {
688 data[2] = MASK_BLUE_REPLACEMENT;
689 }
690 }
691 }
692 g_object_unref(image_mask);
693 }
694 }
695
696 return image;
697 }
698
699 wxBitmap::wxBitmap( const wxString &filename, wxBitmapType type )
700 {
701 LoadFile( filename, type );
702 }
703
704 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
705 {
706 if ( width > 0 && height > 0 )
707 {
708 SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, bits, width, height));
709
710 wxASSERT_MSG( M_BMPDATA->m_pixmap, wxT("couldn't create bitmap") );
711 }
712 }
713
714 wxBitmap::~wxBitmap()
715 {
716 }
717
718 bool wxBitmap::operator == ( const wxBitmap& bmp ) const
719 {
720 return m_refData == bmp.m_refData;
721 }
722
723 bool wxBitmap::operator != ( const wxBitmap& bmp ) const
724 {
725 return m_refData != bmp.m_refData;
726 }
727
728 bool wxBitmap::Ok() const
729 {
730 return (m_refData != NULL) &&
731 (
732 M_BMPDATA->m_pixbuf ||
733 M_BMPDATA->m_pixmap
734 );
735 }
736
737 int wxBitmap::GetHeight() const
738 {
739 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
740
741 return M_BMPDATA->m_height;
742 }
743
744 int wxBitmap::GetWidth() const
745 {
746 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
747
748 return M_BMPDATA->m_width;
749 }
750
751 int wxBitmap::GetDepth() const
752 {
753 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
754
755 return M_BMPDATA->m_bpp;
756 }
757
758 wxMask *wxBitmap::GetMask() const
759 {
760 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
761
762 return M_BMPDATA->m_mask;
763 }
764
765 void wxBitmap::SetMask( wxMask *mask )
766 {
767 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
768
769 if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
770
771 M_BMPDATA->m_mask = mask;
772 }
773
774 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
775 {
776 *this = icon;
777 return Ok();
778 }
779
780 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
781 {
782 wxBitmap ret;
783
784 wxCHECK_MSG( Ok() &&
785 (rect.x >= 0) && (rect.y >= 0) &&
786 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
787 ret, wxT("invalid bitmap or bitmap region") );
788
789 if (HasPixbuf())
790 {
791 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
792 true, //gdk_pixbuf_get_has_alpha(GetPixbuf()),
793 8, rect.width, rect.height);
794 ret.SetPixbuf(pixbuf);
795 ret.SetDepth(M_BMPDATA->m_bpp);
796 gdk_pixbuf_copy_area(GetPixbuf(),
797 rect.x, rect.y, rect.width, rect.height,
798 pixbuf, 0, 0);
799 }
800 else
801 {
802 ret = wxBitmap(rect.width, rect.height, M_BMPDATA->m_bpp);
803 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
804 gdk_draw_drawable( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
805 g_object_unref (gc);
806 }
807
808 if (GetMask())
809 {
810 wxMask *mask = new wxMask;
811 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
812
813 GdkGC *gc = gdk_gc_new( mask->m_bitmap );
814 gdk_draw_drawable(mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, rect.x, rect.y, 0, 0, rect.width, rect.height);
815 g_object_unref (gc);
816
817 ret.SetMask( mask );
818 }
819
820 return ret;
821 }
822
823 bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
824 {
825 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
826
827 // Try to save the bitmap via wxImage handlers:
828 wxImage image = ConvertToImage();
829 return image.Ok() && image.SaveFile(name, type);
830 }
831
832 bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
833 {
834 UnRef();
835
836 if (type == wxBITMAP_TYPE_XPM)
837 {
838 GdkBitmap *mask = (GdkBitmap*) NULL;
839 SetPixmap(gdk_pixmap_create_from_xpm(wxGetRootWindow()->window, &mask, NULL, name.fn_str()));
840
841 if (mask)
842 {
843 M_BMPDATA->m_mask = new wxMask;
844 M_BMPDATA->m_mask->m_bitmap = mask;
845 }
846 }
847 else // try if wxImage can load it
848 {
849 wxImage image;
850 if (image.LoadFile(name, type) && image.Ok())
851 *this = wxBitmap(image);
852 }
853
854 return Ok();
855 }
856
857 #if wxUSE_PALETTE
858 wxPalette *wxBitmap::GetPalette() const
859 {
860 if (!Ok())
861 return (wxPalette *) NULL;
862
863 return M_BMPDATA->m_palette;
864 }
865
866 void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
867 {
868 // TODO
869 }
870 #endif // wxUSE_PALETTE
871
872 void wxBitmap::SetHeight( int height )
873 {
874 if (!m_refData)
875 m_refData = new wxBitmapRefData;
876
877 M_BMPDATA->m_height = height;
878 }
879
880 void wxBitmap::SetWidth( int width )
881 {
882 if (!m_refData)
883 m_refData = new wxBitmapRefData;
884
885 M_BMPDATA->m_width = width;
886 }
887
888 void wxBitmap::SetDepth( int depth )
889 {
890 if (!m_refData)
891 m_refData = new wxBitmapRefData;
892
893 M_BMPDATA->m_bpp = depth;
894 }
895
896 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
897 {
898 if (!m_refData)
899 m_refData = new wxBitmapRefData;
900
901 wxASSERT(M_BMPDATA->m_pixmap == NULL);
902 M_BMPDATA->m_pixmap = pixmap;
903 gdk_drawable_get_size(pixmap, &M_BMPDATA->m_width, &M_BMPDATA->m_height);
904 M_BMPDATA->m_bpp = gdk_drawable_get_depth(pixmap);
905 PurgeOtherRepresentations(Pixmap);
906 }
907
908 GdkPixmap *wxBitmap::GetPixmap() const
909 {
910 wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
911
912 // create the pixmap on the fly if we use Pixbuf representation:
913 if (M_BMPDATA->m_pixmap == NULL)
914 {
915 delete M_BMPDATA->m_mask;
916 M_BMPDATA->m_mask = new wxMask;
917 gdk_pixbuf_render_pixmap_and_mask(M_BMPDATA->m_pixbuf,
918 &M_BMPDATA->m_pixmap,
919 &M_BMPDATA->m_mask->m_bitmap,
920 128 /*threshold*/);
921 }
922
923 return M_BMPDATA->m_pixmap;
924 }
925
926 bool wxBitmap::HasPixmap() const
927 {
928 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
929
930 return M_BMPDATA->m_pixmap != NULL;
931 }
932
933 GdkPixbuf *wxBitmap::GetPixbuf() const
934 {
935 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
936
937 if (M_BMPDATA->m_pixbuf == NULL)
938 {
939 int width = GetWidth();
940 int height = GetHeight();
941
942 // always create the alpha channel so raw bitmap access will work
943 // correctly
944 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
945 true, // GetMask() != NULL,
946 8, width, height);
947 M_BMPDATA->m_pixbuf =
948 gdk_pixbuf_get_from_drawable(pixbuf, M_BMPDATA->m_pixmap, NULL,
949 0, 0, 0, 0, width, height);
950
951 // apply the mask to created pixbuf:
952 if (M_BMPDATA->m_pixbuf && M_BMPDATA->m_mask)
953 {
954 GdkPixbuf *pmask =
955 gdk_pixbuf_get_from_drawable(NULL,
956 M_BMPDATA->m_mask->GetBitmap(),
957 NULL,
958 0, 0, 0, 0, width, height);
959 if (pmask)
960 {
961 guchar *bmp = gdk_pixbuf_get_pixels(pixbuf);
962 guchar *mask = gdk_pixbuf_get_pixels(pmask);
963 int bmprowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
964 int maskrowinc = gdk_pixbuf_get_rowstride(pmask) - 3 * width;
965
966 for (int y = 0; y < height;
967 y++, bmp += bmprowinc, mask += maskrowinc)
968 {
969 for (int x = 0; x < width; x++, bmp += 4, mask += 3)
970 {
971 if (mask[0] == 0 /*black pixel*/)
972 bmp[3] = 0;
973 }
974 }
975
976 g_object_unref (pmask);
977 }
978 }
979 }
980
981 return M_BMPDATA->m_pixbuf;
982 }
983
984 bool wxBitmap::HasPixbuf() const
985 {
986 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
987
988 return M_BMPDATA->m_pixbuf != NULL;
989 }
990
991 void wxBitmap::SetPixbuf( GdkPixbuf *pixbuf )
992 {
993 if (!m_refData)
994 m_refData = new wxBitmapRefData;
995
996 wxASSERT(M_BMPDATA->m_pixbuf == NULL);
997 M_BMPDATA->m_pixbuf = pixbuf;
998 M_BMPDATA->m_width = gdk_pixbuf_get_width(pixbuf);
999 M_BMPDATA->m_height = gdk_pixbuf_get_height(pixbuf);
1000 PurgeOtherRepresentations(Pixbuf);
1001 }
1002
1003 void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
1004 {
1005 if (keep == Pixmap && HasPixbuf())
1006 {
1007 g_object_unref (M_BMPDATA->m_pixbuf);
1008 M_BMPDATA->m_pixbuf = NULL;
1009 }
1010 if (keep == Pixbuf && HasPixmap())
1011 {
1012 g_object_unref (M_BMPDATA->m_pixmap);
1013 M_BMPDATA->m_pixmap = NULL;
1014 }
1015 }
1016
1017 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
1018 {
1019 if (bpp != 32)
1020 return NULL;
1021
1022 GdkPixbuf *pixbuf = GetPixbuf();
1023 if (!pixbuf)
1024 return NULL;
1025
1026 if (!gdk_pixbuf_get_has_alpha( pixbuf ))
1027 return NULL;
1028
1029 #if 0
1030 if (gdk_pixbuf_get_has_alpha( pixbuf ))
1031 wxPrintf( wxT("Has alpha, %d channels\n"), gdk_pixbuf_get_n_channels(pixbuf) );
1032 else
1033 wxPrintf( wxT("No alpha, %d channels.\n"), gdk_pixbuf_get_n_channels(pixbuf) );
1034 #endif
1035
1036 data.m_height = gdk_pixbuf_get_height( pixbuf );
1037 data.m_width = gdk_pixbuf_get_width( pixbuf );
1038 data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
1039
1040 return gdk_pixbuf_get_pixels( pixbuf );
1041 }
1042
1043 void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
1044 {
1045 }
1046
1047
1048 bool wxBitmap::HasAlpha() const
1049 {
1050 return HasPixbuf();
1051 }
1052
1053 void wxBitmap::UseAlpha()
1054 {
1055 GetPixbuf();
1056 }
1057
1058 //-----------------------------------------------------------------------------
1059 // wxBitmapHandler
1060 //-----------------------------------------------------------------------------
1061
1062 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler,wxBitmapHandlerBase)
1063
1064 wxBitmapHandler::~wxBitmapHandler()
1065 {
1066 }
1067
1068 bool wxBitmapHandler::Create(wxBitmap * WXUNUSED(bitmap),
1069 void * WXUNUSED(data),
1070 long WXUNUSED(type),
1071 int WXUNUSED(width),
1072 int WXUNUSED(height),
1073 int WXUNUSED(depth))
1074 {
1075 wxFAIL_MSG( _T("not implemented") );
1076
1077 return false;
1078 }
1079
1080 bool wxBitmapHandler::LoadFile(wxBitmap * WXUNUSED(bitmap),
1081 const wxString& WXUNUSED(name),
1082 long WXUNUSED(flags),
1083 int WXUNUSED(desiredWidth),
1084 int WXUNUSED(desiredHeight))
1085 {
1086 wxFAIL_MSG( _T("not implemented") );
1087
1088 return false;
1089 }
1090
1091 bool wxBitmapHandler::SaveFile(const wxBitmap * WXUNUSED(bitmap),
1092 const wxString& WXUNUSED(name),
1093 int WXUNUSED(type),
1094 const wxPalette * WXUNUSED(palette))
1095 {
1096 wxFAIL_MSG( _T("not implemented") );
1097
1098 return false;
1099 }
1100
1101 /* static */ void wxBitmap::InitStandardHandlers()
1102 {
1103 // TODO: Insert handler based on GdkPixbufs handler later
1104 }