1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/gtk/bitmap.cpp
4
// Author: Robert Roebling
5
// Copyright: (c) 1998 Robert Roebling
6
// Licence: wxWindows licence
7
/////////////////////////////////////////////////////////////////////////////
9
// For compilers that support precompilation, includes "wx.h".
10
#include "wx/wxprec.h"
12
#include "wx/bitmap.h"
17
#include "wx/colour.h"
20
#include "wx/rawbmp.h"
22
#include "wx/gtk/private/object.h"
23
#include "wx/gtk/private.h"
27
extern GtkWidget *wxGetRootWindow();
30
static void PixmapToPixbuf(GdkPixmap* pixmap, GdkPixbuf* pixbuf, int w, int h)
32
gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
33
if (gdk_drawable_get_depth(pixmap) == 1)
35
// invert to match XBM convention
36
guchar* p = gdk_pixbuf_get_pixels(pixbuf);
37
const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
38
const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - w * inc;
39
for (int y = h; y; y--, p += rowpad)
40
for (int x = w; x; x--, p += inc)
42
// pixels are either (0,0,0) or (0xff,0xff,0xff)
50
static void MaskToAlpha(GdkPixmap* mask, GdkPixbuf* pixbuf, int w, int h)
52
GdkPixbuf* mask_pixbuf = gdk_pixbuf_get_from_drawable(
53
NULL, mask, NULL, 0, 0, 0, 0, w, h);
54
guchar* p = gdk_pixbuf_get_pixels(pixbuf) + 3;
55
const guchar* mask_data = gdk_pixbuf_get_pixels(mask_pixbuf);
56
const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - w * 4;
57
const int mask_rowpad = gdk_pixbuf_get_rowstride(mask_pixbuf) - w * 3;
58
for (int y = h; y; y--, p += rowpad, mask_data += mask_rowpad)
60
for (int x = w; x; x--, p += 4, mask_data += 3)
63
// no need to test all 3 components,
64
// pixels are either (0,0,0) or (0xff,0xff,0xff)
65
if (mask_data[0] == 0)
69
g_object_unref(mask_pixbuf);
73
//-----------------------------------------------------------------------------
75
//-----------------------------------------------------------------------------
77
IMPLEMENT_DYNAMIC_CLASS(wxMask, wxMaskBase)
84
wxMask::wxMask(const wxMask& mask)
90
const int w = cairo_image_surface_get_width(mask.m_bitmap);
91
const int h = cairo_image_surface_get_height(mask.m_bitmap);
92
m_bitmap = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
93
const guchar* src = cairo_image_surface_get_data(mask.m_bitmap);
94
guchar* dst = cairo_image_surface_get_data(m_bitmap);
95
const int stride = cairo_image_surface_get_stride(m_bitmap);
96
wxASSERT(stride == cairo_image_surface_get_stride(mask.m_bitmap));
97
memcpy(dst, src, stride * h);
98
cairo_surface_mark_dirty(m_bitmap);
101
if ( !mask.m_bitmap )
107
// create a copy of an existing mask
109
gdk_drawable_get_size(mask.m_bitmap, &w, &h);
110
m_bitmap = gdk_pixmap_new(mask.m_bitmap, w, h, 1);
112
wxGtkObject<GdkGC> gc(gdk_gc_new(m_bitmap));
113
gdk_draw_drawable(m_bitmap, gc, mask.m_bitmap, 0, 0, 0, 0, -1, -1);
117
wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
120
InitFromColour(bitmap, colour);
124
wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
127
Create( bitmap, paletteIndex );
129
#endif // wxUSE_PALETTE
131
wxMask::wxMask( const wxBitmap& bitmap )
134
InitFromMonoBitmap(bitmap);
138
wxMask::wxMask(cairo_surface_t* bitmap)
140
wxMask::wxMask(GdkPixmap* bitmap)
151
cairo_surface_destroy(m_bitmap);
153
g_object_unref (m_bitmap);
158
void wxMask::FreeData()
163
cairo_surface_destroy(m_bitmap);
165
g_object_unref (m_bitmap);
171
bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
173
const int w = bitmap.GetWidth();
174
const int h = bitmap.GetHeight();
177
m_bitmap = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
178
GdkPixbuf* pixbuf = bitmap.GetPixbufNoMask();
179
const guchar* src = gdk_pixbuf_get_pixels(pixbuf);
180
guchar* dst = cairo_image_surface_get_data(m_bitmap);
181
const int stride_src = gdk_pixbuf_get_rowstride(pixbuf);
182
const int stride_dst = cairo_image_surface_get_stride(m_bitmap);
183
const int src_inc = gdk_pixbuf_get_n_channels(pixbuf);
184
const guchar r = colour.Red();
185
const guchar g = colour.Green();
186
const guchar b = colour.Blue();
187
for (int j = 0; j < h; j++, src += stride_src, dst += stride_dst)
189
const guchar* s = src;
190
for (int i = 0; i < w; i++, s += src_inc)
193
if (s[0] == r && s[1] == g && s[2] == b)
197
cairo_surface_mark_dirty(m_bitmap);
199
// create mask as XBM format bitmap
201
// one bit per pixel, each row starts on a byte boundary
202
const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
203
wxByte* out = new wxByte[out_size];
204
// set bits are unmasked
205
memset(out, 0xff, out_size);
206
unsigned bit_index = 0;
207
if (bitmap.HasPixbuf())
209
const wxByte r_mask = colour.Red();
210
const wxByte g_mask = colour.Green();
211
const wxByte b_mask = colour.Blue();
212
GdkPixbuf* pixbuf = bitmap.GetPixbuf();
213
const wxByte* in = gdk_pixbuf_get_pixels(pixbuf);
214
const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
215
const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
216
for (int y = 0; y < h; y++, in += rowpadding)
218
for (int x = 0; x < w; x++, in += inc, bit_index++)
219
if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
220
out[bit_index >> 3] ^= 1 << (bit_index & 7);
221
// move index to next byte boundary
222
bit_index = (bit_index + 7) & ~7u;
227
GdkImage* image = gdk_drawable_get_image(bitmap.GetPixmap(), 0, 0, w, h);
228
GdkColormap* colormap = gdk_image_get_colormap(image);
230
if (colormap == NULL)
231
// mono bitmap, white is pixel value 0
232
mask_pixel = guint32(colour.Red() != 255 || colour.Green() != 255 || colour.Blue() != 255);
236
c.CalcPixel(colormap);
237
mask_pixel = c.GetPixel();
239
for (int y = 0; y < h; y++)
241
for (int x = 0; x < w; x++, bit_index++)
242
if (gdk_image_get_pixel(image, x, y) == mask_pixel)
243
out[bit_index >> 3] ^= 1 << (bit_index & 7);
244
bit_index = (bit_index + 7) & ~7u;
246
g_object_unref(image);
248
m_bitmap = gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h);
254
bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap)
256
if (!bitmap.IsOk()) return false;
258
wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
261
InitFromColour(bitmap, *wxBLACK);
263
m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
265
if (!m_bitmap) return false;
267
wxGtkObject<GdkGC> gc(gdk_gc_new( m_bitmap ));
268
gdk_gc_set_function(gc, GDK_COPY_INVERT);
269
gdk_draw_drawable(m_bitmap, gc, bitmap.GetPixmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight());
275
wxBitmap wxMask::GetBitmap() const
281
cairo_surface_t* mask = m_bitmap;
282
const int w = cairo_image_surface_get_width(mask);
283
const int h = cairo_image_surface_get_height(mask);
284
GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, w, h);
285
const guchar* src = cairo_image_surface_get_data(mask);
286
guchar* dst = gdk_pixbuf_get_pixels(pixbuf);
287
const int stride_src = cairo_image_surface_get_stride(mask);
288
const int stride_dst = gdk_pixbuf_get_rowstride(pixbuf);
289
for (int j = 0; j < h; j++, src += stride_src, dst += stride_dst)
292
for (int i = 0; i < w; i++, d += 3)
299
bitmap = wxBitmap(pixbuf, 1);
301
GdkPixmap* mask = m_bitmap;
303
gdk_drawable_get_size(mask, &w, &h);
304
GdkPixmap* pixmap = gdk_pixmap_new(mask, w, h, -1);
305
GdkGC* gc = gdk_gc_new(pixmap);
306
gdk_gc_set_function(gc, GDK_COPY_INVERT);
307
gdk_draw_drawable(pixmap, gc, mask, 0, 0, 0, 0, w, h);
309
bitmap = wxBitmap(pixmap);
316
wxMask::operator cairo_surface_t*() const
318
wxMask::operator GdkPixmap*() const
324
//-----------------------------------------------------------------------------
326
//-----------------------------------------------------------------------------
328
class wxBitmapRefData: public wxGDIRefData
331
wxBitmapRefData(int width, int height, int depth);
332
virtual ~wxBitmapRefData();
334
virtual bool IsOk() const;
337
GdkPixbuf* m_pixbufMask;
338
GdkPixbuf* m_pixbufNoMask;
339
cairo_surface_t* m_surface;
349
bool m_alphaRequested;
352
// We don't provide a copy ctor as copying m_pixmap and m_pixbuf properly
353
// is expensive and we don't want to do it implicitly (and possibly
354
// accidentally). wxBitmap::CloneGDIRefData() which does need to do it does
355
// it explicitly itself.
356
wxDECLARE_NO_COPY_CLASS(wxBitmapRefData);
359
wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
363
m_pixbufNoMask = NULL;
374
if (m_bpp != 1 && m_bpp != 32)
378
m_bpp = gdk_drawable_get_depth(wxGetRootWindow()->window);
379
m_alphaRequested = depth == 32;
383
wxBitmapRefData::~wxBitmapRefData()
387
g_object_unref(m_pixbufMask);
389
g_object_unref(m_pixbufNoMask);
391
cairo_surface_destroy(m_surface);
394
g_object_unref (m_pixmap);
396
g_object_unref (m_pixbuf);
401
bool wxBitmapRefData::IsOk() const
406
//-----------------------------------------------------------------------------
408
//-----------------------------------------------------------------------------
410
#define M_BMPDATA static_cast<wxBitmapRefData*>(m_refData)
412
IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
414
wxBitmap::wxBitmap(const wxString &filename, wxBitmapType type)
416
LoadFile(filename, type);
419
wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
421
wxASSERT(depth == 1);
422
if (width > 0 && height > 0 && depth == 1)
424
m_refData = new wxBitmapRefData(width, height, 1);
426
GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, width, height);
427
M_BMPDATA->m_pixbufNoMask = pixbuf;
428
const char* src = bits;
429
guchar* dst = gdk_pixbuf_get_pixels(pixbuf);
430
const int stride_src = (width + 7) / 8;
431
const int rowinc_dst = gdk_pixbuf_get_rowstride(pixbuf) - 3 * width;
432
for (int j = 0; j < width; j++, src += stride_src, dst += rowinc_dst)
434
for (int i = 0; i < height; i++)
437
if (src[i >> 3] & (1 << (i & 7)))
445
M_BMPDATA->m_pixmap = gdk_bitmap_create_from_data(
446
wxGetRootWindow()->window, bits, width, height);
451
wxBitmap::wxBitmap(const char* const* bits)
453
wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data"));
456
*this = wxBitmap(wxImage(bits));
457
#elif defined __WXGTK3__
458
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(const_cast<const char**>(bits));
461
m_refData = new wxBitmapRefData(
462
gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf),
463
gdk_pixbuf_get_n_channels(pixbuf) * 8);
464
M_BMPDATA->m_pixbufNoMask = pixbuf;
465
wxASSERT(M_BMPDATA->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(M_BMPDATA->m_pixbufNoMask));
468
GdkBitmap* mask = NULL;
469
GdkPixmap* pixmap = gdk_pixmap_create_from_xpm_d(wxGetRootWindow()->window, &mask, NULL, const_cast<char**>(bits));
473
gdk_drawable_get_size(pixmap, &width, &height);
474
m_refData = new wxBitmapRefData(width, height, -1);
475
M_BMPDATA->m_pixmap = pixmap;
478
M_BMPDATA->m_mask = new wxMask(mask);
484
wxBitmap::wxBitmap(GdkPixbuf* pixbuf, int depth)
489
depth = gdk_pixbuf_get_n_channels(pixbuf) * 8;
490
wxBitmapRefData* bmpData = new wxBitmapRefData(
491
gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf),
495
bmpData->m_pixbufNoMask = pixbuf;
497
bmpData->m_pixbuf = pixbuf;
503
wxBitmap::wxBitmap(GdkPixmap* pixmap)
508
gdk_drawable_get_size(pixmap, &w, &h);
509
wxBitmapRefData* bmpData =
510
new wxBitmapRefData(w, h, gdk_drawable_get_depth(pixmap));
512
bmpData->m_pixmap = pixmap;
517
wxBitmap::~wxBitmap()
521
bool wxBitmap::Create( int width, int height, int depth )
524
wxCHECK_MSG(width >= 0 && height >= 0, false, "invalid bitmap size");
525
m_refData = new wxBitmapRefData(width, height, depth);
530
static void CopyImageData(
531
guchar* dst, int dstChannels, int dstStride,
532
const guchar* src, int srcChannels, int srcStride,
535
if (dstChannels == srcChannels)
537
if (dstStride == srcStride)
538
memcpy(dst, src, size_t(dstStride) * h);
541
const int stride = dstStride < srcStride ? dstStride : srcStride;
542
for (int j = 0; j < h; j++, src += srcStride, dst += dstStride)
543
memcpy(dst, src, stride);
548
for (int j = 0; j < h; j++, src += srcStride, dst += dstStride)
551
const guchar* s = src;
552
if (dstChannels == 4)
554
for (int i = 0; i < w; i++, d += 4, s += 3)
564
for (int i = 0; i < w; i++, d += 3, s += 4)
578
wxBitmap::wxBitmap(const wxImage& image, int depth)
580
wxCHECK_RET(image.IsOk(), "invalid image");
582
const int w = image.GetWidth();
583
const int h = image.GetHeight();
584
const guchar* alpha = image.GetAlpha();
586
depth = alpha ? 32 : 24;
587
else if (depth != 1 && depth != 32)
589
wxBitmapRefData* bmpData = new wxBitmapRefData(w, h, depth);
591
GdkPixbuf* pixbuf_dst = gdk_pixbuf_new(GDK_COLORSPACE_RGB, depth == 32, 8, w, h);
592
bmpData->m_pixbufNoMask = pixbuf_dst;
593
wxASSERT(bmpData->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(bmpData->m_pixbufNoMask));
594
const guchar* src = image.GetData();
596
guchar* dst = gdk_pixbuf_get_pixels(pixbuf_dst);
597
const int dstStride = gdk_pixbuf_get_rowstride(pixbuf_dst);
598
CopyImageData(dst, gdk_pixbuf_get_n_channels(pixbuf_dst), dstStride, src, 3, 3 * w, w, h);
600
if (depth == 32 && alpha)
602
for (int j = 0; j < h; j++, dst += dstStride)
603
for (int i = 0; i < w; i++)
604
dst[i * 4 + 3] = *alpha++;
608
const guchar r = image.GetMaskRed();
609
const guchar g = image.GetMaskGreen();
610
const guchar b = image.GetMaskBlue();
611
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
612
const int stride = cairo_image_surface_get_stride(surface);
613
dst = cairo_image_surface_get_data(surface);
614
memset(dst, 0xff, stride * h);
615
for (int j = 0; j < h; j++, dst += stride)
616
for (int i = 0; i < w; i++, src += 3)
617
if (src[0] == r && src[1] == g && src[2] == b)
619
cairo_surface_mark_dirty(surface);
620
bmpData->m_mask = new wxMask(surface);
624
wxBitmap::wxBitmap(const wxImage& image, int depth)
626
wxCHECK_RET(image.IsOk(), "invalid image");
628
if (depth == 32 || (depth == -1 && image.HasAlpha()))
629
CreateFromImageAsPixbuf(image);
631
// otherwise create pixmap, if alpha is present it will be converted to mask
632
CreateFromImageAsPixmap(image, depth);
635
bool wxBitmap::CreateFromImageAsPixmap(const wxImage& image, int depth)
637
const int w = image.GetWidth();
638
const int h = image.GetHeight();
641
// create XBM format bitmap
643
// one bit per pixel, each row starts on a byte boundary
644
const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
645
wxByte* out = new wxByte[out_size];
646
// set bits are black
647
memset(out, 0xff, out_size);
648
const wxByte* in = image.GetData();
649
unsigned bit_index = 0;
650
for (int y = 0; y < h; y++)
652
for (int x = 0; x < w; x++, in += 3, bit_index++)
653
if (in[0] == 255 && in[1] == 255 && in[2] == 255)
654
out[bit_index >> 3] ^= 1 << (bit_index & 7);
655
// move index to next byte boundary
656
bit_index = (bit_index + 7) & ~7u;
658
SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h));
661
if (!M_BMPDATA) // SetPixmap may have failed
666
SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, w, h, depth));
670
wxGtkObject<GdkGC> gc(gdk_gc_new(M_BMPDATA->m_pixmap));
672
M_BMPDATA->m_pixmap, gc,
674
GDK_RGB_DITHER_NONE, image.GetData(), w * 3);
677
const wxByte* alpha = image.GetAlpha();
678
if (alpha != NULL || image.HasMask())
680
// create mask as XBM format bitmap
682
const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
683
wxByte* out = new wxByte[out_size];
684
memset(out, 0xff, out_size);
685
unsigned bit_index = 0;
688
for (int y = 0; y < h; y++)
690
for (int x = 0; x < w; x++, bit_index++)
691
if (*alpha++ < wxIMAGE_ALPHA_THRESHOLD)
692
out[bit_index >> 3] ^= 1 << (bit_index & 7);
693
bit_index = (bit_index + 7) & ~7u;
698
const wxByte r_mask = image.GetMaskRed();
699
const wxByte g_mask = image.GetMaskGreen();
700
const wxByte b_mask = image.GetMaskBlue();
701
const wxByte* in = image.GetData();
702
for (int y = 0; y < h; y++)
704
for (int x = 0; x < w; x++, in += 3, bit_index++)
705
if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
706
out[bit_index >> 3] ^= 1 << (bit_index & 7);
707
bit_index = (bit_index + 7) & ~7u;
710
SetMask(new wxMask(gdk_bitmap_create_from_data(M_BMPDATA->m_pixmap, (char*)out, w, h)));
716
bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
718
int width = image.GetWidth();
719
int height = image.GetHeight();
721
Create(width, height, 32);
722
GdkPixbuf* pixbuf = GetPixbuf();
727
const unsigned char* in = image.GetData();
728
unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
729
unsigned char *alpha = image.GetAlpha();
731
int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
733
for (int y = 0; y < height; y++, out += rowpad)
735
for (int x = 0; x < width; x++, out += 4, in += 3)
749
wxImage wxBitmap::ConvertToImage() const
753
wxCHECK_MSG(IsOk(), image, "invalid bitmap");
754
wxBitmapRefData* bmpData = M_BMPDATA;
755
const int w = bmpData->m_width;
756
const int h = bmpData->m_height;
757
image.Create(w, h, false);
758
guchar* dst = image.GetData();
759
GdkPixbuf* pixbuf_src = NULL;
760
if (bmpData->m_pixbufNoMask)
761
pixbuf_src = bmpData->m_pixbufNoMask;
762
else if (bmpData->m_surface)
764
pixbuf_src = gdk_pixbuf_get_from_surface(bmpData->m_surface, 0, 0, w, h);
765
bmpData->m_pixbufNoMask = pixbuf_src;
766
wxASSERT(bmpData->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(bmpData->m_pixbufNoMask));
770
const guchar* src = gdk_pixbuf_get_pixels(pixbuf_src);
771
const int srcStride = gdk_pixbuf_get_rowstride(pixbuf_src);
772
const int srcChannels = gdk_pixbuf_get_n_channels(pixbuf_src);
773
CopyImageData(dst, 3, 3 * w, src, srcChannels, srcStride, w, h);
775
if (srcChannels == 4)
778
guchar* alpha = image.GetAlpha();
779
for (int j = 0; j < h; j++, src += srcStride)
781
const guchar* s = src;
782
for (int i = 0; i < w; i++, s += 4)
787
cairo_surface_t* maskSurf = NULL;
789
maskSurf = *bmpData->m_mask;
795
image.SetMaskColour(r, g, b);
796
wxASSERT(cairo_image_surface_get_format(maskSurf) == CAIRO_FORMAT_A8);
797
const int stride = cairo_image_surface_get_stride(maskSurf);
798
const guchar* src = cairo_image_surface_get_data(maskSurf);
799
for (int j = 0; j < h; j++, src += stride)
801
for (int i = 0; i < w; i++, dst += 3)
808
else if (dst[0] == r && dst[1] == g && dst[2] == b)
813
wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
815
const int w = GetWidth();
816
const int h = GetHeight();
817
wxImage image(w, h, false);
818
unsigned char *data = image.GetData();
820
wxCHECK_MSG(data != NULL, wxNullImage, wxT("couldn't create image") );
822
// prefer pixbuf if available, it will preserve alpha and should be quicker
825
GdkPixbuf *pixbuf = GetPixbuf();
826
unsigned char* alpha = NULL;
827
if (gdk_pixbuf_get_has_alpha(pixbuf))
830
alpha = image.GetAlpha();
832
const unsigned char* in = gdk_pixbuf_get_pixels(pixbuf);
833
unsigned char *out = data;
834
const int inc = 3 + int(alpha != NULL);
835
const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
837
for (int y = 0; y < h; y++, in += rowpad)
839
for (int x = 0; x < w; x++, in += inc, out += 3)
851
GdkPixmap* pixmap = GetPixmap();
852
GdkPixmap* pixmap_invert = NULL;
855
// mono bitmaps are inverted, i.e. 0 is white
856
pixmap_invert = gdk_pixmap_new(pixmap, w, h, 1);
857
wxGtkObject<GdkGC> gc(gdk_gc_new(pixmap_invert));
858
gdk_gc_set_function(gc, GDK_COPY_INVERT);
859
gdk_draw_drawable(pixmap_invert, gc, pixmap, 0, 0, 0, 0, w, h);
860
pixmap = pixmap_invert;
862
// create a pixbuf which shares data with the wxImage
863
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
864
data, GDK_COLORSPACE_RGB, false, 8, w, h, 3 * w, NULL, NULL);
866
gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
868
g_object_unref(pixbuf);
869
if (pixmap_invert != NULL)
870
g_object_unref(pixmap_invert);
872
// convert mask, unless there is already alpha
873
if (GetMask() && !image.HasAlpha())
875
// we hard code the mask colour for now but we could also make an
876
// effort (and waste time) to choose a colour not present in the
877
// image already to avoid having to fudge the pixels below --
878
// whether it's worth to do it is unclear however
879
const int MASK_RED = 1;
880
const int MASK_GREEN = 2;
881
const int MASK_BLUE = 3;
882
const int MASK_BLUE_REPLACEMENT = 2;
884
image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
885
GdkImage* image_mask = gdk_drawable_get_image(*GetMask(), 0, 0, w, h);
887
for (int y = 0; y < h; y++)
889
for (int x = 0; x < w; x++, data += 3)
891
if (gdk_image_get_pixel(image_mask, x, y) == 0)
894
data[1] = MASK_GREEN;
897
else if (data[0] == MASK_RED && data[1] == MASK_GREEN && data[2] == MASK_BLUE)
899
// we have to fudge the colour a bit to prevent
900
// this pixel from appearing transparent
901
data[2] = MASK_BLUE_REPLACEMENT;
905
g_object_unref(image_mask);
912
#endif // wxUSE_IMAGE
914
int wxBitmap::GetHeight() const
916
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
918
return M_BMPDATA->m_height;
921
int wxBitmap::GetWidth() const
923
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
925
return M_BMPDATA->m_width;
928
int wxBitmap::GetDepth() const
930
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
932
return M_BMPDATA->m_bpp;
935
wxMask *wxBitmap::GetMask() const
937
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
939
return M_BMPDATA->m_mask;
942
void wxBitmap::SetMask( wxMask *mask )
944
wxCHECK_RET( IsOk(), wxT("invalid bitmap") );
947
delete M_BMPDATA->m_mask;
948
M_BMPDATA->m_mask = mask;
951
bool wxBitmap::CopyFromIcon(const wxIcon& icon)
958
static cairo_surface_t* GetSubSurface(cairo_surface_t* surface, const wxRect& rect)
960
cairo_surface_flush(surface);
961
const cairo_format_t format = cairo_image_surface_get_format(surface);
963
if (format != CAIRO_FORMAT_A8)
965
cairo_surface_t* subSurface = cairo_image_surface_create(format, rect.width, rect.height);
966
const int srcStride = cairo_image_surface_get_stride(surface);
967
const int dstStride = cairo_image_surface_get_stride(subSurface);
968
const guchar* src = cairo_image_surface_get_data(surface) + rect.y * srcStride + x;
969
guchar* dst = cairo_image_surface_get_data(subSurface);
970
for (int j = 0; j < rect.height; j++, src += srcStride, dst += dstStride)
971
memcpy(dst, src, dstStride);
972
cairo_surface_mark_dirty(subSurface);
977
wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
981
wxCHECK_MSG(IsOk(), ret, wxT("invalid bitmap"));
983
const int w = rect.width;
984
const int h = rect.height;
985
const wxBitmapRefData* bmpData = M_BMPDATA;
987
wxCHECK_MSG(rect.x >= 0 && rect.y >= 0 &&
988
rect.x + w <= bmpData->m_width &&
989
rect.y + h <= bmpData->m_height,
990
ret, wxT("invalid bitmap region"));
992
wxBitmapRefData * const newRef = new wxBitmapRefData(w, h, bmpData->m_bpp);
993
ret.m_refData = newRef;
996
if (bmpData->m_pixbufNoMask)
998
GdkPixbuf* pixbuf = gdk_pixbuf_new_subpixbuf(bmpData->m_pixbufNoMask, rect.x, rect.y, w, h);
999
newRef->m_pixbufNoMask = gdk_pixbuf_copy(pixbuf);
1000
wxASSERT(newRef->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(newRef->m_pixbufNoMask));
1001
g_object_unref(pixbuf);
1003
else if (bmpData->m_surface)
1004
newRef->m_surface = GetSubSurface(bmpData->m_surface, rect);
1006
cairo_surface_t* maskSurf = NULL;
1007
if (bmpData->m_mask)
1008
maskSurf = *bmpData->m_mask;
1011
newRef->m_mask = new wxMask(GetSubSurface(maskSurf, rect));
1014
if (bmpData->m_pixbuf)
1017
gdk_pixbuf_new_subpixbuf(bmpData->m_pixbuf, rect.x, rect.y, w, h);
1018
newRef->m_pixbuf = gdk_pixbuf_copy(pixbuf);
1019
g_object_unref(pixbuf);
1021
if (bmpData->m_pixmap)
1023
newRef->m_pixmap = gdk_pixmap_new(bmpData->m_pixmap, w, h, -1);
1024
GdkGC* gc = gdk_gc_new(newRef->m_pixmap);
1026
newRef->m_pixmap, gc, bmpData->m_pixmap, rect.x, rect.y, 0, 0, w, h);
1029
GdkPixmap* mask = NULL;
1030
if (bmpData->m_mask)
1031
mask = *bmpData->m_mask;
1034
GdkPixmap* sub_mask = gdk_pixmap_new(mask, w, h, 1);
1035
newRef->m_mask = new wxMask(sub_mask);
1036
GdkGC* gc = gdk_gc_new(sub_mask);
1038
sub_mask, gc, mask, rect.x, rect.y, 0, 0, w, h);
1046
bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
1048
wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
1050
const char* type_name = NULL;
1053
case wxBITMAP_TYPE_ANI: type_name = "ani"; break;
1054
case wxBITMAP_TYPE_BMP: type_name = "bmp"; break;
1055
case wxBITMAP_TYPE_GIF: type_name = "gif"; break;
1056
case wxBITMAP_TYPE_ICO: type_name = "ico"; break;
1057
case wxBITMAP_TYPE_JPEG: type_name = "jpeg"; break;
1058
case wxBITMAP_TYPE_PCX: type_name = "pcx"; break;
1059
case wxBITMAP_TYPE_PNG: type_name = "png"; break;
1060
case wxBITMAP_TYPE_PNM: type_name = "pnm"; break;
1061
case wxBITMAP_TYPE_TGA: type_name = "tga"; break;
1062
case wxBITMAP_TYPE_TIFF: type_name = "tiff"; break;
1063
case wxBITMAP_TYPE_XBM: type_name = "xbm"; break;
1064
case wxBITMAP_TYPE_XPM: type_name = "xpm"; break;
1068
gdk_pixbuf_save(GetPixbuf(), wxGTK_CONV_FN(name), type_name, NULL, NULL))
1073
return ConvertToImage().SaveFile(name, type);
1079
bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
1081
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file(wxGTK_CONV_FN(name), NULL);
1084
*this = wxBitmap(pixbuf);
1089
if (image.LoadFile(name, type) && image.IsOk())
1091
*this = wxBitmap(image);
1101
wxPalette *wxBitmap::GetPalette() const
1106
void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
1110
#endif // wxUSE_PALETTE
1112
void wxBitmap::SetHeight( int height )
1115
M_BMPDATA->m_height = height;
1118
void wxBitmap::SetWidth( int width )
1121
M_BMPDATA->m_width = width;
1124
void wxBitmap::SetDepth( int depth )
1127
M_BMPDATA->m_bpp = depth;
1131
void wxBitmap::SetPixmap( GdkPixmap *pixmap )
1139
gdk_drawable_get_size(pixmap, &w, &h);
1140
wxBitmapRefData* bmpData = new wxBitmapRefData(w, h, 0);
1141
m_refData = bmpData;
1142
bmpData->m_pixmap = pixmap;
1143
bmpData->m_bpp = gdk_drawable_get_depth(pixmap);
1146
GdkPixmap *wxBitmap::GetPixmap() const
1148
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
1150
wxBitmapRefData* bmpData = M_BMPDATA;
1151
if (bmpData->m_pixmap)
1152
return bmpData->m_pixmap;
1154
if (bmpData->m_pixbuf)
1156
GdkPixmap* pixmap = NULL;
1157
GdkPixmap** mask_pixmap = NULL;
1158
if (gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf))
1160
// make new mask from alpha
1161
mask_pixmap = &pixmap;
1163
gdk_pixbuf_render_pixmap_and_mask(
1164
bmpData->m_pixbuf, &bmpData->m_pixmap, mask_pixmap, 128);
1167
delete bmpData->m_mask;
1168
bmpData->m_mask = new wxMask(pixmap);
1173
bmpData->m_pixmap = gdk_pixmap_new(wxGetRootWindow()->window,
1174
bmpData->m_width, bmpData->m_height, bmpData->m_bpp == 1 ? 1 : -1);
1176
return bmpData->m_pixmap;
1179
bool wxBitmap::HasPixmap() const
1181
wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
1183
return M_BMPDATA->m_pixmap != NULL;
1188
GdkPixbuf* wxBitmap::GetPixbufNoMask() const
1190
wxCHECK_MSG(IsOk(), NULL, "invalid bitmap");
1192
wxBitmapRefData* bmpData = M_BMPDATA;
1193
GdkPixbuf* pixbuf = bmpData->m_pixbufNoMask;
1197
const int w = bmpData->m_width;
1198
const int h = bmpData->m_height;
1199
if (bmpData->m_surface)
1200
pixbuf = gdk_pixbuf_get_from_surface(bmpData->m_surface, 0, 0, w, h);
1202
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, bmpData->m_bpp == 32, 8, w, h);
1203
bmpData->m_pixbufNoMask = pixbuf;
1204
wxASSERT(bmpData->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(bmpData->m_pixbufNoMask));
1209
// helper to set up a simulated depth 1 surface
1210
static void SetSourceSurface1(const wxBitmapRefData* bmpData, cairo_t* cr, int x, int y, const wxColour* fg, const wxColour* bg)
1212
GdkPixbuf* pixbuf = gdk_pixbuf_copy(bmpData->m_pixbufNoMask);
1213
const int w = bmpData->m_width;
1214
const int h = bmpData->m_height;
1215
const int stride = gdk_pixbuf_get_rowstride(pixbuf);
1216
const int channels = gdk_pixbuf_get_n_channels(pixbuf);
1217
guchar* dst = gdk_pixbuf_get_pixels(pixbuf);
1218
guchar fg_r = 0, fg_g = 0, fg_b = 0;
1219
if (fg && fg->IsOk())
1225
guchar bg_r = 255, bg_g = 255, bg_b = 255;
1226
if (bg && bg->IsOk())
1232
for (int j = 0; j < h; j++, dst += stride)
1235
for (int i = 0; i < w; i++, d += channels)
1249
gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
1250
g_object_unref(pixbuf);
1253
void wxBitmap::SetSourceSurface(cairo_t* cr, int x, int y, const wxColour* fg, const wxColour* bg) const
1255
wxBitmapRefData* bmpData = M_BMPDATA;
1256
if (bmpData->m_surface)
1258
cairo_set_source_surface(cr, bmpData->m_surface, x, y);
1261
wxCHECK_RET(bmpData->m_pixbufNoMask, "no bitmap data");
1262
if (bmpData->m_bpp == 1)
1263
SetSourceSurface1(bmpData, cr, x, y, fg, bg);
1266
gdk_cairo_set_source_pixbuf(cr, bmpData->m_pixbufNoMask, x, y);
1267
cairo_pattern_get_surface(cairo_get_source(cr), &bmpData->m_surface);
1268
cairo_surface_reference(bmpData->m_surface);
1272
cairo_t* wxBitmap::CairoCreate() const
1274
wxCHECK_MSG(IsOk(), NULL, "invalid bitmap");
1276
wxBitmapRefData* bmpData = M_BMPDATA;
1278
if (bmpData->m_surface)
1279
cr = cairo_create(bmpData->m_surface);
1282
GdkPixbuf* pixbuf = bmpData->m_pixbufNoMask;
1283
const bool useAlpha = bmpData->m_bpp == 32 || (pixbuf && gdk_pixbuf_get_has_alpha(pixbuf));
1284
bmpData->m_surface = cairo_image_surface_create(
1285
useAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
1286
bmpData->m_width, bmpData->m_height);
1287
cr = cairo_create(bmpData->m_surface);
1290
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
1292
cairo_set_source_rgb(cr, 0, 0, 0);
1295
if (bmpData->m_pixbufNoMask)
1297
g_object_unref(bmpData->m_pixbufNoMask);
1298
bmpData->m_pixbufNoMask = NULL;
1300
if (bmpData->m_pixbufMask)
1302
g_object_unref(bmpData->m_pixbufMask);
1303
bmpData->m_pixbufMask = NULL;
1305
wxASSERT(cr && cairo_status(cr) == 0);
1309
void wxBitmap::Draw(cairo_t* cr, int x, int y, bool useMask, const wxColour* fg, const wxColour* bg) const
1311
wxCHECK_RET(IsOk(), "invalid bitmap");
1313
wxBitmapRefData* bmpData = M_BMPDATA;
1314
SetSourceSurface(cr, x, y, fg, bg);
1315
cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
1316
cairo_surface_t* mask = NULL;
1317
if (useMask && bmpData->m_mask)
1318
mask = *bmpData->m_mask;
1320
cairo_mask_surface(cr, mask, x, y);
1326
GdkPixbuf *wxBitmap::GetPixbuf() const
1328
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
1330
wxBitmapRefData* bmpData = M_BMPDATA;
1332
if (bmpData->m_pixbufMask)
1333
return bmpData->m_pixbufMask;
1335
if (bmpData->m_pixbufNoMask == NULL)
1337
cairo_surface_t* mask = NULL;
1338
if (bmpData->m_mask)
1339
mask = *bmpData->m_mask;
1341
return bmpData->m_pixbufNoMask;
1343
const int w = bmpData->m_width;
1344
const int h = bmpData->m_height;
1345
bmpData->m_pixbufMask = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, w, h);
1347
guchar* dst = gdk_pixbuf_get_pixels(bmpData->m_pixbufMask);
1348
const int dstStride = gdk_pixbuf_get_rowstride(bmpData->m_pixbufMask);
1349
CopyImageData(dst, 4, dstStride,
1350
gdk_pixbuf_get_pixels(bmpData->m_pixbufNoMask),
1351
gdk_pixbuf_get_n_channels(bmpData->m_pixbufNoMask),
1352
gdk_pixbuf_get_rowstride(bmpData->m_pixbufNoMask),
1355
const guchar* src = cairo_image_surface_get_data(mask);
1356
const int srcStride = cairo_image_surface_get_stride(mask);
1357
for (int j = 0; j < h; j++, src += srcStride, dst += dstStride)
1358
for (int i = 0; i < w; i++)
1362
return bmpData->m_pixbufMask;
1364
if (bmpData->m_pixbuf)
1365
return bmpData->m_pixbuf;
1367
const int w = bmpData->m_width;
1368
const int h = bmpData->m_height;
1369
GdkPixmap* mask = NULL;
1370
if (bmpData->m_mask)
1371
mask = *bmpData->m_mask;
1372
const bool useAlpha = bmpData->m_alphaRequested || mask;
1373
bmpData->m_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, useAlpha, 8, w, h);
1374
if (bmpData->m_pixmap)
1375
PixmapToPixbuf(bmpData->m_pixmap, bmpData->m_pixbuf, w, h);
1377
MaskToAlpha(mask, bmpData->m_pixbuf, w, h);
1378
return bmpData->m_pixbuf;
1383
bool wxBitmap::HasPixbuf() const
1385
wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
1387
return M_BMPDATA->m_pixbuf != NULL;
1390
void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
1392
if (keep == Pixmap && HasPixbuf())
1394
g_object_unref (M_BMPDATA->m_pixbuf);
1395
M_BMPDATA->m_pixbuf = NULL;
1397
if (keep == Pixbuf && HasPixmap())
1399
g_object_unref (M_BMPDATA->m_pixmap);
1400
M_BMPDATA->m_pixmap = NULL;
1405
#ifdef wxHAS_RAW_BITMAP
1406
void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
1410
GdkPixbuf* pixbuf = GetPixbufNoMask();
1411
if ((bpp == 32) == (gdk_pixbuf_get_has_alpha(pixbuf) != 0))
1413
bits = gdk_pixbuf_get_pixels(pixbuf);
1414
wxBitmapRefData* bmpData = M_BMPDATA;
1415
data.m_width = bmpData->m_width;
1416
data.m_height = bmpData->m_height;
1417
data.m_stride = gdk_pixbuf_get_rowstride(pixbuf);
1418
if (bmpData->m_pixbufMask)
1420
g_object_unref(bmpData->m_pixbufMask);
1421
bmpData->m_pixbufMask = NULL;
1423
if (bmpData->m_surface)
1425
cairo_surface_destroy(bmpData->m_surface);
1426
bmpData->m_surface = NULL;
1430
GdkPixbuf *pixbuf = GetPixbuf();
1431
const bool hasAlpha = HasAlpha();
1433
// allow access if bpp is valid and matches existence of alpha
1434
if ( pixbuf && ((bpp == 24 && !hasAlpha) || (bpp == 32 && hasAlpha)) )
1436
data.m_height = gdk_pixbuf_get_height( pixbuf );
1437
data.m_width = gdk_pixbuf_get_width( pixbuf );
1438
data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
1439
bits = gdk_pixbuf_get_pixels(pixbuf);
1445
void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
1448
#endif // wxHAS_RAW_BITMAP
1450
bool wxBitmap::HasAlpha() const
1452
const wxBitmapRefData* bmpData = M_BMPDATA;
1454
return bmpData && bmpData->m_bpp == 32;
1456
return bmpData && (bmpData->m_alphaRequested ||
1457
(bmpData->m_pixbuf && gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf)));
1461
wxGDIRefData* wxBitmap::CreateGDIRefData() const
1463
return new wxBitmapRefData(0, 0, 0);
1466
wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
1468
const wxBitmapRefData* oldRef = static_cast<const wxBitmapRefData*>(data);
1469
wxBitmapRefData * const newRef = new wxBitmapRefData(oldRef->m_width,
1473
if (oldRef->m_pixbufNoMask)
1474
newRef->m_pixbufNoMask = gdk_pixbuf_copy(oldRef->m_pixbufNoMask);
1475
if (oldRef->m_surface)
1477
const int w = oldRef->m_width;
1478
const int h = oldRef->m_height;
1479
cairo_surface_t* surface = cairo_image_surface_create(
1480
cairo_image_surface_get_format(oldRef->m_surface), w, h);
1481
newRef->m_surface = surface;
1482
cairo_surface_flush(oldRef->m_surface);
1483
const guchar* src = cairo_image_surface_get_data(oldRef->m_surface);
1484
guchar* dst = cairo_image_surface_get_data(surface);
1485
const int stride = cairo_image_surface_get_stride(surface);
1486
wxASSERT(stride == cairo_image_surface_get_stride(oldRef->m_surface));
1487
memcpy(dst, src, stride * h);
1488
cairo_surface_mark_dirty(surface);
1491
if (oldRef->m_pixmap != NULL)
1493
newRef->m_pixmap = gdk_pixmap_new(
1494
oldRef->m_pixmap, oldRef->m_width, oldRef->m_height,
1495
// use pixmap depth, m_bpp may not match
1496
gdk_drawable_get_depth(oldRef->m_pixmap));
1497
wxGtkObject<GdkGC> gc(gdk_gc_new(newRef->m_pixmap));
1499
newRef->m_pixmap, gc, oldRef->m_pixmap, 0, 0, 0, 0, -1, -1);
1501
if (oldRef->m_pixbuf != NULL)
1503
newRef->m_pixbuf = gdk_pixbuf_copy(oldRef->m_pixbuf);
1506
if (oldRef->m_mask != NULL)
1508
newRef->m_mask = new wxMask(*oldRef->m_mask);
1514
/* static */ void wxBitmap::InitStandardHandlers()
1516
// TODO: Insert handler based on GdkPixbufs handler later