+ GdkBitmap* mask = NULL;
+ SetPixmap(gdk_pixmap_create_from_xpm_d(wxGetRootWindow()->window, &mask, NULL, wx_const_cast(char**, bits)));
+
+ if (M_BMPDATA->m_pixmap != NULL && mask != NULL)
+ {
+ M_BMPDATA->m_mask = new wxMask;
+ M_BMPDATA->m_mask->m_bitmap = mask;
+ }
+}
+
+wxBitmap::~wxBitmap()
+{
+}
+
+bool wxBitmap::Create( int width, int height, int depth )
+{
+ UnRef();
+
+ if ( width <= 0 || height <= 0 )
+ {
+ return false;
+ }
+
+ if (depth == 32)
+ {
+ SetPixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height), 32);
+ }
+ else
+ {
+ if (depth != 1)
+ {
+ const GdkVisual* visual = wxTheApp->GetGdkVisual();
+ if (depth == -1)
+ depth = visual->depth;
+
+ wxCHECK_MSG(depth == visual->depth, false, wxT("invalid bitmap depth"));
+ }
+
+ SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, width, height, depth));
+ }
+
+ return Ok();
+}
+
+wxBitmap wxBitmap::Rescale(int clipx, int clipy, int clipwidth, int clipheight, int newx, int newy) const
+{
+ wxBitmap bmp;
+
+ wxCHECK_MSG(Ok(), bmp, wxT("invalid bitmap"));
+
+ int width = wxMax(newx, 1);
+ int height = wxMax(newy, 1);
+ width = wxMin(width, clipwidth);
+ height = wxMin(height, clipheight);
+
+ const double scale_x = double(newx) / M_BMPDATA->m_width;
+ const double scale_y = double(newy) / M_BMPDATA->m_height;
+
+ // Converting to pixbuf, scaling with gdk_pixbuf_scale, and converting
+ // back, is faster than scaling pixmap ourselves.
+
+ // use pixbuf if already available,
+ // otherwise create temporary pixbuf from pixmap
+ GdkPixbuf* pixbuf = M_BMPDATA->m_pixbuf;
+ if (pixbuf)
+ g_object_ref(pixbuf);
+ else
+ pixbuf = gdk_pixbuf_get_from_drawable(
+ NULL, M_BMPDATA->m_pixmap, NULL,
+ 0, 0, 0, 0, M_BMPDATA->m_width, M_BMPDATA->m_height);
+
+ // new pixbuf for scaled wxBitmap
+ GdkPixbuf* pixbuf_scaled = gdk_pixbuf_new(
+ GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha(pixbuf), 8, width, height);
+
+ // GDK_INTERP_NEAREST is the lowest-quality method for continuous-tone
+ // images, but the only one which preserves sharp edges
+ gdk_pixbuf_scale(
+ pixbuf, pixbuf_scaled,
+ 0, 0, width, height, -clipx, -clipy, scale_x, scale_y,
+ GDK_INTERP_NEAREST);
+
+ g_object_unref(pixbuf);
+ bmp.SetPixbuf(pixbuf_scaled, M_BMPDATA->m_bpp);
+
+ if (M_BMPDATA->m_mask)
+ {
+ pixbuf = gdk_pixbuf_get_from_drawable(
+ NULL, M_BMPDATA->m_mask->m_bitmap, NULL,
+ 0, 0, 0, 0, M_BMPDATA->m_width, M_BMPDATA->m_height);
+
+ pixbuf_scaled = gdk_pixbuf_new(
+ GDK_COLORSPACE_RGB, false, 8, width, height);
+
+ gdk_pixbuf_scale(
+ pixbuf, pixbuf_scaled,
+ 0, 0, width, height, -clipx, -clipy, scale_x, scale_y,
+ GDK_INTERP_NEAREST);
+
+ g_object_unref(pixbuf);
+
+ // use existing functionality to create mask from scaled pixbuf
+ wxBitmap maskbmp;
+ maskbmp.SetPixbuf(pixbuf_scaled);
+ bmp.SetMask(new wxMask(maskbmp, *wxBLACK));
+ }
+ return bmp;
+}
+
+#if wxUSE_IMAGE
+
+bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
+{
+ UnRef();
+
+ wxCHECK_MSG( image.Ok(), false, wxT("invalid image") );
+ wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") );
+
+ if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
+ return false;
+
+ // create pixbuf if image has alpha and requested depth is compatible
+ if (image.HasAlpha() && (depth == -1 || depth == 32))
+ return CreateFromImageAsPixbuf(image);
+
+ // otherwise create pixmap, if alpha is present it will be converted to mask
+ return CreateFromImageAsPixmap(image, depth);
+}
+
+bool wxBitmap::CreateFromImageAsPixmap(const wxImage& image, int depth)
+{
+ const int w = image.GetWidth();
+ const int h = image.GetHeight();
+ if (depth == 1)
+ {
+ // create XBM format bitmap
+
+ // one bit per pixel, each row starts on a byte boundary
+ const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
+ wxByte* out = new wxByte[out_size];
+ // set bits are black
+ memset(out, 0xff, out_size);
+ const wxByte* in = image.GetData();
+ unsigned bit_index = 0;
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++, in += 3, bit_index++)
+ if (in[0] == 255 && in[1] == 255 && in[2] == 255)
+ out[bit_index >> 3] ^= 1 << (bit_index & 7);
+ // move index to next byte boundary
+ bit_index = (bit_index + 7) & ~7u;
+ }
+ SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h));
+ delete[] out;
+ }
+ else
+ {
+ SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, w, h, depth));
+ GdkGC* gc = gdk_gc_new(M_BMPDATA->m_pixmap);
+ gdk_draw_rgb_image(
+ M_BMPDATA->m_pixmap, gc,
+ 0, 0, w, h,
+ GDK_RGB_DITHER_NONE, image.GetData(), w * 3);
+ g_object_unref(gc);
+ }
+
+ const wxByte* alpha = image.GetAlpha();
+ if (alpha != NULL || image.HasMask())
+ {
+ // create mask as XBM format bitmap
+
+ const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
+ wxByte* out = new wxByte[out_size];
+ memset(out, 0xff, out_size);
+ unsigned bit_index = 0;
+ if (alpha != NULL)
+ {
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++, bit_index++)
+ if (*alpha++ < wxIMAGE_ALPHA_THRESHOLD)
+ out[bit_index >> 3] ^= 1 << (bit_index & 7);
+ bit_index = (bit_index + 7) & ~7u;
+ }
+ }
+ else
+ {
+ const wxByte r_mask = image.GetMaskRed();
+ const wxByte g_mask = image.GetMaskGreen();
+ const wxByte b_mask = image.GetMaskBlue();
+ const wxByte* in = image.GetData();
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++, in += 3, bit_index++)
+ if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
+ out[bit_index >> 3] ^= 1 << (bit_index & 7);
+ bit_index = (bit_index + 7) & ~7u;
+ }
+ }
+ wxMask* mask = new wxMask;
+ mask->m_bitmap = gdk_bitmap_create_from_data(M_BMPDATA->m_pixmap, (char*)out, w, h);
+ SetMask(mask);
+ delete[] out;
+ }
+ return true;