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