Adjust x,y parameters by pizza scroll offset in DoSetSize
[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/icon.h"
17 #include "wx/image.h"
18 #include "wx/colour.h"
19 #endif
20
21 #include "wx/rawbmp.h"
22
23 #include "wx/gtk/private/object.h"
24 #include "wx/gtk/private.h"
25
26 #include <gtk/gtk.h>
27
28 extern GtkWidget *wxGetRootWindow();
29
30 static 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
50 static 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
72 //-----------------------------------------------------------------------------
73 // wxMask
74 //-----------------------------------------------------------------------------
75
76 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxMaskBase)
77
78 wxMask::wxMask()
79 {
80 m_bitmap = NULL;
81 }
82
83 wxMask::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
100 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
101 {
102 m_bitmap = NULL;
103 InitFromColour(bitmap, colour);
104 }
105
106 #if wxUSE_PALETTE
107 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
108 {
109 m_bitmap = NULL;
110 Create( bitmap, paletteIndex );
111 }
112 #endif // wxUSE_PALETTE
113
114 wxMask::wxMask( const wxBitmap& bitmap )
115 {
116 m_bitmap = NULL;
117 InitFromMonoBitmap(bitmap);
118 }
119
120 wxMask::wxMask(GdkPixmap* bitmap)
121 {
122 m_bitmap = bitmap;
123 }
124
125 wxMask::~wxMask()
126 {
127 if (m_bitmap)
128 g_object_unref (m_bitmap);
129 }
130
131 void wxMask::FreeData()
132 {
133 if (m_bitmap)
134 {
135 g_object_unref (m_bitmap);
136 m_bitmap = NULL;
137 }
138 }
139
140 bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
141 {
142 const int w = bitmap.GetWidth();
143 const int h = bitmap.GetHeight();
144
145 // create mask as XBM format bitmap
146
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];
150 // set bits are unmasked
151 memset(out, 0xff, out_size);
152 unsigned bit_index = 0;
153 if (bitmap.HasPixbuf())
154 {
155 const wxByte r_mask = colour.Red();
156 const wxByte g_mask = colour.Green();
157 const wxByte b_mask = colour.Blue();
158 GdkPixbuf* pixbuf = bitmap.GetPixbuf();
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 }
170 }
171 else
172 {
173 GdkImage* image = gdk_drawable_get_image(bitmap.GetPixmap(), 0, 0, w, h);
174 GdkColormap* colormap = gdk_image_get_colormap(image);
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
180 {
181 wxColor c(colour);
182 c.CalcPixel(colormap);
183 mask_pixel = c.GetPixel();
184 }
185 for (int y = 0; y < h; y++)
186 {
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;
191 }
192 g_object_unref(image);
193 }
194 m_bitmap = gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h);
195 delete[] out;
196 return true;
197 }
198
199 bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap)
200 {
201 if (!bitmap.IsOk()) return false;
202
203 wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
204
205 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
206
207 if (!m_bitmap) return false;
208
209 wxGtkObject<GdkGC> gc(gdk_gc_new( m_bitmap ));
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());
212
213 return true;
214 }
215
216 GdkPixmap* wxMask::GetBitmap() const
217 {
218 return m_bitmap;
219 }
220
221 //-----------------------------------------------------------------------------
222 // wxBitmapRefData
223 //-----------------------------------------------------------------------------
224
225 class wxBitmapRefData: public wxGDIRefData
226 {
227 public:
228 wxBitmapRefData(int width, int height, int depth);
229 virtual ~wxBitmapRefData();
230
231 virtual bool IsOk() const;
232
233 GdkPixmap *m_pixmap;
234 GdkPixbuf *m_pixbuf;
235 wxMask *m_mask;
236 int m_width;
237 int m_height;
238 int m_bpp;
239 bool m_alphaRequested;
240
241 private:
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);
247 };
248
249 wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
250 {
251 m_pixmap = NULL;
252 m_pixbuf = NULL;
253 m_mask = NULL;
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;
260 }
261
262 wxBitmapRefData::~wxBitmapRefData()
263 {
264 if (m_pixmap)
265 g_object_unref (m_pixmap);
266 if (m_pixbuf)
267 g_object_unref (m_pixbuf);
268 delete m_mask;
269 }
270
271 bool wxBitmapRefData::IsOk() const
272 {
273 return m_bpp != 0;
274 }
275
276 //-----------------------------------------------------------------------------
277 // wxBitmap
278 //-----------------------------------------------------------------------------
279
280 #define M_BMPDATA static_cast<wxBitmapRefData*>(m_refData)
281
282 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
283
284 wxBitmap::wxBitmap(const wxString &filename, wxBitmapType type)
285 {
286 LoadFile(filename, type);
287 }
288
289 wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
290 {
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));
295 }
296 }
297
298 wxBitmap::wxBitmap(const char* const* bits)
299 {
300 wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data"));
301
302 GdkBitmap* mask = NULL;
303 SetPixmap(gdk_pixmap_create_from_xpm_d(wxGetRootWindow()->window, &mask, NULL, const_cast<char**>(bits)));
304 if (!M_BMPDATA)
305 return;
306
307 if (M_BMPDATA->m_pixmap != NULL && mask != NULL)
308 {
309 M_BMPDATA->m_mask = new wxMask(mask);
310 }
311 }
312
313 wxBitmap::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
325 wxBitmap::~wxBitmap()
326 {
327 }
328
329 bool wxBitmap::Create( int width, int height, int depth )
330 {
331 UnRef();
332 wxCHECK_MSG(width >= 0 && height >= 0, false, "invalid bitmap size");
333 m_refData = new wxBitmapRefData(width, height, depth);
334 return true;
335 }
336
337 #if wxUSE_IMAGE
338
339 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
340 {
341 UnRef();
342
343 wxCHECK_MSG( image.IsOk(), false, wxT("invalid image") );
344
345 if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
346 return false;
347
348 if (depth == 32 || (depth == -1 && image.HasAlpha()))
349 return CreateFromImageAsPixbuf(image);
350
351 // otherwise create pixmap, if alpha is present it will be converted to mask
352 return CreateFromImageAsPixmap(image, depth);
353 }
354
355 bool wxBitmap::CreateFromImageAsPixmap(const wxImage& image, int depth)
356 {
357 const int w = image.GetWidth();
358 const int h = image.GetHeight();
359 if (depth == 1)
360 {
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];
366 // set bits are black
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;
380
381 if (!M_BMPDATA) // SetPixmap may have failed
382 return false;
383 }
384 else
385 {
386 SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, w, h, depth));
387 if (!M_BMPDATA)
388 return false;
389
390 wxGtkObject<GdkGC> gc(gdk_gc_new(M_BMPDATA->m_pixmap));
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);
395 }
396
397 const wxByte* alpha = image.GetAlpha();
398 if (alpha != NULL || image.HasMask())
399 {
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)
407 {
408 for (int y = 0; y < h; y++)
409 {
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;
414 }
415 }
416 else
417 {
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 }
430 SetMask(new wxMask(gdk_bitmap_create_from_data(M_BMPDATA->m_pixmap, (char*)out, w, h)));
431 delete[] out;
432 }
433 return IsOk();
434 }
435
436 bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
437 {
438 int width = image.GetWidth();
439 int height = image.GetHeight();
440
441 Create(width, height, 32);
442 GdkPixbuf* pixbuf = GetPixbuf();
443 if (!pixbuf)
444 return false;
445
446 // Copy the data:
447 const unsigned char* in = image.GetData();
448 unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
449 unsigned char *alpha = image.GetAlpha();
450
451 int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
452
453 for (int y = 0; y < height; y++, out += rowpad)
454 {
455 for (int x = 0; x < width; x++, out += 4, in += 3)
456 {
457 out[0] = in[0];
458 out[1] = in[1];
459 out[2] = in[2];
460 if (alpha)
461 out[3] = *alpha++;
462 }
463 }
464
465 return true;
466 }
467
468 wxImage wxBitmap::ConvertToImage() const
469 {
470 wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
471
472 const int w = GetWidth();
473 const int h = GetHeight();
474 wxImage image(w, h, false);
475 unsigned char *data = image.GetData();
476
477 wxCHECK_MSG(data != NULL, wxNullImage, wxT("couldn't create image") );
478
479 // prefer pixbuf if available, it will preserve alpha and should be quicker
480 if (HasPixbuf())
481 {
482 GdkPixbuf *pixbuf = GetPixbuf();
483 unsigned char* alpha = NULL;
484 if (gdk_pixbuf_get_has_alpha(pixbuf))
485 {
486 image.SetAlpha();
487 alpha = image.GetAlpha();
488 }
489 const unsigned char* in = gdk_pixbuf_get_pixels(pixbuf);
490 unsigned char *out = data;
491 const int inc = 3 + int(alpha != NULL);
492 const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
493
494 for (int y = 0; y < h; y++, in += rowpad)
495 {
496 for (int x = 0; x < w; x++, in += inc, out += 3)
497 {
498 out[0] = in[0];
499 out[1] = in[1];
500 out[2] = in[2];
501 if (alpha != NULL)
502 *alpha++ = in[3];
503 }
504 }
505 }
506 else
507 {
508 GdkPixmap* pixmap = GetPixmap();
509 GdkPixmap* pixmap_invert = NULL;
510 if (GetDepth() == 1)
511 {
512 // mono bitmaps are inverted, i.e. 0 is white
513 pixmap_invert = gdk_pixmap_new(pixmap, w, h, 1);
514 wxGtkObject<GdkGC> gc(gdk_gc_new(pixmap_invert));
515 gdk_gc_set_function(gc, GDK_COPY_INVERT);
516 gdk_draw_drawable(pixmap_invert, gc, pixmap, 0, 0, 0, 0, w, h);
517 pixmap = pixmap_invert;
518 }
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);
522
523 gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
524
525 g_object_unref(pixbuf);
526 if (pixmap_invert != NULL)
527 g_object_unref(pixmap_invert);
528 }
529 // convert mask, unless there is already alpha
530 if (GetMask() && !image.HasAlpha())
531 {
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
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;
540
541 image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
542 GdkImage* image_mask = gdk_drawable_get_image(GetMask()->GetBitmap(), 0, 0, w, h);
543
544 for (int y = 0; y < h; y++)
545 {
546 for (int x = 0; x < w; x++, data += 3)
547 {
548 if (gdk_image_get_pixel(image_mask, x, y) == 0)
549 {
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 {
556 // we have to fudge the colour a bit to prevent
557 // this pixel from appearing transparent
558 data[2] = MASK_BLUE_REPLACEMENT;
559 }
560 }
561 }
562 g_object_unref(image_mask);
563 }
564
565 return image;
566 }
567
568 #endif // wxUSE_IMAGE
569
570 int wxBitmap::GetHeight() const
571 {
572 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
573
574 return M_BMPDATA->m_height;
575 }
576
577 int wxBitmap::GetWidth() const
578 {
579 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
580
581 return M_BMPDATA->m_width;
582 }
583
584 int wxBitmap::GetDepth() const
585 {
586 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
587
588 return M_BMPDATA->m_bpp;
589 }
590
591 wxMask *wxBitmap::GetMask() const
592 {
593 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
594
595 return M_BMPDATA->m_mask;
596 }
597
598 void wxBitmap::SetMask( wxMask *mask )
599 {
600 wxCHECK_RET( IsOk(), wxT("invalid bitmap") );
601
602 AllocExclusive();
603 delete M_BMPDATA->m_mask;
604 M_BMPDATA->m_mask = mask;
605 }
606
607 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
608 {
609 *this = icon;
610 return IsOk();
611 }
612
613 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
614 {
615 wxBitmap ret;
616
617 wxCHECK_MSG(IsOk(), ret, wxT("invalid bitmap"));
618
619 const int w = rect.width;
620 const int h = rect.height;
621 const wxBitmapRefData* bmpData = M_BMPDATA;
622
623 wxCHECK_MSG(rect.x >= 0 && rect.y >= 0 &&
624 rect.x + w <= bmpData->m_width &&
625 rect.y + h <= bmpData->m_height,
626 ret, wxT("invalid bitmap region"));
627
628 wxBitmapRefData * const newRef = new wxBitmapRefData(w, h, bmpData->m_bpp);
629 ret.m_refData = newRef;
630
631 if (bmpData->m_pixbuf)
632 {
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);
637 }
638 if (bmpData->m_pixmap)
639 {
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);
645 }
646 GdkPixmap* mask = NULL;
647 if (bmpData->m_mask)
648 mask = bmpData->m_mask->GetBitmap();
649 if (mask)
650 {
651 GdkPixmap* sub_mask = gdk_pixmap_new(mask, w, h, 1);
652 newRef->m_mask = new wxMask(sub_mask);
653 GdkGC* gc = gdk_gc_new(sub_mask);
654 gdk_draw_drawable(
655 sub_mask, gc, mask, rect.x, rect.y, 0, 0, w, h);
656 g_object_unref(gc);
657 }
658
659 return ret;
660 }
661
662 bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
663 {
664 wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
665
666 #if wxUSE_IMAGE
667 wxImage image = ConvertToImage();
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 &&
681 gdk_pixbuf_save(GetPixbuf(), wxGTK_CONV_FN(name), type_name, NULL, NULL);
682 }
683
684 bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
685 {
686 #if wxUSE_IMAGE
687 wxImage image;
688 if (image.LoadFile(name, type) && image.IsOk())
689 *this = wxBitmap(image);
690 else
691 #endif
692 {
693 wxUnusedVar(type); // The type is detected automatically by GDK.
694
695 *this = wxBitmap(gdk_pixbuf_new_from_file(wxGTK_CONV_FN(name), NULL));
696 }
697
698 return IsOk();
699 }
700
701 #if wxUSE_PALETTE
702 wxPalette *wxBitmap::GetPalette() const
703 {
704 return NULL;
705 }
706
707 void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
708 {
709 // TODO
710 }
711 #endif // wxUSE_PALETTE
712
713 void wxBitmap::SetHeight( int height )
714 {
715 AllocExclusive();
716 M_BMPDATA->m_height = height;
717 }
718
719 void wxBitmap::SetWidth( int width )
720 {
721 AllocExclusive();
722 M_BMPDATA->m_width = width;
723 }
724
725 void wxBitmap::SetDepth( int depth )
726 {
727 AllocExclusive();
728 M_BMPDATA->m_bpp = depth;
729 }
730
731 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
732 {
733 UnRef();
734
735 if (!pixmap)
736 return;
737
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);
744 }
745
746 GdkPixmap *wxBitmap::GetPixmap() const
747 {
748 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
749
750 wxBitmapRefData* bmpData = M_BMPDATA;
751 if (bmpData->m_pixmap)
752 return bmpData->m_pixmap;
753
754 if (bmpData->m_pixbuf)
755 {
756 GdkPixmap* pixmap = NULL;
757 GdkPixmap** mask_pixmap = NULL;
758 if (gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf))
759 {
760 // make new mask from alpha
761 mask_pixmap = &pixmap;
762 }
763 gdk_pixbuf_render_pixmap_and_mask(
764 bmpData->m_pixbuf, &bmpData->m_pixmap, mask_pixmap, 128);
765 if (pixmap)
766 {
767 delete bmpData->m_mask;
768 bmpData->m_mask = new wxMask(pixmap);
769 }
770 }
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;
777 }
778
779 bool wxBitmap::HasPixmap() const
780 {
781 wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
782
783 return M_BMPDATA->m_pixmap != NULL;
784 }
785
786 GdkPixbuf *wxBitmap::GetPixbuf() const
787 {
788 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
789
790 wxBitmapRefData* bmpData = M_BMPDATA;
791 if (bmpData->m_pixbuf)
792 return bmpData->m_pixbuf;
793
794 const int w = bmpData->m_width;
795 const int h = bmpData->m_height;
796 GdkPixmap* mask = NULL;
797 if (bmpData->m_mask)
798 mask = bmpData->m_mask->GetBitmap();
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;
806 }
807
808 bool wxBitmap::HasPixbuf() const
809 {
810 wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
811
812 return M_BMPDATA->m_pixbuf != NULL;
813 }
814
815 void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
816 {
817 if (keep == Pixmap && HasPixbuf())
818 {
819 g_object_unref (M_BMPDATA->m_pixbuf);
820 M_BMPDATA->m_pixbuf = NULL;
821 }
822 if (keep == Pixbuf && HasPixmap())
823 {
824 g_object_unref (M_BMPDATA->m_pixmap);
825 M_BMPDATA->m_pixmap = NULL;
826 }
827 }
828
829 #ifdef wxHAS_RAW_BITMAP
830 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
831 {
832 void* bits = NULL;
833 GdkPixbuf *pixbuf = GetPixbuf();
834 const bool hasAlpha = HasAlpha();
835
836 // allow access if bpp is valid and matches existence of alpha
837 if ( pixbuf && ((bpp == 24 && !hasAlpha) || (bpp == 32 && hasAlpha)) )
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;
845 }
846
847 void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
848 {
849 }
850 #endif // wxHAS_RAW_BITMAP
851
852 bool wxBitmap::HasAlpha() const
853 {
854 const wxBitmapRefData* bmpData = M_BMPDATA;
855 return bmpData && (bmpData->m_alphaRequested ||
856 (bmpData->m_pixbuf && gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf)));
857 }
858
859 wxGDIRefData* wxBitmap::CreateGDIRefData() const
860 {
861 return new wxBitmapRefData(0, 0, 0);
862 }
863
864 wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
865 {
866 const wxBitmapRefData* oldRef = static_cast<const wxBitmapRefData*>(data);
867 wxBitmapRefData * const newRef = new wxBitmapRefData(oldRef->m_width,
868 oldRef->m_height,
869 oldRef->m_bpp);
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));
876 wxGtkObject<GdkGC> gc(gdk_gc_new(newRef->m_pixmap));
877 gdk_draw_drawable(
878 newRef->m_pixmap, gc, oldRef->m_pixmap, 0, 0, 0, 0, -1, -1);
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 {
886 newRef->m_mask = new wxMask(*oldRef->m_mask);
887 }
888
889 return newRef;
890 }
891
892 /* static */ void wxBitmap::InitStandardHandlers()
893 {
894 // TODO: Insert handler based on GdkPixbufs handler later
895 }