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