+ wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
+
+ const int w = GetWidth();
+ const int h = GetHeight();
+ wxImage image(w, h, false);
+ unsigned char *data = image.GetData();
+
+ wxCHECK_MSG(data != NULL, wxNullImage, wxT("couldn't create image") );
+
+ // prefer pixbuf if available, it will preserve alpha and should be quicker
+ if (HasPixbuf())
+ {
+ GdkPixbuf *pixbuf = GetPixbuf();
+ unsigned char* alpha = NULL;
+ if (gdk_pixbuf_get_has_alpha(pixbuf))
+ {
+ image.SetAlpha();
+ alpha = image.GetAlpha();
+ }
+ const unsigned char* in = gdk_pixbuf_get_pixels(pixbuf);
+ unsigned char *out = data;
+ const int inc = 3 + int(alpha != NULL);
+ const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
+
+ for (int y = 0; y < h; y++, in += rowpad)
+ {
+ for (int x = 0; x < w; x++, in += inc, out += 3)
+ {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ if (alpha != NULL)
+ *alpha++ = in[3];
+ }
+ }
+ }
+ else
+ {
+ GdkPixmap* pixmap = GetPixmap();
+ GdkPixmap* pixmap_invert = NULL;
+ if (GetDepth() == 1)
+ {
+ // mono bitmaps are inverted, i.e. 0 is white
+ pixmap_invert = gdk_pixmap_new(pixmap, w, h, 1);
+ GdkGC* gc = gdk_gc_new(pixmap_invert);
+ gdk_gc_set_function(gc, GDK_COPY_INVERT);
+ gdk_draw_drawable(pixmap_invert, gc, pixmap, 0, 0, 0, 0, w, h);
+ g_object_unref(gc);
+ pixmap = pixmap_invert;
+ }
+ // create a pixbuf which shares data with the wxImage
+ GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
+ data, GDK_COLORSPACE_RGB, false, 8, w, h, 3 * w, NULL, NULL);
+
+ gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
+
+ g_object_unref(pixbuf);
+ if (pixmap_invert != NULL)
+ g_object_unref(pixmap_invert);
+ }
+ // convert mask, unless there is already alpha
+ if (GetMask() && !image.HasAlpha())
+ {
+ // we hard code the mask colour for now but we could also make an
+ // effort (and waste time) to choose a colour not present in the
+ // image already to avoid having to fudge the pixels below --
+ // whether it's worth to do it is unclear however
+ const int MASK_RED = 1;
+ const int MASK_GREEN = 2;
+ const int MASK_BLUE = 3;
+ const int MASK_BLUE_REPLACEMENT = 2;
+
+ image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
+ GdkImage* image_mask = gdk_drawable_get_image(GetMask()->GetBitmap(), 0, 0, w, h);
+
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++, data += 3)
+ {
+ if (gdk_image_get_pixel(image_mask, x, y) == 0)
+ {
+ data[0] = MASK_RED;
+ data[1] = MASK_GREEN;
+ data[2] = MASK_BLUE;
+ }
+ else if (data[0] == MASK_RED && data[1] == MASK_GREEN && data[2] == MASK_BLUE)
+ {
+ // we have to fudge the colour a bit to prevent
+ // this pixel from appearing transparent
+ data[2] = MASK_BLUE_REPLACEMENT;
+ }
+ }
+ }
+ g_object_unref(image_mask);
+ }
+
+ return image;