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