]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/bitmap.cpp
really fix binary backwards compatibility for wxMotif
[wxWidgets.git] / src / gtk / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "bitmap.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #include "wx/defs.h"
18
19 #include "wx/bitmap.h"
20 #include "wx/palette.h"
21 #include "wx/icon.h"
22 #include "wx/filefn.h"
23 #include "wx/image.h"
24 #include "wx/dcmemory.h"
25 #include "wx/app.h"
26
27 #ifdef __WXGTK20__
28 #include "wx/rawbmp.h"
29 // need this to get gdk_image_new_bitmap()
30 #define GDK_ENABLE_BROKEN
31 #endif
32
33 #include <gdk/gdk.h>
34 #include <gtk/gtk.h>
35 #include <gdk/gdkx.h>
36
37 #ifdef __WXGTK20__
38 #include <gdk/gdkimage.h>
39 #else // GTK+ 1.2
40 #include <gdk/gdkrgb.h>
41 #endif // GTK+ 2.0/1.2
42
43 #include "wx/math.h"
44
45 extern void gdk_wx_draw_bitmap (GdkDrawable *drawable,
46 GdkGC *gc,
47 GdkDrawable *src,
48 gint xsrc,
49 gint ysrc,
50 gint xdest,
51 gint ydest,
52 gint width,
53 gint height);
54
55 //-----------------------------------------------------------------------------
56 // data
57 //-----------------------------------------------------------------------------
58
59 extern GtkWidget *wxGetRootWindow();
60
61 //-----------------------------------------------------------------------------
62 // wxMask
63 //-----------------------------------------------------------------------------
64
65 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
66
67 wxMask::wxMask()
68 {
69 m_bitmap = (GdkBitmap *) NULL;
70 }
71
72 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
73 {
74 m_bitmap = (GdkBitmap *) NULL;
75 Create( bitmap, colour );
76 }
77
78 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
79 {
80 m_bitmap = (GdkBitmap *) NULL;
81 Create( bitmap, paletteIndex );
82 }
83
84 wxMask::wxMask( const wxBitmap& bitmap )
85 {
86 m_bitmap = (GdkBitmap *) NULL;
87 Create( bitmap );
88 }
89
90 wxMask::~wxMask()
91 {
92 if (m_bitmap)
93 gdk_bitmap_unref( m_bitmap );
94 }
95
96 bool wxMask::Create( const wxBitmap& bitmap,
97 const wxColour& colour )
98 {
99 if (m_bitmap)
100 {
101 gdk_bitmap_unref( m_bitmap );
102 m_bitmap = (GdkBitmap*) NULL;
103 }
104
105 wxImage image = bitmap.ConvertToImage();
106 if (!image.Ok()) return false;
107
108 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, image.GetWidth(), image.GetHeight(), 1 );
109 GdkGC *gc = gdk_gc_new( m_bitmap );
110
111 GdkColor color;
112 color.red = 65000;
113 color.green = 65000;
114 color.blue = 65000;
115 color.pixel = 1;
116 gdk_gc_set_foreground( gc, &color );
117 gdk_gc_set_fill( gc, GDK_SOLID );
118 gdk_draw_rectangle( m_bitmap, gc, TRUE, 0, 0, image.GetWidth(), image.GetHeight() );
119
120 unsigned char *data = image.GetData();
121 int index = 0;
122
123 unsigned char red = colour.Red();
124 unsigned char green = colour.Green();
125 unsigned char blue = colour.Blue();
126
127 GdkVisual *visual = wxTheApp->GetGdkVisual();
128
129 int bpp = visual->depth;
130 if ((bpp == 16) && (visual->red_mask != 0xf800))
131 bpp = 15;
132 if (bpp == 15)
133 {
134 red = red & 0xf8;
135 green = green & 0xf8;
136 blue = blue & 0xf8;
137 }
138 else if (bpp == 16)
139 {
140 red = red & 0xf8;
141 green = green & 0xfc;
142 blue = blue & 0xf8;
143 }
144 else if (bpp == 12)
145 {
146 red = red & 0xf0;
147 green = green & 0xf0;
148 blue = blue & 0xf0;
149 }
150
151 color.red = 0;
152 color.green = 0;
153 color.blue = 0;
154 color.pixel = 0;
155 gdk_gc_set_foreground( gc, &color );
156
157 for (int j = 0; j < image.GetHeight(); j++)
158 {
159 int start_x = -1;
160 int i;
161 for (i = 0; i < image.GetWidth(); i++)
162 {
163 if ((data[index] == red) &&
164 (data[index+1] == green) &&
165 (data[index+2] == blue))
166 {
167 if (start_x == -1)
168 start_x = i;
169 }
170 else
171 {
172 if (start_x != -1)
173 {
174 gdk_draw_line( m_bitmap, gc, start_x, j, i-1, j );
175 start_x = -1;
176 }
177 }
178 index += 3;
179 }
180 if (start_x != -1)
181 gdk_draw_line( m_bitmap, gc, start_x, j, i, j );
182 }
183
184 gdk_gc_unref( gc );
185
186 return true;
187 }
188
189 bool wxMask::Create( const wxBitmap& bitmap, int paletteIndex )
190 {
191 unsigned char r,g,b;
192 wxPalette *pal = bitmap.GetPalette();
193
194 wxCHECK_MSG( pal, false, wxT("Cannot create mask from bitmap without palette") );
195
196 pal->GetRGB(paletteIndex, &r, &g, &b);
197
198 return Create(bitmap, wxColour(r, g, b));
199 }
200
201 bool wxMask::Create( const wxBitmap& bitmap )
202 {
203 if (m_bitmap)
204 {
205 gdk_bitmap_unref( m_bitmap );
206 m_bitmap = (GdkBitmap*) NULL;
207 }
208
209 if (!bitmap.Ok()) return false;
210
211 wxCHECK_MSG( bitmap.GetBitmap(), false, wxT("Cannot create mask from colour bitmap") );
212
213 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
214
215 if (!m_bitmap) return false;
216
217 GdkGC *gc = gdk_gc_new( m_bitmap );
218
219 gdk_wx_draw_bitmap( m_bitmap, gc, bitmap.GetBitmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight() );
220
221 gdk_gc_unref( gc );
222
223 return true;
224 }
225
226 GdkBitmap *wxMask::GetBitmap() const
227 {
228 return m_bitmap;
229 }
230
231 //-----------------------------------------------------------------------------
232 // wxBitmap
233 //-----------------------------------------------------------------------------
234
235 class wxBitmapRefData: public wxObjectRefData
236 {
237 public:
238 wxBitmapRefData();
239 ~wxBitmapRefData();
240
241 GdkPixmap *m_pixmap;
242 GdkBitmap *m_bitmap;
243 #ifdef __WXGTK20__
244 GdkPixbuf *m_pixbuf;
245 #endif
246 wxMask *m_mask;
247 int m_width;
248 int m_height;
249 int m_bpp;
250 wxPalette *m_palette;
251 };
252
253 wxBitmapRefData::wxBitmapRefData()
254 {
255 m_pixmap = (GdkPixmap *) NULL;
256 m_bitmap = (GdkBitmap *) NULL;
257 #ifdef __WXGTK20__
258 m_pixbuf = (GdkPixbuf *) NULL;
259 #endif
260 m_mask = (wxMask *) NULL;
261 m_width = 0;
262 m_height = 0;
263 m_bpp = 0;
264 m_palette = (wxPalette *) NULL;
265 }
266
267 wxBitmapRefData::~wxBitmapRefData()
268 {
269 if (m_pixmap)
270 gdk_pixmap_unref( m_pixmap );
271 if (m_bitmap)
272 gdk_bitmap_unref( m_bitmap );
273 #ifdef __WXGTK20__
274 if (m_pixbuf)
275 gdk_pixbuf_unref( m_pixbuf );
276 #endif
277 delete m_mask;
278 delete m_palette;
279 }
280
281 //-----------------------------------------------------------------------------
282
283 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
284
285 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
286
287 wxBitmap::wxBitmap()
288 {
289 }
290
291 wxBitmap::wxBitmap( int width, int height, int depth )
292 {
293 Create( width, height, depth );
294 }
295
296 bool wxBitmap::Create( int width, int height, int depth )
297 {
298 UnRef();
299
300 if ( width <= 0 || height <= 0 )
301 {
302 return false;
303 }
304
305 GdkVisual *visual = wxTheApp->GetGdkVisual();
306
307 if (depth == -1)
308 depth = visual->depth;
309
310 wxCHECK_MSG( (depth == visual->depth) || (depth == 1) || (depth == 32), false,
311 wxT("invalid bitmap depth") )
312
313 m_refData = new wxBitmapRefData();
314 M_BMPDATA->m_mask = (wxMask *) NULL;
315 M_BMPDATA->m_width = width;
316 M_BMPDATA->m_height = height;
317 if (depth == 1)
318 {
319 M_BMPDATA->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
320 M_BMPDATA->m_bpp = 1;
321 }
322 #ifdef __WXGTK20__
323 else if (depth == 32)
324 {
325 M_BMPDATA->m_pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, true,
326 8, width, height);
327 M_BMPDATA->m_bpp = 32;
328 }
329 #endif
330 else
331 {
332 M_BMPDATA->m_pixmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, depth );
333 M_BMPDATA->m_bpp = visual->depth;
334 }
335
336 return Ok();
337 }
338
339 bool wxBitmap::CreateFromXpm( const char **bits )
340 {
341 UnRef();
342
343 wxCHECK_MSG( bits != NULL, false, wxT("invalid bitmap data") )
344
345 GdkVisual *visual = wxTheApp->GetGdkVisual();
346
347 m_refData = new wxBitmapRefData();
348
349 GdkBitmap *mask = (GdkBitmap*) NULL;
350
351 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm_d( wxGetRootWindow()->window, &mask, NULL, (gchar **) bits );
352
353 wxCHECK_MSG( M_BMPDATA->m_pixmap, false, wxT("couldn't create pixmap") );
354
355 if (mask)
356 {
357 M_BMPDATA->m_mask = new wxMask();
358 M_BMPDATA->m_mask->m_bitmap = mask;
359 }
360
361 gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
362
363 M_BMPDATA->m_bpp = visual->depth; // Can we get a different depth from create_from_xpm_d() ?
364
365 return true;
366 }
367
368 wxBitmap wxBitmap::Rescale( int clipx, int clipy, int clipwidth, int clipheight, int newx, int newy )
369 {
370 wxCHECK_MSG( Ok(), wxNullBitmap, wxT("invalid bitmap") );
371
372 if (newy==M_BMPDATA->m_width && newy==M_BMPDATA->m_height)
373 return *this;
374
375 int width = wxMax(newx, 1);
376 int height = wxMax(newy, 1);
377 width = wxMin(width, clipwidth);
378 height = wxMin(height, clipheight);
379
380 wxBitmap bmp;
381
382 #ifdef __WXGTK20__
383 if (HasPixbuf())
384 {
385 bmp.SetWidth(width);
386 bmp.SetHeight(height);
387 bmp.SetDepth(GetDepth());
388 bmp.SetPixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB,
389 gdk_pixbuf_get_has_alpha(GetPixbuf()),
390 8, width, height));
391 gdk_pixbuf_scale(GetPixbuf(), bmp.GetPixbuf(),
392 0, 0, width, height,
393 clipx, clipy,
394 (double)newx/GetWidth(), (double)newy/GetHeight(),
395 GDK_INTERP_BILINEAR);
396 }
397 else
398 #endif // __WXGTK20__
399 {
400 GdkImage *img = (GdkImage*) NULL;
401 if (GetPixmap())
402 img = gdk_image_get( GetPixmap(), 0, 0, GetWidth(), GetHeight() );
403 else if (GetBitmap())
404 img = gdk_image_get( GetBitmap(), 0, 0, GetWidth(), GetHeight() );
405 else
406 wxFAIL_MSG( wxT("Ill-formed bitmap") );
407
408 wxCHECK_MSG( img, wxNullBitmap, wxT("couldn't create image") );
409
410 int bpp = -1;
411
412
413 GdkGC *gc = NULL;
414 GdkPixmap *dstpix = NULL;
415 if (GetPixmap())
416 {
417 GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
418 if (visual == NULL)
419 visual = wxTheApp->GetGdkVisual();
420
421 bpp = visual->depth;
422 bmp = wxBitmap(width,height,bpp);
423 dstpix = bmp.GetPixmap();
424 gc = gdk_gc_new( dstpix );
425 }
426
427 char *dst = NULL;
428 long dstbyteperline = 0;
429
430 if (GetBitmap())
431 {
432 bpp = 1;
433 dstbyteperline = width/8*M_BMPDATA->m_bpp;
434 if (width*M_BMPDATA->m_bpp % 8 != 0)
435 dstbyteperline++;
436 dst = (char*) malloc(dstbyteperline*height);
437 }
438
439 // be careful to use the right scaling factor
440 float scx = (float)M_BMPDATA->m_width/(float)newx;
441 float scy = (float)M_BMPDATA->m_height/(float)newy;
442 // prepare accel-tables
443 int *tablex = (int *)calloc(width,sizeof(int));
444 int *tabley = (int *)calloc(height,sizeof(int));
445
446 // accel table filled with clipped values
447 for (int x = 0; x < width; x++)
448 tablex[x] = (int) (scx * (x+clipx));
449 for (int y = 0; y < height; y++)
450 tabley[y] = (int) (scy * (y+clipy));
451
452 // Main rescaling routine starts here
453 for (int h = 0; h < height; h++)
454 {
455 char outbyte = 0;
456 int old_x = -1;
457 guint32 old_pixval = 0;
458
459 for (int w = 0; w < width; w++)
460 {
461 guint32 pixval;
462 int x = tablex[w];
463 if (x == old_x)
464 pixval = old_pixval;
465 else
466 {
467 pixval = gdk_image_get_pixel( img, x, tabley[h] );
468 old_pixval = pixval;
469 old_x = x;
470 }
471
472 if (bpp == 1)
473 {
474 if (!pixval)
475 {
476 char bit=1;
477 char shift = bit << (w % 8);
478 outbyte |= shift;
479 }
480
481 if ((w+1)%8==0)
482 {
483 dst[h*dstbyteperline+w/8] = outbyte;
484 outbyte = 0;
485 }
486 }
487 else
488 {
489 GdkColor col;
490 col.pixel = pixval;
491 gdk_gc_set_foreground( gc, &col );
492 gdk_draw_point( dstpix, gc, w, h);
493 }
494 }
495
496 // do not forget the last byte
497 if ((bpp == 1) && (width % 8 != 0))
498 dst[h*dstbyteperline+width/8] = outbyte;
499 }
500
501 gdk_image_destroy( img );
502 if (gc) gdk_gc_unref( gc );
503
504 if (bpp == 1)
505 {
506 bmp = wxBitmap( (const char *)dst, width, height, 1 );
507 free( dst );
508 }
509
510 if (GetMask())
511 {
512 dstbyteperline = width/8;
513 if (width % 8 != 0)
514 dstbyteperline++;
515 dst = (char*) malloc(dstbyteperline*height);
516 img = gdk_image_get( GetMask()->GetBitmap(), 0, 0, GetWidth(), GetHeight() );
517
518 for (int h = 0; h < height; h++)
519 {
520 char outbyte = 0;
521 int old_x = -1;
522 guint32 old_pixval = 0;
523
524 for (int w = 0; w < width; w++)
525 {
526 guint32 pixval;
527 int x = tablex[w];
528 if (x == old_x)
529 pixval = old_pixval;
530 else
531 {
532 pixval = gdk_image_get_pixel( img, x, tabley[h] );
533 old_pixval = pixval;
534 old_x = x;
535 }
536
537 if (pixval)
538 {
539 char bit=1;
540 char shift = bit << (w % 8);
541 outbyte |= shift;
542 }
543
544 if ((w+1)%8 == 0)
545 {
546 dst[h*dstbyteperline+w/8] = outbyte;
547 outbyte = 0;
548 }
549 }
550
551 // do not forget the last byte
552 if (width % 8 != 0)
553 dst[h*dstbyteperline+width/8] = outbyte;
554 }
555 wxMask* mask = new wxMask;
556 mask->m_bitmap = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) dst, width, height );
557 bmp.SetMask(mask);
558
559 free( dst );
560 gdk_image_destroy( img );
561 }
562
563 free( tablex );
564 free( tabley );
565 }
566
567 return bmp;
568 }
569
570 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
571 {
572 UnRef();
573
574 wxCHECK_MSG( image.Ok(), false, wxT("invalid image") )
575 wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") )
576
577 if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
578 return false;
579
580 m_refData = new wxBitmapRefData();
581
582 if (depth == 1)
583 {
584 return CreateFromImageAsBitmap(image);
585 }
586 else
587 {
588 #ifdef __WXGTK20__
589 if (image.HasAlpha())
590 return CreateFromImageAsPixbuf(image);
591 #endif
592 return CreateFromImageAsPixmap(image);
593 }
594 }
595
596 // conversion to mono bitmap:
597 bool wxBitmap::CreateFromImageAsBitmap(const wxImage& img)
598 {
599 // convert alpha channel to mask, if it is present:
600 wxImage image(img);
601 image.ConvertAlphaToMask();
602
603 int width = image.GetWidth();
604 int height = image.GetHeight();
605
606 SetHeight( height );
607 SetWidth( width );
608
609 SetBitmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 ) );
610
611 SetDepth( 1 );
612
613 GdkVisual *visual = wxTheApp->GetGdkVisual();
614
615 // Create picture image
616
617 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
618
619 GdkImage *data_image =
620 gdk_image_new_bitmap( visual, data_data, width, height );
621
622 // Create mask image
623
624 GdkImage *mask_image = (GdkImage*) NULL;
625
626 if (image.HasMask())
627 {
628 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
629
630 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
631
632 wxMask *mask = new wxMask();
633 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
634
635 SetMask( mask );
636 }
637
638 int r_mask = image.GetMaskRed();
639 int g_mask = image.GetMaskGreen();
640 int b_mask = image.GetMaskBlue();
641
642 unsigned char* data = image.GetData();
643
644 int index = 0;
645 for (int y = 0; y < height; y++)
646 {
647 for (int x = 0; x < width; x++)
648 {
649 int r = data[index];
650 index++;
651 int g = data[index];
652 index++;
653 int b = data[index];
654 index++;
655
656 if (image.HasMask())
657 {
658 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
659 gdk_image_put_pixel( mask_image, x, y, 1 );
660 else
661 gdk_image_put_pixel( mask_image, x, y, 0 );
662 }
663
664 if ((r == 255) && (b == 255) && (g == 255))
665 gdk_image_put_pixel( data_image, x, y, 1 );
666 else
667 gdk_image_put_pixel( data_image, x, y, 0 );
668
669 } // for
670 } // for
671
672 // Blit picture
673
674 GdkGC *data_gc = gdk_gc_new( GetBitmap() );
675
676 gdk_draw_image( GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
677
678 gdk_image_destroy( data_image );
679 gdk_gc_unref( data_gc );
680
681 // Blit mask
682
683 if (image.HasMask())
684 {
685 GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
686
687 gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
688
689 gdk_image_destroy( mask_image );
690 gdk_gc_unref( mask_gc );
691 }
692
693 return true;
694 }
695
696 // conversion to colour bitmap:
697 bool wxBitmap::CreateFromImageAsPixmap(const wxImage& img)
698 {
699 // convert alpha channel to mask, if it is present:
700 wxImage image(img);
701 image.ConvertAlphaToMask();
702
703 int width = image.GetWidth();
704 int height = image.GetHeight();
705
706 SetHeight( height );
707 SetWidth( width );
708
709 SetPixmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, -1 ) );
710
711 GdkVisual *visual = wxTheApp->GetGdkVisual();
712
713 int bpp = visual->depth;
714
715 SetDepth( bpp );
716
717 if ((bpp == 16) && (visual->red_mask != 0xf800))
718 bpp = 15;
719 else if (bpp < 8)
720 bpp = 8;
721
722 // We handle 8-bit bitmaps ourselves using the colour cube, 12-bit
723 // visuals are not supported by GDK so we do these ourselves, too.
724 // 15-bit and 16-bit should actually work and 24-bit certainly does.
725 #ifdef __sgi
726 if (!image.HasMask() && (bpp > 16))
727 #else
728 if (!image.HasMask() && (bpp > 12))
729 #endif
730 {
731 static bool s_hasInitialized = false;
732
733 if (!s_hasInitialized)
734 {
735 gdk_rgb_init();
736 s_hasInitialized = true;
737 }
738
739 GdkGC *gc = gdk_gc_new( GetPixmap() );
740
741 gdk_draw_rgb_image( GetPixmap(),
742 gc,
743 0, 0,
744 width, height,
745 GDK_RGB_DITHER_NONE,
746 image.GetData(),
747 width*3 );
748
749 gdk_gc_unref( gc );
750 return true;
751 }
752
753 // Create picture image
754
755 GdkImage *data_image =
756 gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
757
758 // Create mask image
759
760 GdkImage *mask_image = (GdkImage*) NULL;
761
762 if (image.HasMask())
763 {
764 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
765
766 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
767
768 wxMask *mask = new wxMask();
769 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
770
771 SetMask( mask );
772 }
773
774 // Render
775
776 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
777 byte_order b_o = RGB;
778
779 if (bpp > 8)
780 {
781 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
782 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RBG;
783 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
784 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
785 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
786 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
787 }
788
789 int r_mask = image.GetMaskRed();
790 int g_mask = image.GetMaskGreen();
791 int b_mask = image.GetMaskBlue();
792
793 unsigned char* data = image.GetData();
794
795 int index = 0;
796 for (int y = 0; y < height; y++)
797 {
798 for (int x = 0; x < width; x++)
799 {
800 int r = data[index];
801 index++;
802 int g = data[index];
803 index++;
804 int b = data[index];
805 index++;
806
807 if (image.HasMask())
808 {
809 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
810 gdk_image_put_pixel( mask_image, x, y, 1 );
811 else
812 gdk_image_put_pixel( mask_image, x, y, 0 );
813 }
814
815 switch (bpp)
816 {
817 case 8:
818 {
819 int pixel = -1;
820 if (wxTheApp->m_colorCube)
821 {
822 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
823 }
824 else
825 {
826 GdkColormap *cmap = gtk_widget_get_default_colormap();
827 GdkColor *colors = cmap->colors;
828 int max = 3 * (65536);
829
830 for (int i = 0; i < cmap->size; i++)
831 {
832 int rdiff = (r << 8) - colors[i].red;
833 int gdiff = (g << 8) - colors[i].green;
834 int bdiff = (b << 8) - colors[i].blue;
835 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
836 if (sum < max) { pixel = i; max = sum; }
837 }
838 }
839
840 gdk_image_put_pixel( data_image, x, y, pixel );
841
842 break;
843 }
844 case 12: // SGI only
845 {
846 guint32 pixel = 0;
847 switch (b_o)
848 {
849 case RGB: pixel = ((r & 0xf0) << 4) | (g & 0xf0) | ((b & 0xf0) >> 4); break;
850 case RBG: pixel = ((r & 0xf0) << 4) | (b & 0xf0) | ((g & 0xf0) >> 4); break;
851 case GRB: pixel = ((g & 0xf0) << 4) | (r & 0xf0) | ((b & 0xf0) >> 4); break;
852 case GBR: pixel = ((g & 0xf0) << 4) | (b & 0xf0) | ((r & 0xf0) >> 4); break;
853 case BRG: pixel = ((b & 0xf0) << 4) | (r & 0xf0) | ((g & 0xf0) >> 4); break;
854 case BGR: pixel = ((b & 0xf0) << 4) | (g & 0xf0) | ((r & 0xf0) >> 4); break;
855 }
856 gdk_image_put_pixel( data_image, x, y, pixel );
857 break;
858 }
859 case 15:
860 {
861 guint32 pixel = 0;
862 switch (b_o)
863 {
864 case RGB: pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
865 case RBG: pixel = ((r & 0xf8) << 7) | ((b & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
866 case GRB: pixel = ((g & 0xf8) << 7) | ((r & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
867 case GBR: pixel = ((g & 0xf8) << 7) | ((b & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
868 case BRG: pixel = ((b & 0xf8) << 7) | ((r & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
869 case BGR: pixel = ((b & 0xf8) << 7) | ((g & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
870 }
871 gdk_image_put_pixel( data_image, x, y, pixel );
872 break;
873 }
874 case 16:
875 {
876 // I actually don't know if for 16-bit displays, it is alway the green
877 // component or the second component which has 6 bits.
878 guint32 pixel = 0;
879 switch (b_o)
880 {
881 case RGB: pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
882 case RBG: pixel = ((r & 0xf8) << 8) | ((b & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
883 case GRB: pixel = ((g & 0xf8) << 8) | ((r & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
884 case GBR: pixel = ((g & 0xf8) << 8) | ((b & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
885 case BRG: pixel = ((b & 0xf8) << 8) | ((r & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
886 case BGR: pixel = ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
887 }
888 gdk_image_put_pixel( data_image, x, y, pixel );
889 break;
890 }
891 case 32:
892 case 24:
893 {
894 guint32 pixel = 0;
895 switch (b_o)
896 {
897 case RGB: pixel = (r << 16) | (g << 8) | b; break;
898 case RBG: pixel = (r << 16) | (b << 8) | g; break;
899 case BRG: pixel = (b << 16) | (r << 8) | g; break;
900 case BGR: pixel = (b << 16) | (g << 8) | r; break;
901 case GRB: pixel = (g << 16) | (r << 8) | b; break;
902 case GBR: pixel = (g << 16) | (b << 8) | r; break;
903 }
904 gdk_image_put_pixel( data_image, x, y, pixel );
905 break;
906 }
907 default: break;
908 }
909 } // for
910 } // for
911
912 // Blit picture
913
914 GdkGC *data_gc = gdk_gc_new( GetPixmap() );
915
916 gdk_draw_image( GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
917
918 gdk_image_destroy( data_image );
919 gdk_gc_unref( data_gc );
920
921 // Blit mask
922
923 if (image.HasMask())
924 {
925 GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
926
927 gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
928
929 gdk_image_destroy( mask_image );
930 gdk_gc_unref( mask_gc );
931 }
932
933 return true;
934 }
935
936 #ifdef __WXGTK20__
937 bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
938 {
939 int width = image.GetWidth();
940 int height = image.GetHeight();
941
942 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
943 image.HasAlpha(),
944 8 /* bits per sample */,
945 width, height);
946 if (!pixbuf)
947 return false;
948
949 wxASSERT( image.HasAlpha() ); // for now
950 wxASSERT( gdk_pixbuf_get_n_channels(pixbuf) == 4 );
951 wxASSERT( gdk_pixbuf_get_width(pixbuf) == width );
952 wxASSERT( gdk_pixbuf_get_height(pixbuf) == height );
953
954 M_BMPDATA->m_pixbuf = pixbuf;
955 SetHeight(height);
956 SetWidth(width);
957 SetDepth(wxTheApp->GetGdkVisual()->depth);
958
959 // Copy the data:
960 unsigned char *in = image.GetData();
961 unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
962 unsigned char *alpha = image.GetAlpha();
963
964 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
965
966 for (int y = 0; y < height; y++, out += rowinc)
967 {
968 for (int x = 0; x < width; x++, alpha++, out += 4, in += 3)
969 {
970 out[0] = in[0];
971 out[1] = in[1];
972 out[2] = in[2];
973 out[3] = *alpha;
974 }
975 }
976
977 return true;
978 }
979 #endif // __WXGTK20__
980
981 wxImage wxBitmap::ConvertToImage() const
982 {
983 wxImage image;
984
985 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
986
987 image.Create(GetWidth(), GetHeight());
988 unsigned char *data = image.GetData();
989
990 if (!data)
991 {
992 wxFAIL_MSG( wxT("couldn't create image") );
993 return wxNullImage;
994 }
995
996 #ifdef __WXGTK20__
997 if (HasPixbuf())
998 {
999 GdkPixbuf *pixbuf = GetPixbuf();
1000 wxASSERT( gdk_pixbuf_get_has_alpha(pixbuf) );
1001
1002 int w = GetWidth();
1003 int h = GetHeight();
1004
1005 image.SetAlpha();
1006
1007 unsigned char *alpha = image.GetAlpha();
1008 unsigned char *in = gdk_pixbuf_get_pixels(pixbuf);
1009 unsigned char *out = data;
1010 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * w;
1011
1012 for (int y = 0; y < h; y++, in += rowinc)
1013 {
1014 for (int x = 0; x < w; x++, in += 4, out += 3, alpha++)
1015 {
1016 out[0] = in[0];
1017 out[1] = in[1];
1018 out[2] = in[2];
1019 *alpha = in[3];
1020 }
1021 }
1022 }
1023 else
1024 #endif // __WXGTK20__
1025 {
1026 // the colour used as transparent one in wxImage and the one it is
1027 // replaced with when it really occurs in the bitmap
1028 static const int MASK_RED = 1;
1029 static const int MASK_GREEN = 2;
1030 static const int MASK_BLUE = 3;
1031 static const int MASK_BLUE_REPLACEMENT = 2;
1032
1033 GdkImage *gdk_image = (GdkImage*) NULL;
1034
1035 if (HasPixmap())
1036 {
1037 gdk_image = gdk_image_get( GetPixmap(),
1038 0, 0,
1039 GetWidth(), GetHeight() );
1040 }
1041 else if (GetBitmap())
1042 {
1043 gdk_image = gdk_image_get( GetBitmap(),
1044 0, 0,
1045 GetWidth(), GetHeight() );
1046 }
1047 else
1048 {
1049 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1050 }
1051
1052 wxCHECK_MSG( gdk_image, wxNullImage, wxT("couldn't create image") );
1053
1054 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1055 if (GetMask())
1056 {
1057 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
1058 0, 0,
1059 GetWidth(), GetHeight() );
1060
1061 image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
1062 }
1063
1064 int bpp = -1;
1065 int red_shift_right = 0;
1066 int green_shift_right = 0;
1067 int blue_shift_right = 0;
1068 int red_shift_left = 0;
1069 int green_shift_left = 0;
1070 int blue_shift_left = 0;
1071 bool use_shift = false;
1072
1073 if (GetPixmap())
1074 {
1075 GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
1076 if (visual == NULL)
1077 visual = wxTheApp->GetGdkVisual();
1078
1079 bpp = visual->depth;
1080 if (bpp == 16)
1081 bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1082 red_shift_right = visual->red_shift;
1083 red_shift_left = 8-visual->red_prec;
1084 green_shift_right = visual->green_shift;
1085 green_shift_left = 8-visual->green_prec;
1086 blue_shift_right = visual->blue_shift;
1087 blue_shift_left = 8-visual->blue_prec;
1088
1089 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
1090 }
1091 if (GetBitmap())
1092 {
1093 bpp = 1;
1094 }
1095
1096
1097 GdkColormap *cmap = gtk_widget_get_default_colormap();
1098
1099 long pos = 0;
1100 for (int j = 0; j < GetHeight(); j++)
1101 {
1102 for (int i = 0; i < GetWidth(); i++)
1103 {
1104 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
1105 if (bpp == 1)
1106 {
1107 if (pixel == 0)
1108 {
1109 data[pos] = 0;
1110 data[pos+1] = 0;
1111 data[pos+2] = 0;
1112 }
1113 else
1114 {
1115 data[pos] = 255;
1116 data[pos+1] = 255;
1117 data[pos+2] = 255;
1118 }
1119 }
1120 else if (use_shift)
1121 {
1122 data[pos] = (pixel >> red_shift_right) << red_shift_left;
1123 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1124 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
1125 }
1126 else if (cmap->colors)
1127 {
1128 data[pos] = cmap->colors[pixel].red >> 8;
1129 data[pos+1] = cmap->colors[pixel].green >> 8;
1130 data[pos+2] = cmap->colors[pixel].blue >> 8;
1131 }
1132 else
1133 {
1134 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1135 }
1136
1137 if (gdk_image_mask)
1138 {
1139 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1140 if (mask_pixel == 0)
1141 {
1142 data[pos] = MASK_RED;
1143 data[pos+1] = MASK_GREEN;
1144 data[pos+2] = MASK_BLUE;
1145 }
1146 else if ( data[pos] == MASK_RED &&
1147 data[pos+1] == MASK_GREEN &&
1148 data[pos+2] == MASK_BLUE )
1149 {
1150 data[pos+2] = MASK_BLUE_REPLACEMENT;
1151 }
1152 }
1153
1154 pos += 3;
1155 }
1156 }
1157
1158 gdk_image_destroy( gdk_image );
1159 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1160 }
1161
1162 return image;
1163 }
1164
1165 wxBitmap::wxBitmap( const wxBitmap& bmp )
1166 : wxBitmapBase()
1167 {
1168 Ref( bmp );
1169 }
1170
1171 wxBitmap::wxBitmap( const wxString &filename, wxBitmapType type )
1172 {
1173 LoadFile( filename, type );
1174 }
1175
1176 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
1177 {
1178 if ( width > 0 && height > 0 )
1179 {
1180 m_refData = new wxBitmapRefData();
1181
1182 M_BMPDATA->m_mask = (wxMask *) NULL;
1183 M_BMPDATA->m_bitmap = gdk_bitmap_create_from_data
1184 (
1185 wxGetRootWindow()->window,
1186 (gchar *) bits,
1187 width,
1188 height
1189 );
1190 M_BMPDATA->m_width = width;
1191 M_BMPDATA->m_height = height;
1192 M_BMPDATA->m_bpp = 1;
1193
1194 wxASSERT_MSG( M_BMPDATA->m_bitmap, wxT("couldn't create bitmap") );
1195 }
1196 }
1197
1198 wxBitmap::~wxBitmap()
1199 {
1200 }
1201
1202 wxBitmap& wxBitmap::operator = ( const wxBitmap& bmp )
1203 {
1204 if ( m_refData != bmp.m_refData )
1205 Ref( bmp );
1206
1207 return *this;
1208 }
1209
1210 bool wxBitmap::operator == ( const wxBitmap& bmp ) const
1211 {
1212 return m_refData == bmp.m_refData;
1213 }
1214
1215 bool wxBitmap::operator != ( const wxBitmap& bmp ) const
1216 {
1217 return m_refData != bmp.m_refData;
1218 }
1219
1220 bool wxBitmap::Ok() const
1221 {
1222 return (m_refData != NULL) &&
1223 (
1224 #ifdef __WXGTK20__
1225 M_BMPDATA->m_pixbuf ||
1226 #endif
1227 M_BMPDATA->m_bitmap || M_BMPDATA->m_pixmap
1228 );
1229 }
1230
1231 int wxBitmap::GetHeight() const
1232 {
1233 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1234
1235 return M_BMPDATA->m_height;
1236 }
1237
1238 int wxBitmap::GetWidth() const
1239 {
1240 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1241
1242 return M_BMPDATA->m_width;
1243 }
1244
1245 int wxBitmap::GetDepth() const
1246 {
1247 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1248
1249 return M_BMPDATA->m_bpp;
1250 }
1251
1252 wxMask *wxBitmap::GetMask() const
1253 {
1254 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
1255
1256 return M_BMPDATA->m_mask;
1257 }
1258
1259 void wxBitmap::SetMask( wxMask *mask )
1260 {
1261 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
1262
1263 if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
1264
1265 M_BMPDATA->m_mask = mask;
1266 }
1267
1268 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
1269 {
1270 *this = icon;
1271 return true;
1272 }
1273
1274 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
1275 {
1276 wxCHECK_MSG( Ok() &&
1277 (rect.x >= 0) && (rect.y >= 0) &&
1278 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
1279 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
1280
1281 wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
1282 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
1283
1284 #ifdef __WXGTK20__
1285 if (HasPixbuf())
1286 {
1287 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1288 gdk_pixbuf_get_has_alpha(GetPixbuf()),
1289 8, GetWidth(), GetHeight());
1290 ret.SetPixbuf(pixbuf);
1291 gdk_pixbuf_copy_area(GetPixbuf(),
1292 rect.x, rect.y, rect.width, rect.height,
1293 pixbuf, 0, 0);
1294 }
1295 else
1296 #endif // __WXGTK20__
1297 {
1298 if (ret.GetPixmap())
1299 {
1300 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
1301 gdk_draw_pixmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1302 gdk_gc_destroy( gc );
1303 }
1304 else
1305 {
1306 GdkGC *gc = gdk_gc_new( ret.GetBitmap() );
1307 GdkColor col;
1308 col.pixel = 0xFFFFFF;
1309 gdk_gc_set_foreground( gc, &col );
1310 col.pixel = 0;
1311 gdk_gc_set_background( gc, &col );
1312 gdk_wx_draw_bitmap( ret.GetBitmap(), gc, GetBitmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1313 gdk_gc_destroy( gc );
1314 }
1315 }
1316
1317 if (GetMask())
1318 {
1319 wxMask *mask = new wxMask;
1320 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
1321
1322 GdkGC *gc = gdk_gc_new( mask->m_bitmap );
1323 GdkColor col;
1324 col.pixel = 0xFFFFFF;
1325 gdk_gc_set_foreground( gc, &col );
1326 col.pixel = 0;
1327 gdk_gc_set_background( gc, &col );
1328 gdk_wx_draw_bitmap( mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, rect.x, rect.y, 0, 0, rect.width, rect.height );
1329 gdk_gc_destroy( gc );
1330
1331 ret.SetMask( mask );
1332 }
1333
1334 return ret;
1335 }
1336
1337 bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
1338 {
1339 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1340
1341 // Try to save the bitmap via wxImage handlers:
1342 {
1343 wxImage image = ConvertToImage();
1344 if (image.Ok()) return image.SaveFile( name, type );
1345 }
1346
1347 return false;
1348 }
1349
1350 bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
1351 {
1352 UnRef();
1353
1354 if (!wxFileExists(name))
1355 return false;
1356
1357 GdkVisual *visual = wxTheApp->GetGdkVisual();
1358
1359 if (type == wxBITMAP_TYPE_XPM)
1360 {
1361 m_refData = new wxBitmapRefData();
1362
1363 GdkBitmap *mask = (GdkBitmap*) NULL;
1364
1365 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm
1366 (
1367 wxGetRootWindow()->window,
1368 &mask,
1369 NULL,
1370 name.fn_str()
1371 );
1372
1373 if (mask)
1374 {
1375 M_BMPDATA->m_mask = new wxMask();
1376 M_BMPDATA->m_mask->m_bitmap = mask;
1377 }
1378
1379 gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
1380
1381 M_BMPDATA->m_bpp = visual->depth;
1382 }
1383 else // try if wxImage can load it
1384 {
1385 wxImage image;
1386 if ( !image.LoadFile( name, type ) || !image.Ok() )
1387 return false;
1388
1389 *this = wxBitmap(image);
1390 }
1391
1392 return true;
1393 }
1394
1395 wxPalette *wxBitmap::GetPalette() const
1396 {
1397 if (!Ok())
1398 return (wxPalette *) NULL;
1399
1400 return M_BMPDATA->m_palette;
1401 }
1402
1403 void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
1404 {
1405 // TODO
1406 }
1407
1408 void wxBitmap::SetHeight( int height )
1409 {
1410 if (!m_refData)
1411 m_refData = new wxBitmapRefData();
1412
1413 M_BMPDATA->m_height = height;
1414 }
1415
1416 void wxBitmap::SetWidth( int width )
1417 {
1418 if (!m_refData)
1419 m_refData = new wxBitmapRefData();
1420
1421 M_BMPDATA->m_width = width;
1422 }
1423
1424 void wxBitmap::SetDepth( int depth )
1425 {
1426 if (!m_refData)
1427 m_refData = new wxBitmapRefData();
1428
1429 M_BMPDATA->m_bpp = depth;
1430 }
1431
1432 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
1433 {
1434 if (!m_refData)
1435 m_refData = new wxBitmapRefData();
1436
1437 M_BMPDATA->m_pixmap = pixmap;
1438 #ifdef __WXGTK20__
1439 PurgeOtherRepresentations(Pixmap);
1440 #endif
1441 }
1442
1443 void wxBitmap::SetBitmap( GdkPixmap *bitmap )
1444 {
1445 if (!m_refData)
1446 m_refData = new wxBitmapRefData();
1447
1448 M_BMPDATA->m_bitmap = bitmap;
1449 #ifdef __WXGTK20__
1450 PurgeOtherRepresentations(Pixmap);
1451 #endif
1452 }
1453
1454 GdkPixmap *wxBitmap::GetPixmap() const
1455 {
1456 wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
1457
1458 #ifdef __WXGTK20__
1459 // create the pixmap on the fly if we use Pixbuf representation:
1460 if (HasPixbuf() && !HasPixmap())
1461 {
1462 delete M_BMPDATA->m_mask;
1463 M_BMPDATA->m_mask = new wxMask();
1464 gdk_pixbuf_render_pixmap_and_mask(M_BMPDATA->m_pixbuf,
1465 &M_BMPDATA->m_pixmap,
1466 &M_BMPDATA->m_mask->m_bitmap,
1467 128 /*threshold*/);
1468 }
1469 #endif // __WXGTK20__
1470
1471 return M_BMPDATA->m_pixmap;
1472 }
1473
1474 bool wxBitmap::HasPixmap() const
1475 {
1476 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1477
1478 return M_BMPDATA->m_pixmap != NULL;
1479 }
1480
1481 GdkBitmap *wxBitmap::GetBitmap() const
1482 {
1483 wxCHECK_MSG( Ok(), (GdkBitmap *) NULL, wxT("invalid bitmap") );
1484
1485 return M_BMPDATA->m_bitmap;
1486 }
1487
1488 #ifdef __WXGTK20__
1489 GdkPixbuf *wxBitmap::GetPixbuf() const
1490 {
1491 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
1492
1493 if (HasPixmap() && !HasPixbuf())
1494 {
1495 int width = GetWidth();
1496 int height = GetHeight();
1497
1498 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1499 GetMask() != NULL,
1500 8, width, height);
1501 M_BMPDATA->m_pixbuf =
1502 gdk_pixbuf_get_from_drawable(pixbuf, M_BMPDATA->m_pixmap, NULL,
1503 0, 0, 0, 0, width, height);
1504
1505 // apply the mask to created pixbuf:
1506 if (M_BMPDATA->m_pixbuf && M_BMPDATA->m_mask)
1507 {
1508 GdkPixbuf *pmask =
1509 gdk_pixbuf_get_from_drawable(NULL,
1510 M_BMPDATA->m_mask->GetBitmap(),
1511 NULL,
1512 0, 0, 0, 0, width, height);
1513 if (pmask)
1514 {
1515 guchar *bmp = gdk_pixbuf_get_pixels(pixbuf);
1516 guchar *mask = gdk_pixbuf_get_pixels(pmask);
1517 int bmprowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
1518 int maskrowinc = gdk_pixbuf_get_rowstride(pmask) - 3 * width;
1519
1520 for (int y = 0; y < height;
1521 y++, bmp += bmprowinc, mask += maskrowinc)
1522 {
1523 for (int x = 0; x < width; x++, bmp += 4, mask += 3)
1524 {
1525 if (mask[0] == 0 /*black pixel*/)
1526 bmp[3] = 0;
1527 }
1528 }
1529
1530 gdk_pixbuf_unref(pmask);
1531 }
1532 }
1533 }
1534
1535 return M_BMPDATA->m_pixbuf;
1536 }
1537
1538 bool wxBitmap::HasPixbuf() const
1539 {
1540 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1541
1542 return M_BMPDATA->m_pixbuf != NULL;
1543 }
1544
1545 void wxBitmap::SetPixbuf( GdkPixbuf *pixbuf )
1546 {
1547 if (!m_refData)
1548 m_refData = new wxBitmapRefData();
1549
1550 M_BMPDATA->m_pixbuf = pixbuf;
1551 PurgeOtherRepresentations(Pixbuf);
1552 }
1553
1554 void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
1555 {
1556 if (keep == Pixmap && HasPixbuf())
1557 {
1558 gdk_pixbuf_unref( M_BMPDATA->m_pixbuf );
1559 M_BMPDATA->m_pixbuf = NULL;
1560 }
1561 if (keep == Pixbuf && HasPixmap())
1562 {
1563 gdk_pixmap_unref( M_BMPDATA->m_pixmap );
1564 M_BMPDATA->m_pixmap = NULL;
1565 }
1566 }
1567
1568 #endif // __WXGTK20__
1569
1570 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
1571 {
1572 #ifdef __WXGTK20__
1573 if (bpp != 32)
1574 return NULL;
1575
1576 GdkPixbuf *pixbuf = GetPixbuf();
1577 if (!pixbuf)
1578 return NULL;
1579
1580 #if 0
1581 if (gdk_pixbuf_get_has_alpha( pixbuf ))
1582 wxPrintf( wxT("Has alpha\n") );
1583 else
1584 wxPrintf( wxT("No alpha.\n") );
1585 #endif
1586
1587 data.m_height = gdk_pixbuf_get_height( pixbuf );
1588 data.m_width = gdk_pixbuf_get_width( pixbuf );
1589 data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
1590
1591 return gdk_pixbuf_get_pixels( pixbuf );
1592 #else
1593 return NULL;
1594 #endif
1595 }
1596
1597 void wxBitmap::UngetRawData(wxPixelDataBase& data)
1598 {
1599 }
1600
1601
1602 bool wxBitmap::HasAlpha() const
1603 {
1604 #ifdef __WXGTK20__
1605 return HasPixbuf();
1606 #else
1607 return false;
1608 #endif
1609 }
1610
1611 void wxBitmap::UseAlpha()
1612 {
1613 #ifdef __WXGTK20__
1614 GetPixbuf();
1615 #endif
1616 }
1617
1618 //-----------------------------------------------------------------------------
1619 // wxBitmapHandler
1620 //-----------------------------------------------------------------------------
1621
1622 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler,wxBitmapHandlerBase)
1623
1624 wxBitmapHandler::~wxBitmapHandler()
1625 {
1626 }
1627
1628 bool wxBitmapHandler::Create(wxBitmap *bitmap, void *data, long type, int width, int height, int depth)
1629 {
1630 return false;
1631 }
1632
1633 bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1634 int desiredWidth, int desiredHeight)
1635 {
1636 return false;
1637 }
1638
1639 bool wxBitmapHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette)
1640 {
1641 return false;
1642 }
1643
1644 /* static */ void wxBitmap::InitStandardHandlers()
1645 {
1646 // TODO: Insert handler based on GdkPixbufs handler later
1647 }
1648
1649