]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/bitmap.cpp
Remove unnecessary base class OnPaint() call from wxGenericColourDialog.
[wxWidgets.git] / src / gtk / bitmap.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
0b04c4e0 2// Name: src/gtk/bitmap.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
6f65e337 5// RCS-ID: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
559a723c
WS
13#include "wx/bitmap.h"
14
93763ad5 15#ifndef WX_PRECOMP
923d28da 16 #include "wx/icon.h"
155ecd4c 17 #include "wx/image.h"
5ff14574 18 #include "wx/colour.h"
93763ad5 19#endif
22bd9387 20
ce7c8a97 21#include "wx/rawbmp.h"
9e691f46 22
f3d74739 23#include "wx/gtk/private/object.h"
c282e47d 24#include "wx/gtk/private.h"
f3d74739 25
d76fe38b 26#include <gtk/gtk.h>
13111b2a 27
c2fa61e8 28extern GtkWidget *wxGetRootWindow();
c801d85f 29
06497cba
PC
30static void PixmapToPixbuf(GdkPixmap* pixmap, GdkPixbuf* pixbuf, int w, int h)
31{
32 gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
33 if (gdk_drawable_get_depth(pixmap) == 1)
34 {
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)
41 {
42 // pixels are either (0,0,0) or (0xff,0xff,0xff)
43 p[0] = ~p[0];
44 p[1] = ~p[1];
45 p[2] = ~p[2];
46 }
47 }
48}
49
50static void MaskToAlpha(GdkPixmap* mask, GdkPixbuf* pixbuf, int w, int h)
51{
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)
59 {
60 for (int x = w; x; x--, p += 4, mask_data += 3)
61 {
62 *p = 255;
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)
66 *p = 0;
67 }
68 }
69 g_object_unref(mask_pixbuf);
70}
71
c801d85f
KB
72//-----------------------------------------------------------------------------
73// wxMask
74//-----------------------------------------------------------------------------
75
60a3d1c6 76IMPLEMENT_DYNAMIC_CLASS(wxMask, wxMaskBase)
c801d85f 77
8bbe427f 78wxMask::wxMask()
c801d85f 79{
d3b9f782 80 m_bitmap = NULL;
ff7b1510 81}
c801d85f 82
27297c82
VZ
83wxMask::wxMask(const wxMask& mask)
84{
85 if ( !mask.m_bitmap )
86 {
87 m_bitmap = NULL;
88 return;
89 }
90
91 // create a copy of an existing mask
92 gint w, h;
93 gdk_drawable_get_size(mask.m_bitmap, &w, &h);
94 m_bitmap = gdk_pixmap_new(mask.m_bitmap, w, h, 1);
95
96 wxGtkObject<GdkGC> gc(gdk_gc_new(m_bitmap));
97 gdk_draw_drawable(m_bitmap, gc, mask.m_bitmap, 0, 0, 0, 0, -1, -1);
98}
99
91b8de8d 100wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
c801d85f 101{
d3b9f782 102 m_bitmap = NULL;
60a3d1c6 103 InitFromColour(bitmap, colour);
ff7b1510 104}
c801d85f 105
0b04c4e0 106#if wxUSE_PALETTE
91b8de8d 107wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
c801d85f 108{
d3b9f782 109 m_bitmap = NULL;
91b8de8d 110 Create( bitmap, paletteIndex );
ff7b1510 111}
0b04c4e0 112#endif // wxUSE_PALETTE
c801d85f 113
91b8de8d 114wxMask::wxMask( const wxBitmap& bitmap )
c801d85f 115{
d3b9f782 116 m_bitmap = NULL;
60a3d1c6 117 InitFromMonoBitmap(bitmap);
ff7b1510 118}
c801d85f 119
2d13e22f
PC
120wxMask::wxMask(GdkPixmap* bitmap)
121{
122 m_bitmap = bitmap;
123}
124
8bbe427f 125wxMask::~wxMask()
c801d85f 126{
13111b2a 127 if (m_bitmap)
3fe39b0c 128 g_object_unref (m_bitmap);
ff7b1510 129}
c801d85f 130
60a3d1c6 131void wxMask::FreeData()
91b8de8d
RR
132{
133 if (m_bitmap)
284b4c88 134 {
3fe39b0c 135 g_object_unref (m_bitmap);
d3b9f782 136 m_bitmap = NULL;
91b8de8d 137 }
60a3d1c6 138}
13111b2a 139
60a3d1c6
PC
140bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
141{
13785a4b
PC
142 const int w = bitmap.GetWidth();
143 const int h = bitmap.GetHeight();
13111b2a 144
5ac1d44a 145 // create mask as XBM format bitmap
13111b2a 146
5ac1d44a
PC
147 // one bit per pixel, each row starts on a byte boundary
148 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
149 wxByte* out = new wxByte[out_size];
d0e79755 150 // set bits are unmasked
5ac1d44a
PC
151 memset(out, 0xff, out_size);
152 unsigned bit_index = 0;
13785a4b 153 if (bitmap.HasPixbuf())
1fb4de31 154 {
5ac1d44a
PC
155 const wxByte r_mask = colour.Red();
156 const wxByte g_mask = colour.Green();
157 const wxByte b_mask = colour.Blue();
13785a4b 158 GdkPixbuf* pixbuf = bitmap.GetPixbuf();
5ac1d44a
PC
159 const wxByte* in = gdk_pixbuf_get_pixels(pixbuf);
160 const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
161 const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
162 for (int y = 0; y < h; y++, in += rowpadding)
163 {
164 for (int x = 0; x < w; x++, in += inc, bit_index++)
165 if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
166 out[bit_index >> 3] ^= 1 << (bit_index & 7);
167 // move index to next byte boundary
168 bit_index = (bit_index + 7) & ~7u;
169 }
2eefae6e 170 }
13785a4b 171 else
1fb4de31 172 {
5ac1d44a 173 GdkImage* image = gdk_drawable_get_image(bitmap.GetPixmap(), 0, 0, w, h);
13785a4b 174 GdkColormap* colormap = gdk_image_get_colormap(image);
a7cfe08a
PC
175 guint32 mask_pixel;
176 if (colormap == NULL)
177 // mono bitmap, white is pixel value 0
178 mask_pixel = guint32(colour.Red() != 255 || colour.Green() != 255 || colour.Blue() != 255);
179 else
13785a4b
PC
180 {
181 wxColor c(colour);
182 c.CalcPixel(colormap);
183 mask_pixel = c.GetPixel();
184 }
5ac1d44a 185 for (int y = 0; y < h; y++)
1fb4de31 186 {
5ac1d44a
PC
187 for (int x = 0; x < w; x++, bit_index++)
188 if (gdk_image_get_pixel(image, x, y) == mask_pixel)
189 out[bit_index >> 3] ^= 1 << (bit_index & 7);
190 bit_index = (bit_index + 7) & ~7u;
f9ee644e 191 }
13785a4b 192 g_object_unref(image);
5ac1d44a
PC
193 }
194 m_bitmap = gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h);
195 delete[] out;
902725ee 196 return true;
91b8de8d
RR
197}
198
60a3d1c6 199bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap)
91b8de8d 200{
3d37a968 201 if (!bitmap.IsOk()) return false;
284b4c88 202
b85229d1 203 wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
284b4c88 204
c2fa61e8 205 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
284b4c88 206
902725ee 207 if (!m_bitmap) return false;
284b4c88 208
f3d74739 209 wxGtkObject<GdkGC> gc(gdk_gc_new( m_bitmap ));
9be3f755
PC
210 gdk_gc_set_function(gc, GDK_COPY_INVERT);
211 gdk_draw_drawable(m_bitmap, gc, bitmap.GetPixmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight());
284b4c88 212
902725ee 213 return true;
91b8de8d
RR
214}
215
29e461a2 216GdkPixmap* wxMask::GetBitmap() const
c801d85f 217{
fd0eed64 218 return m_bitmap;
ff7b1510 219}
8bbe427f 220
c801d85f 221//-----------------------------------------------------------------------------
732d8c74 222// wxBitmapRefData
c801d85f
KB
223//-----------------------------------------------------------------------------
224
8f884a0d 225class wxBitmapRefData: public wxGDIRefData
c801d85f 226{
fd0eed64 227public:
06497cba 228 wxBitmapRefData(int width, int height, int depth);
d3c7fc99 229 virtual ~wxBitmapRefData();
f2593d0d 230
06497cba 231 virtual bool IsOk() const;
8f884a0d 232
f2593d0d 233 GdkPixmap *m_pixmap;
feac7937 234 GdkPixbuf *m_pixbuf;
f2593d0d
RR
235 wxMask *m_mask;
236 int m_width;
237 int m_height;
238 int m_bpp;
06497cba 239 bool m_alphaRequested;
fc684792
VZ
240
241private:
242 // We don't provide a copy ctor as copying m_pixmap and m_pixbuf properly
243 // is expensive and we don't want to do it implicitly (and possibly
244 // accidentally). wxBitmap::CloneGDIRefData() which does need to do it does
245 // it explicitly itself.
246 wxDECLARE_NO_COPY_CLASS(wxBitmapRefData);
c801d85f
KB
247};
248
06497cba 249wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
c801d85f 250{
d3b9f782
VZ
251 m_pixmap = NULL;
252 m_pixbuf = NULL;
253 m_mask = NULL;
06497cba
PC
254 m_width = width;
255 m_height = height;
256 m_bpp = depth;
257 if (m_bpp < 0)
258 m_bpp = gdk_drawable_get_depth(wxGetRootWindow()->window);
259 m_alphaRequested = depth == 32;
ff7b1510 260}
c801d85f 261
8bbe427f 262wxBitmapRefData::~wxBitmapRefData()
c801d85f 263{
3ebcd89d 264 if (m_pixmap)
3fe39b0c 265 g_object_unref (m_pixmap);
feac7937 266 if (m_pixbuf)
3fe39b0c 267 g_object_unref (m_pixbuf);
3ebcd89d 268 delete m_mask;
ff7b1510 269}
c801d85f 270
06497cba
PC
271bool wxBitmapRefData::IsOk() const
272{
273 return m_bpp != 0;
274}
732d8c74
FM
275
276//-----------------------------------------------------------------------------
277// wxBitmap
c801d85f
KB
278//-----------------------------------------------------------------------------
279
5c33522f 280#define M_BMPDATA static_cast<wxBitmapRefData*>(m_refData)
c801d85f
KB
281
282IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
283
23656673
PC
284wxBitmap::wxBitmap(const wxString &filename, wxBitmapType type)
285{
286 LoadFile(filename, type);
287}
288
289wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
c801d85f 290{
23656673
PC
291 wxASSERT(depth == 1);
292 if (width > 0 && height > 0 && depth == 1)
293 {
294 SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, bits, width, height));
23656673 295 }
ff7b1510 296}
8bbe427f 297
452418c4
PC
298wxBitmap::wxBitmap(const char* const* bits)
299{
300 wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data"));
301
302 GdkBitmap* mask = NULL;
5c33522f 303 SetPixmap(gdk_pixmap_create_from_xpm_d(wxGetRootWindow()->window, &mask, NULL, const_cast<char**>(bits)));
3d37a968
FM
304 if (!M_BMPDATA)
305 return;
452418c4
PC
306
307 if (M_BMPDATA->m_pixmap != NULL && mask != NULL)
308 {
2d13e22f 309 M_BMPDATA->m_mask = new wxMask(mask);
452418c4
PC
310 }
311}
312
54195d23
PC
313wxBitmap::wxBitmap(GdkPixbuf* pixbuf)
314{
315 if (pixbuf)
316 {
317 wxBitmapRefData* bmpData = new wxBitmapRefData(
318 gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf),
319 gdk_pixbuf_get_n_channels(pixbuf) * 8);
320 m_refData = bmpData;
321 bmpData->m_pixbuf = pixbuf;
322 }
323}
324
23656673 325wxBitmap::~wxBitmap()
c801d85f 326{
c826213d
RR
327}
328
329bool wxBitmap::Create( int width, int height, int depth )
330{
331 UnRef();
06497cba
PC
332 wxCHECK_MSG(width >= 0 && height >= 0, false, "invalid bitmap size");
333 m_refData = new wxBitmapRefData(width, height, depth);
334 return true;
ff7b1510 335}
b5f01ae0 336
c0521644
VZ
337#if wxUSE_IMAGE
338
feac7937 339bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
b5f01ae0 340{
a11672a4
RR
341 UnRef();
342
3d37a968 343 wxCHECK_MSG( image.IsOk(), false, wxT("invalid image") );
b5f01ae0 344
feac7937
VS
345 if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
346 return false;
902725ee 347
e503ef07 348 if (depth == 32 || (depth == -1 && image.HasAlpha()))
5588ce92
PC
349 return CreateFromImageAsPixbuf(image);
350
70029506 351 // otherwise create pixmap, if alpha is present it will be converted to mask
5ac1d44a 352 return CreateFromImageAsPixmap(image, depth);
feac7937 353}
3ebcd89d 354
5ac1d44a 355bool wxBitmap::CreateFromImageAsPixmap(const wxImage& image, int depth)
feac7937 356{
5ac1d44a
PC
357 const int w = image.GetWidth();
358 const int h = image.GetHeight();
359 if (depth == 1)
feac7937 360 {
5ac1d44a
PC
361 // create XBM format bitmap
362
363 // one bit per pixel, each row starts on a byte boundary
364 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
365 wxByte* out = new wxByte[out_size];
d0e79755 366 // set bits are black
5ac1d44a
PC
367 memset(out, 0xff, out_size);
368 const wxByte* in = image.GetData();
369 unsigned bit_index = 0;
370 for (int y = 0; y < h; y++)
371 {
372 for (int x = 0; x < w; x++, in += 3, bit_index++)
373 if (in[0] == 255 && in[1] == 255 && in[2] == 255)
374 out[bit_index >> 3] ^= 1 << (bit_index & 7);
375 // move index to next byte boundary
376 bit_index = (bit_index + 7) & ~7u;
377 }
378 SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h));
379 delete[] out;
3d37a968
FM
380
381 if (!M_BMPDATA) // SetPixmap may have failed
382 return false;
5ac1d44a
PC
383 }
384 else
385 {
386 SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, w, h, depth));
3d37a968
FM
387 if (!M_BMPDATA)
388 return false;
389
f3d74739 390 wxGtkObject<GdkGC> gc(gdk_gc_new(M_BMPDATA->m_pixmap));
5ac1d44a
PC
391 gdk_draw_rgb_image(
392 M_BMPDATA->m_pixmap, gc,
393 0, 0, w, h,
394 GDK_RGB_DITHER_NONE, image.GetData(), w * 3);
feac7937 395 }
b5f01ae0 396
5ac1d44a
PC
397 const wxByte* alpha = image.GetAlpha();
398 if (alpha != NULL || image.HasMask())
feac7937 399 {
5ac1d44a
PC
400 // create mask as XBM format bitmap
401
402 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
403 wxByte* out = new wxByte[out_size];
404 memset(out, 0xff, out_size);
405 unsigned bit_index = 0;
406 if (alpha != NULL)
b5f01ae0 407 {
5ac1d44a 408 for (int y = 0; y < h; y++)
b5f01ae0 409 {
5ac1d44a
PC
410 for (int x = 0; x < w; x++, bit_index++)
411 if (*alpha++ < wxIMAGE_ALPHA_THRESHOLD)
412 out[bit_index >> 3] ^= 1 << (bit_index & 7);
413 bit_index = (bit_index + 7) & ~7u;
feac7937 414 }
5ac1d44a
PC
415 }
416 else
b5f01ae0 417 {
5ac1d44a
PC
418 const wxByte r_mask = image.GetMaskRed();
419 const wxByte g_mask = image.GetMaskGreen();
420 const wxByte b_mask = image.GetMaskBlue();
421 const wxByte* in = image.GetData();
422 for (int y = 0; y < h; y++)
423 {
424 for (int x = 0; x < w; x++, in += 3, bit_index++)
425 if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
426 out[bit_index >> 3] ^= 1 << (bit_index & 7);
427 bit_index = (bit_index + 7) & ~7u;
428 }
429 }
2d13e22f 430 SetMask(new wxMask(gdk_bitmap_create_from_data(M_BMPDATA->m_pixmap, (char*)out, w, h)));
5ac1d44a
PC
431 delete[] out;
432 }
3d37a968 433 return IsOk();
b5f01ae0
VS
434}
435
feac7937 436bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
b5f01ae0 437{
feac7937
VS
438 int width = image.GetWidth();
439 int height = image.GetHeight();
2eefae6e 440
23656673 441 Create(width, height, 32);
06497cba 442 GdkPixbuf* pixbuf = GetPixbuf();
feac7937
VS
443 if (!pixbuf)
444 return false;
c2fa61e8 445
feac7937 446 // Copy the data:
23656673 447 const unsigned char* in = image.GetData();
feac7937
VS
448 unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
449 unsigned char *alpha = image.GetAlpha();
902725ee 450
23656673 451 int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
b5f01ae0 452
23656673 453 for (int y = 0; y < height; y++, out += rowpad)
b5f01ae0 454 {
e503ef07 455 for (int x = 0; x < width; x++, out += 4, in += 3)
feac7937
VS
456 {
457 out[0] = in[0];
458 out[1] = in[1];
459 out[2] = in[2];
e503ef07
PC
460 if (alpha)
461 out[3] = *alpha++;
feac7937 462 }
b5f01ae0 463 }
902725ee 464
feac7937
VS
465 return true;
466}
b5f01ae0 467
feac7937
VS
468wxImage wxBitmap::ConvertToImage() const
469{
3d37a968 470 wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
902725ee 471
afbfbfdf
PC
472 const int w = GetWidth();
473 const int h = GetHeight();
23656673 474 wxImage image(w, h, false);
feac7937 475 unsigned char *data = image.GetData();
2eefae6e 476
5588ce92 477 wxCHECK_MSG(data != NULL, wxNullImage, wxT("couldn't create image") );
b5f01ae0 478
70029506 479 // prefer pixbuf if available, it will preserve alpha and should be quicker
feac7937 480 if (HasPixbuf())
b5f01ae0 481 {
feac7937 482 GdkPixbuf *pixbuf = GetPixbuf();
70029506
PC
483 unsigned char* alpha = NULL;
484 if (gdk_pixbuf_get_has_alpha(pixbuf))
485 {
486 image.SetAlpha();
487 alpha = image.GetAlpha();
488 }
23656673 489 const unsigned char* in = gdk_pixbuf_get_pixels(pixbuf);
feac7937 490 unsigned char *out = data;
70029506 491 const int inc = 3 + int(alpha != NULL);
23656673 492 const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
b5f01ae0 493
23656673 494 for (int y = 0; y < h; y++, in += rowpad)
feac7937 495 {
70029506 496 for (int x = 0; x < w; x++, in += inc, out += 3)
feac7937
VS
497 {
498 out[0] = in[0];
499 out[1] = in[1];
500 out[2] = in[2];
70029506
PC
501 if (alpha != NULL)
502 *alpha++ = in[3];
feac7937
VS
503 }
504 }
b5f01ae0 505 }
feac7937 506 else
b5f01ae0 507 {
afbfbfdf
PC
508 GdkPixmap* pixmap = GetPixmap();
509 GdkPixmap* pixmap_invert = NULL;
510 if (GetDepth() == 1)
b5f01ae0 511 {
d0e79755 512 // mono bitmaps are inverted, i.e. 0 is white
afbfbfdf 513 pixmap_invert = gdk_pixmap_new(pixmap, w, h, 1);
f3d74739 514 wxGtkObject<GdkGC> gc(gdk_gc_new(pixmap_invert));
afbfbfdf
PC
515 gdk_gc_set_function(gc, GDK_COPY_INVERT);
516 gdk_draw_drawable(pixmap_invert, gc, pixmap, 0, 0, 0, 0, w, h);
afbfbfdf 517 pixmap = pixmap_invert;
feac7937 518 }
afbfbfdf
PC
519 // create a pixbuf which shares data with the wxImage
520 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
521 data, GDK_COLORSPACE_RGB, false, 8, w, h, 3 * w, NULL, NULL);
feac7937 522
afbfbfdf 523 gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
feac7937 524
afbfbfdf
PC
525 g_object_unref(pixbuf);
526 if (pixmap_invert != NULL)
527 g_object_unref(pixmap_invert);
70029506
PC
528 }
529 // convert mask, unless there is already alpha
530 if (GetMask() && !image.HasAlpha())
531 {
23656673
PC
532 // we hard code the mask colour for now but we could also make an
533 // effort (and waste time) to choose a colour not present in the
534 // image already to avoid having to fudge the pixels below --
535 // whether it's worth to do it is unclear however
70029506
PC
536 const int MASK_RED = 1;
537 const int MASK_GREEN = 2;
538 const int MASK_BLUE = 3;
539 const int MASK_BLUE_REPLACEMENT = 2;
feac7937 540
70029506
PC
541 image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
542 GdkImage* image_mask = gdk_drawable_get_image(GetMask()->GetBitmap(), 0, 0, w, h);
feac7937 543
70029506
PC
544 for (int y = 0; y < h; y++)
545 {
546 for (int x = 0; x < w; x++, data += 3)
8ab696e0 547 {
70029506 548 if (gdk_image_get_pixel(image_mask, x, y) == 0)
8ab696e0 549 {
70029506
PC
550 data[0] = MASK_RED;
551 data[1] = MASK_GREEN;
552 data[2] = MASK_BLUE;
553 }
554 else if (data[0] == MASK_RED && data[1] == MASK_GREEN && data[2] == MASK_BLUE)
555 {
23656673
PC
556 // we have to fudge the colour a bit to prevent
557 // this pixel from appearing transparent
70029506 558 data[2] = MASK_BLUE_REPLACEMENT;
feac7937 559 }
feac7937 560 }
b5f01ae0 561 }
70029506 562 g_object_unref(image_mask);
feac7937 563 }
b5f01ae0
VS
564
565 return image;
566}
567
c0521644
VZ
568#endif // wxUSE_IMAGE
569
91b8de8d 570int wxBitmap::GetHeight() const
c801d85f 571{
3d37a968 572 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
e55ad60e 573
fd0eed64 574 return M_BMPDATA->m_height;
ff7b1510 575}
c801d85f 576
91b8de8d 577int wxBitmap::GetWidth() const
c801d85f 578{
3d37a968 579 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
8bbe427f 580
fd0eed64 581 return M_BMPDATA->m_width;
ff7b1510 582}
c801d85f 583
91b8de8d 584int wxBitmap::GetDepth() const
c801d85f 585{
3d37a968 586 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
8bbe427f 587
fd0eed64 588 return M_BMPDATA->m_bpp;
ff7b1510 589}
c801d85f 590
91b8de8d 591wxMask *wxBitmap::GetMask() const
c801d85f 592{
d3b9f782 593 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
8bbe427f 594
fd0eed64 595 return M_BMPDATA->m_mask;
ff7b1510 596}
c801d85f
KB
597
598void wxBitmap::SetMask( wxMask *mask )
599{
3d37a968 600 wxCHECK_RET( IsOk(), wxT("invalid bitmap") );
8bbe427f 601
e3e89a93 602 AllocExclusive();
23656673 603 delete M_BMPDATA->m_mask;
fd0eed64 604 M_BMPDATA->m_mask = mask;
ff7b1510 605}
c801d85f 606
db0aec83
VS
607bool wxBitmap::CopyFromIcon(const wxIcon& icon)
608{
609 *this = icon;
3d37a968 610 return IsOk();
db0aec83
VS
611}
612
17bec151
RR
613wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
614{
5588ce92
PC
615 wxBitmap ret;
616
3d37a968 617 wxCHECK_MSG(IsOk(), ret, wxT("invalid bitmap"));
06497cba
PC
618
619 const int w = rect.width;
620 const int h = rect.height;
621 const wxBitmapRefData* bmpData = M_BMPDATA;
622
23656673 623 wxCHECK_MSG(rect.x >= 0 && rect.y >= 0 &&
06497cba
PC
624 rect.x + w <= bmpData->m_width &&
625 rect.y + h <= bmpData->m_height,
23656673 626 ret, wxT("invalid bitmap region"));
13111b2a 627
fc684792 628 wxBitmapRefData * const newRef = new wxBitmapRefData(w, h, bmpData->m_bpp);
06497cba 629 ret.m_refData = newRef;
06497cba
PC
630
631 if (bmpData->m_pixbuf)
17bec151 632 {
06497cba
PC
633 GdkPixbuf* pixbuf =
634 gdk_pixbuf_new_subpixbuf(bmpData->m_pixbuf, rect.x, rect.y, w, h);
635 newRef->m_pixbuf = gdk_pixbuf_copy(pixbuf);
636 g_object_unref(pixbuf);
17bec151 637 }
06497cba 638 if (bmpData->m_pixmap)
17bec151 639 {
06497cba
PC
640 newRef->m_pixmap = gdk_pixmap_new(bmpData->m_pixmap, w, h, -1);
641 GdkGC* gc = gdk_gc_new(newRef->m_pixmap);
642 gdk_draw_drawable(
643 newRef->m_pixmap, gc, bmpData->m_pixmap, rect.x, rect.y, 0, 0, w, h);
644 g_object_unref(gc);
17bec151 645 }
2d13e22f
PC
646 GdkPixmap* mask = NULL;
647 if (bmpData->m_mask)
648 mask = bmpData->m_mask->GetBitmap();
649 if (mask)
17bec151 650 {
2d13e22f
PC
651 GdkPixmap* sub_mask = gdk_pixmap_new(mask, w, h, 1);
652 newRef->m_mask = new wxMask(sub_mask);
06497cba
PC
653 GdkGC* gc = gdk_gc_new(sub_mask);
654 gdk_draw_drawable(
2d13e22f 655 sub_mask, gc, mask, rect.x, rect.y, 0, 0, w, h);
06497cba 656 g_object_unref(gc);
17bec151 657 }
13111b2a 658
17bec151
RR
659 return ret;
660}
661
4611dd06 662bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
c801d85f 663{
3d37a968 664 wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
8bbe427f 665
c0521644 666#if wxUSE_IMAGE
5588ce92 667 wxImage image = ConvertToImage();
8362e67c
PC
668 if (image.IsOk() && image.SaveFile(name, type))
669 return true;
670#endif
671 const char* type_name = NULL;
672 switch (type)
673 {
674 case wxBITMAP_TYPE_BMP: type_name = "bmp"; break;
675 case wxBITMAP_TYPE_ICO: type_name = "ico"; break;
676 case wxBITMAP_TYPE_JPEG: type_name = "jpeg"; break;
677 case wxBITMAP_TYPE_PNG: type_name = "png"; break;
678 default: break;
679 }
680 return type_name &&
c282e47d 681 gdk_pixbuf_save(GetPixbuf(), wxGTK_CONV_FN(name), type_name, NULL, NULL);
ff7b1510 682}
c801d85f 683
4611dd06 684bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
c801d85f 685{
c0521644 686#if wxUSE_IMAGE
8362e67c
PC
687 wxImage image;
688 if (image.LoadFile(name, type) && image.IsOk())
689 *this = wxBitmap(image);
690 else
691#endif
fd0eed64 692 {
357f4c81
VZ
693 wxUnusedVar(type); // The type is detected automatically by GDK.
694
c282e47d 695 *this = wxBitmap(gdk_pixbuf_new_from_file(wxGTK_CONV_FN(name), NULL));
fd0eed64 696 }
8bbe427f 697
3d37a968 698 return IsOk();
ff7b1510 699}
8bbe427f 700
0b04c4e0 701#if wxUSE_PALETTE
91b8de8d 702wxPalette *wxBitmap::GetPalette() const
c801d85f 703{
b2bf3ac6 704 return NULL;
ff7b1510 705}
c801d85f 706
4611dd06
RR
707void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
708{
709 // TODO
710}
0b04c4e0 711#endif // wxUSE_PALETTE
4611dd06 712
4bc67cc5
RR
713void wxBitmap::SetHeight( int height )
714{
e3e89a93 715 AllocExclusive();
4bc67cc5
RR
716 M_BMPDATA->m_height = height;
717}
718
719void wxBitmap::SetWidth( int width )
720{
e3e89a93 721 AllocExclusive();
4bc67cc5
RR
722 M_BMPDATA->m_width = width;
723}
724
725void wxBitmap::SetDepth( int depth )
726{
e3e89a93 727 AllocExclusive();
4bc67cc5
RR
728 M_BMPDATA->m_bpp = depth;
729}
730
731void wxBitmap::SetPixmap( GdkPixmap *pixmap )
732{
06497cba
PC
733 UnRef();
734
3d37a968
FM
735 if (!pixmap)
736 return;
737
06497cba
PC
738 int w, h;
739 gdk_drawable_get_size(pixmap, &w, &h);
740 wxBitmapRefData* bmpData = new wxBitmapRefData(w, h, 0);
741 m_refData = bmpData;
742 bmpData->m_pixmap = pixmap;
743 bmpData->m_bpp = gdk_drawable_get_depth(pixmap);
4bc67cc5
RR
744}
745
91b8de8d 746GdkPixmap *wxBitmap::GetPixmap() const
c801d85f 747{
d3b9f782 748 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
8bbe427f 749
06497cba
PC
750 wxBitmapRefData* bmpData = M_BMPDATA;
751 if (bmpData->m_pixmap)
752 return bmpData->m_pixmap;
753
754 if (bmpData->m_pixbuf)
feac7937 755 {
2d13e22f 756 GdkPixmap* pixmap = NULL;
06497cba
PC
757 GdkPixmap** mask_pixmap = NULL;
758 if (gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf))
70029506
PC
759 {
760 // make new mask from alpha
2d13e22f 761 mask_pixmap = &pixmap;
70029506 762 }
06497cba
PC
763 gdk_pixbuf_render_pixmap_and_mask(
764 bmpData->m_pixbuf, &bmpData->m_pixmap, mask_pixmap, 128);
2d13e22f
PC
765 if (pixmap)
766 {
767 delete bmpData->m_mask;
768 bmpData->m_mask = new wxMask(pixmap);
769 }
feac7937 770 }
06497cba
PC
771 else
772 {
773 bmpData->m_pixmap = gdk_pixmap_new(wxGetRootWindow()->window,
774 bmpData->m_width, bmpData->m_height, bmpData->m_bpp == 1 ? 1 : -1);
775 }
776 return bmpData->m_pixmap;
ff7b1510 777}
8bbe427f 778
feac7937
VS
779bool wxBitmap::HasPixmap() const
780{
3d37a968 781 wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
feac7937
VS
782
783 return M_BMPDATA->m_pixmap != NULL;
784}
785
feac7937
VS
786GdkPixbuf *wxBitmap::GetPixbuf() const
787{
3d37a968 788 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
feac7937 789
06497cba
PC
790 wxBitmapRefData* bmpData = M_BMPDATA;
791 if (bmpData->m_pixbuf)
792 return bmpData->m_pixbuf;
6db34764 793
06497cba
PC
794 const int w = bmpData->m_width;
795 const int h = bmpData->m_height;
796 GdkPixmap* mask = NULL;
797 if (bmpData->m_mask)
2d13e22f 798 mask = bmpData->m_mask->GetBitmap();
06497cba
PC
799 const bool useAlpha = bmpData->m_alphaRequested || mask;
800 bmpData->m_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, useAlpha, 8, w, h);
801 if (bmpData->m_pixmap)
802 PixmapToPixbuf(bmpData->m_pixmap, bmpData->m_pixbuf, w, h);
803 if (mask)
804 MaskToAlpha(mask, bmpData->m_pixbuf, w, h);
805 return bmpData->m_pixbuf;
feac7937
VS
806}
807
808bool wxBitmap::HasPixbuf() const
809{
3d37a968 810 wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
feac7937
VS
811
812 return M_BMPDATA->m_pixbuf != NULL;
813}
814
feac7937
VS
815void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
816{
817 if (keep == Pixmap && HasPixbuf())
818 {
3fe39b0c 819 g_object_unref (M_BMPDATA->m_pixbuf);
feac7937
VS
820 M_BMPDATA->m_pixbuf = NULL;
821 }
822 if (keep == Pixbuf && HasPixmap())
823 {
3fe39b0c 824 g_object_unref (M_BMPDATA->m_pixmap);
feac7937
VS
825 M_BMPDATA->m_pixmap = NULL;
826 }
827}
828
ce7c8a97 829#ifdef wxHAS_RAW_BITMAP
284f2b59
RR
830void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
831{
70029506 832 void* bits = NULL;
284f2b59 833 GdkPixbuf *pixbuf = GetPixbuf();
70029506 834 const bool hasAlpha = HasAlpha();
3d37a968 835
70029506 836 // allow access if bpp is valid and matches existence of alpha
c74fc1e1 837 if ( pixbuf && ((bpp == 24 && !hasAlpha) || (bpp == 32 && hasAlpha)) )
70029506
PC
838 {
839 data.m_height = gdk_pixbuf_get_height( pixbuf );
840 data.m_width = gdk_pixbuf_get_width( pixbuf );
841 data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
842 bits = gdk_pixbuf_get_pixels(pixbuf);
843 }
844 return bits;
284f2b59
RR
845}
846
17a1ebd1 847void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
284f2b59
RR
848{
849}
ce7c8a97 850#endif // wxHAS_RAW_BITMAP
284f2b59 851
902725ee 852bool wxBitmap::HasAlpha() const
0ff2a74d 853{
06497cba
PC
854 const wxBitmapRefData* bmpData = M_BMPDATA;
855 return bmpData && (bmpData->m_alphaRequested ||
856 (bmpData->m_pixbuf && gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf)));
0ff2a74d
RR
857}
858
8f884a0d 859wxGDIRefData* wxBitmap::CreateGDIRefData() const
e3e89a93 860{
06497cba 861 return new wxBitmapRefData(0, 0, 0);
e3e89a93
PC
862}
863
8f884a0d 864wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
e3e89a93 865{
5c33522f 866 const wxBitmapRefData* oldRef = static_cast<const wxBitmapRefData*>(data);
fc684792
VZ
867 wxBitmapRefData * const newRef = new wxBitmapRefData(oldRef->m_width,
868 oldRef->m_height,
869 oldRef->m_bpp);
e3e89a93
PC
870 if (oldRef->m_pixmap != NULL)
871 {
872 newRef->m_pixmap = gdk_pixmap_new(
873 oldRef->m_pixmap, oldRef->m_width, oldRef->m_height,
874 // use pixmap depth, m_bpp may not match
875 gdk_drawable_get_depth(oldRef->m_pixmap));
f3d74739 876 wxGtkObject<GdkGC> gc(gdk_gc_new(newRef->m_pixmap));
e3e89a93
PC
877 gdk_draw_drawable(
878 newRef->m_pixmap, gc, oldRef->m_pixmap, 0, 0, 0, 0, -1, -1);
e3e89a93
PC
879 }
880 if (oldRef->m_pixbuf != NULL)
881 {
882 newRef->m_pixbuf = gdk_pixbuf_copy(oldRef->m_pixbuf);
883 }
884 if (oldRef->m_mask != NULL)
885 {
27297c82 886 newRef->m_mask = new wxMask(*oldRef->m_mask);
e3e89a93 887 }
e3e89a93
PC
888
889 return newRef;
890}
891
4b61c88d
RR
892/* static */ void wxBitmap::InitStandardHandlers()
893{
894 // TODO: Insert handler based on GdkPixbufs handler later
895}