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