Comment out suspicious 1-bit bitmap conversion
[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/app.h"
17 #include "wx/palette.h"
18 #include "wx/icon.h"
19 #include "wx/math.h"
20 #include "wx/image.h"
21 #endif
22
23 #include "wx/rawbmp.h"
24
25 #include <gtk/gtk.h>
26
27 //-----------------------------------------------------------------------------
28 // data
29 //-----------------------------------------------------------------------------
30
31 extern GtkWidget *wxGetRootWindow();
32
33 //-----------------------------------------------------------------------------
34 // wxMask
35 //-----------------------------------------------------------------------------
36
37 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
38
39 wxMask::wxMask()
40 {
41 m_bitmap = (GdkBitmap *) NULL;
42 }
43
44 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
45 {
46 m_bitmap = (GdkBitmap *) NULL;
47 Create( bitmap, colour );
48 }
49
50 #if wxUSE_PALETTE
51 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
52 {
53 m_bitmap = (GdkBitmap *) NULL;
54 Create( bitmap, paletteIndex );
55 }
56 #endif // wxUSE_PALETTE
57
58 wxMask::wxMask( const wxBitmap& bitmap )
59 {
60 m_bitmap = (GdkBitmap *) NULL;
61 Create( bitmap );
62 }
63
64 wxMask::~wxMask()
65 {
66 if (m_bitmap)
67 g_object_unref (m_bitmap);
68 }
69
70 bool wxMask::Create( const wxBitmap& bitmap,
71 const wxColour& colour )
72 {
73 if (m_bitmap)
74 {
75 g_object_unref (m_bitmap);
76 m_bitmap = (GdkBitmap*) NULL;
77 }
78
79 const int w = bitmap.GetWidth();
80 const int h = bitmap.GetHeight();
81
82 // create mask as XBM format bitmap
83
84 // one bit per pixel, each row starts on a byte boundary
85 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
86 wxByte* out = new wxByte[out_size];
87 // set bits are white
88 memset(out, 0xff, out_size);
89 unsigned bit_index = 0;
90 if (bitmap.HasPixbuf())
91 {
92 const wxByte r_mask = colour.Red();
93 const wxByte g_mask = colour.Green();
94 const wxByte b_mask = colour.Blue();
95 GdkPixbuf* pixbuf = bitmap.GetPixbuf();
96 const wxByte* in = gdk_pixbuf_get_pixels(pixbuf);
97 const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
98 const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
99 for (int y = 0; y < h; y++, in += rowpadding)
100 {
101 for (int x = 0; x < w; x++, in += inc, bit_index++)
102 if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
103 out[bit_index >> 3] ^= 1 << (bit_index & 7);
104 // move index to next byte boundary
105 bit_index = (bit_index + 7) & ~7u;
106 }
107 }
108 else
109 {
110 GdkImage* image = gdk_drawable_get_image(bitmap.GetPixmap(), 0, 0, w, h);
111 GdkColormap* colormap = gdk_image_get_colormap(image);
112 guint32 mask_pixel = 1;
113 if (colormap != NULL)
114 {
115 wxColor c(colour);
116 c.CalcPixel(colormap);
117 mask_pixel = c.GetPixel();
118 }
119 for (int y = 0; y < h; y++)
120 {
121 for (int x = 0; x < w; x++, bit_index++)
122 if (gdk_image_get_pixel(image, x, y) == mask_pixel)
123 out[bit_index >> 3] ^= 1 << (bit_index & 7);
124 bit_index = (bit_index + 7) & ~7u;
125 }
126 g_object_unref(image);
127 }
128 m_bitmap = gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h);
129 delete[] out;
130 return true;
131 }
132
133 #if wxUSE_PALETTE
134 bool wxMask::Create( const wxBitmap& bitmap, int paletteIndex )
135 {
136 unsigned char r,g,b;
137 wxPalette *pal = bitmap.GetPalette();
138
139 wxCHECK_MSG( pal, false, wxT("Cannot create mask from bitmap without palette") );
140
141 pal->GetRGB(paletteIndex, &r, &g, &b);
142
143 return Create(bitmap, wxColour(r, g, b));
144 }
145 #endif // wxUSE_PALETTE
146
147 bool wxMask::Create( const wxBitmap& bitmap )
148 {
149 if (m_bitmap)
150 {
151 g_object_unref (m_bitmap);
152 m_bitmap = (GdkBitmap*) NULL;
153 }
154
155 if (!bitmap.Ok()) return false;
156
157 wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
158
159 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
160
161 if (!m_bitmap) return false;
162
163 GdkGC *gc = gdk_gc_new( m_bitmap );
164 gdk_gc_set_function(gc, GDK_COPY_INVERT);
165 gdk_draw_drawable(m_bitmap, gc, bitmap.GetPixmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight());
166 g_object_unref (gc);
167
168 return true;
169 }
170
171 GdkBitmap *wxMask::GetBitmap() const
172 {
173 return m_bitmap;
174 }
175
176 //-----------------------------------------------------------------------------
177 // wxBitmap
178 //-----------------------------------------------------------------------------
179
180 class wxBitmapRefData: public wxObjectRefData
181 {
182 public:
183 wxBitmapRefData();
184 ~wxBitmapRefData();
185
186 GdkPixmap *m_pixmap;
187 GdkPixbuf *m_pixbuf;
188 wxMask *m_mask;
189 int m_width;
190 int m_height;
191 int m_bpp;
192 wxPalette *m_palette;
193 };
194
195 wxBitmapRefData::wxBitmapRefData()
196 {
197 m_pixmap = (GdkPixmap *) NULL;
198 m_pixbuf = (GdkPixbuf *) NULL;
199 m_mask = (wxMask *) NULL;
200 m_width = 0;
201 m_height = 0;
202 m_bpp = 0;
203 m_palette = (wxPalette *) NULL;
204 }
205
206 wxBitmapRefData::~wxBitmapRefData()
207 {
208 if (m_pixmap)
209 g_object_unref (m_pixmap);
210 if (m_pixbuf)
211 g_object_unref (m_pixbuf);
212 delete m_mask;
213 #if wxUSE_PALETTE
214 delete m_palette;
215 #endif // wxUSE_PALETTE
216 }
217
218 //-----------------------------------------------------------------------------
219
220 #define M_BMPDATA wx_static_cast(wxBitmapRefData*, m_refData)
221
222 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
223
224 wxBitmap::wxBitmap()
225 {
226 }
227
228 wxBitmap::wxBitmap( int width, int height, int depth )
229 {
230 Create( width, height, depth );
231 }
232
233 bool wxBitmap::Create( int width, int height, int depth )
234 {
235 UnRef();
236
237 if ( width <= 0 || height <= 0 )
238 {
239 return false;
240 }
241
242 if (depth == 32)
243 {
244 SetPixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height));
245 M_BMPDATA->m_bpp = 32;
246 }
247 else
248 {
249 if (depth != 1)
250 {
251 const GdkVisual* visual = wxTheApp->GetGdkVisual();
252 if (depth == -1)
253 depth = visual->depth;
254
255 wxCHECK_MSG(depth == visual->depth, false, wxT("invalid bitmap depth"));
256 }
257
258 SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, width, height, depth));
259 }
260
261 return Ok();
262 }
263
264 bool wxBitmap::CreateFromXpm( const char **bits )
265 {
266 UnRef();
267
268 wxCHECK_MSG( bits != NULL, false, wxT("invalid bitmap data") );
269
270 GdkBitmap *mask = (GdkBitmap*) NULL;
271 SetPixmap(gdk_pixmap_create_from_xpm_d(wxGetRootWindow()->window, &mask, NULL, (gchar**)bits));
272
273 wxCHECK_MSG( M_BMPDATA->m_pixmap, false, wxT("couldn't create pixmap") );
274
275 if (mask)
276 {
277 M_BMPDATA->m_mask = new wxMask;
278 M_BMPDATA->m_mask->m_bitmap = mask;
279 }
280
281 return true;
282 }
283
284 wxBitmap wxBitmap::Rescale( int clipx, int clipy, int clipwidth, int clipheight, int newx, int newy )
285 {
286 wxBitmap bmp;
287
288 wxCHECK_MSG(Ok(), bmp, wxT("invalid bitmap"));
289
290 if (newy==M_BMPDATA->m_width && newy==M_BMPDATA->m_height)
291 return *this;
292
293 int width = wxMax(newx, 1);
294 int height = wxMax(newy, 1);
295 width = wxMin(width, clipwidth);
296 height = wxMin(height, clipheight);
297
298 if (HasPixbuf())
299 {
300 bmp.SetDepth(GetDepth());
301 bmp.SetPixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB,
302 true, //gdk_pixbuf_get_has_alpha(GetPixbuf()),
303 8, width, height));
304 gdk_pixbuf_scale(GetPixbuf(), bmp.GetPixbuf(),
305 0, 0, width, height,
306 clipx, clipy,
307 (double)newx/GetWidth(), (double)newy/GetHeight(),
308 GDK_INTERP_BILINEAR);
309 }
310 else
311 {
312 GdkImage* img = gdk_drawable_get_image(GetPixmap(), 0, 0, GetWidth(), GetHeight());
313
314 wxCHECK_MSG(img, bmp, wxT("couldn't create image"));
315
316 GdkGC *gc = NULL;
317 GdkPixmap *dstpix = NULL;
318 char *dst = NULL;
319 long dstbyteperline = 0;
320
321 if (GetDepth() != 1)
322 {
323 GdkVisual *visual = gdk_drawable_get_visual( GetPixmap() );
324 if (visual == NULL)
325 visual = wxTheApp->GetGdkVisual();
326
327 bmp = wxBitmap(width, height, visual->depth);
328 dstpix = bmp.GetPixmap();
329 gc = gdk_gc_new( dstpix );
330 }
331 else
332 {
333 dstbyteperline = (width + 7) / 8;
334 dst = (char*) malloc(dstbyteperline*height);
335 }
336
337 // be careful to use the right scaling factor
338 float scx = (float)M_BMPDATA->m_width/(float)newx;
339 float scy = (float)M_BMPDATA->m_height/(float)newy;
340 // prepare accel-tables
341 int *tablex = (int *)calloc(width,sizeof(int));
342 int *tabley = (int *)calloc(height,sizeof(int));
343
344 // accel table filled with clipped values
345 for (int x = 0; x < width; x++)
346 tablex[x] = (int) (scx * (x+clipx));
347 for (int y = 0; y < height; y++)
348 tabley[y] = (int) (scy * (y+clipy));
349
350 // Main rescaling routine starts here
351 for (int h = 0; h < height; h++)
352 {
353 char outbyte = 0;
354 int old_x = -1;
355 guint32 old_pixval = 0;
356
357 for (int w = 0; w < width; w++)
358 {
359 guint32 pixval;
360 int x = tablex[w];
361 if (x == old_x)
362 pixval = old_pixval;
363 else
364 {
365 pixval = gdk_image_get_pixel( img, x, tabley[h] );
366 old_pixval = pixval;
367 old_x = x;
368 }
369
370 if ( dst )
371 {
372 if (!pixval)
373 {
374 char bit=1;
375 char shift = bit << (w % 8);
376 outbyte |= shift;
377 }
378
379 if ((w+1)%8==0)
380 {
381 dst[h*dstbyteperline+w/8] = outbyte;
382 outbyte = 0;
383 }
384 }
385 else
386 {
387 GdkColor col;
388 col.pixel = pixval;
389 gdk_gc_set_foreground( gc, &col );
390 gdk_draw_point( dstpix, gc, w, h);
391 }
392 }
393
394 // do not forget the last byte
395 if ( dst && (width % 8 != 0) )
396 dst[h*dstbyteperline+width/8] = outbyte;
397 }
398
399 g_object_unref (img);
400 if (gc) g_object_unref (gc);
401
402 if ( dst )
403 {
404 bmp = wxBitmap( (const char *)dst, width, height, 1 );
405 free( dst );
406 }
407
408 if (GetMask())
409 {
410 dstbyteperline = (width + 7) / 8;
411 dst = (char*) malloc(dstbyteperline*height);
412 img = gdk_drawable_get_image(GetMask()->GetBitmap(), 0, 0, GetWidth(), GetHeight());
413
414 for (int h = 0; h < height; h++)
415 {
416 char outbyte = 0;
417 int old_x = -1;
418 guint32 old_pixval = 0;
419
420 for (int w = 0; w < width; w++)
421 {
422 guint32 pixval;
423 int x = tablex[w];
424 if (x == old_x)
425 pixval = old_pixval;
426 else
427 {
428 pixval = gdk_image_get_pixel( img, x, tabley[h] );
429 old_pixval = pixval;
430 old_x = x;
431 }
432
433 if (pixval)
434 {
435 char bit=1;
436 char shift = bit << (w % 8);
437 outbyte |= shift;
438 }
439
440 if ((w+1)%8 == 0)
441 {
442 dst[h*dstbyteperline+w/8] = outbyte;
443 outbyte = 0;
444 }
445 }
446
447 // do not forget the last byte
448 if (width % 8 != 0)
449 dst[h*dstbyteperline+width/8] = outbyte;
450 }
451 wxMask* mask = new wxMask;
452 mask->m_bitmap = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) dst, width, height );
453 bmp.SetMask(mask);
454
455 free( dst );
456 g_object_unref (img);
457 }
458
459 free( tablex );
460 free( tabley );
461 }
462
463 return bmp;
464 }
465
466 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
467 {
468 UnRef();
469
470 wxCHECK_MSG( image.Ok(), false, wxT("invalid image") );
471 wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") );
472
473 if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
474 return false;
475
476 if (depth == 1)
477 return CreateFromImageAsPixmap(image, depth);
478
479 if (image.HasAlpha())
480 return CreateFromImageAsPixbuf(image);
481
482 return CreateFromImageAsPixmap(image, depth);
483 }
484
485 bool wxBitmap::CreateFromImageAsPixmap(const wxImage& image, int depth)
486 {
487 const int w = image.GetWidth();
488 const int h = image.GetHeight();
489 if (depth == 1)
490 {
491 // create XBM format bitmap
492
493 // one bit per pixel, each row starts on a byte boundary
494 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
495 wxByte* out = new wxByte[out_size];
496 // set bits are white
497 memset(out, 0xff, out_size);
498 const wxByte* in = image.GetData();
499 unsigned bit_index = 0;
500 for (int y = 0; y < h; y++)
501 {
502 for (int x = 0; x < w; x++, in += 3, bit_index++)
503 if (in[0] == 255 && in[1] == 255 && in[2] == 255)
504 out[bit_index >> 3] ^= 1 << (bit_index & 7);
505 // move index to next byte boundary
506 bit_index = (bit_index + 7) & ~7u;
507 }
508 SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h));
509 delete[] out;
510 }
511 else
512 {
513 SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, w, h, depth));
514 GdkGC* gc = gdk_gc_new(M_BMPDATA->m_pixmap);
515 gdk_draw_rgb_image(
516 M_BMPDATA->m_pixmap, gc,
517 0, 0, w, h,
518 GDK_RGB_DITHER_NONE, image.GetData(), w * 3);
519 g_object_unref(gc);
520 }
521
522 const wxByte* alpha = image.GetAlpha();
523 if (alpha != NULL || image.HasMask())
524 {
525 // create mask as XBM format bitmap
526
527 const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
528 wxByte* out = new wxByte[out_size];
529 memset(out, 0xff, out_size);
530 unsigned bit_index = 0;
531 if (alpha != NULL)
532 {
533 for (int y = 0; y < h; y++)
534 {
535 for (int x = 0; x < w; x++, bit_index++)
536 if (*alpha++ < wxIMAGE_ALPHA_THRESHOLD)
537 out[bit_index >> 3] ^= 1 << (bit_index & 7);
538 bit_index = (bit_index + 7) & ~7u;
539 }
540 }
541 else
542 {
543 const wxByte r_mask = image.GetMaskRed();
544 const wxByte g_mask = image.GetMaskGreen();
545 const wxByte b_mask = image.GetMaskBlue();
546 const wxByte* in = image.GetData();
547 for (int y = 0; y < h; y++)
548 {
549 for (int x = 0; x < w; x++, in += 3, bit_index++)
550 if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
551 out[bit_index >> 3] ^= 1 << (bit_index & 7);
552 bit_index = (bit_index + 7) & ~7u;
553 }
554 }
555 wxMask* mask = new wxMask;
556 mask->m_bitmap = gdk_bitmap_create_from_data(M_BMPDATA->m_pixmap, (char*)out, w, h);
557 SetMask(mask);
558 delete[] out;
559 }
560 return true;
561 }
562
563 bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
564 {
565 int width = image.GetWidth();
566 int height = image.GetHeight();
567
568 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
569 true, //image.HasAlpha(),
570 8 /* bits per sample */,
571 width, height);
572 if (!pixbuf)
573 return false;
574
575 wxASSERT( image.HasAlpha() ); // for now
576 wxASSERT( gdk_pixbuf_get_n_channels(pixbuf) == 4 );
577 wxASSERT( gdk_pixbuf_get_width(pixbuf) == width );
578 wxASSERT( gdk_pixbuf_get_height(pixbuf) == height );
579
580 SetDepth(wxTheApp->GetGdkVisual()->depth);
581 SetPixbuf(pixbuf);
582
583 // Copy the data:
584 unsigned char *in = image.GetData();
585 unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
586 unsigned char *alpha = image.GetAlpha();
587
588 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
589
590 for (int y = 0; y < height; y++, out += rowinc)
591 {
592 for (int x = 0; x < width; x++, alpha++, out += 4, in += 3)
593 {
594 out[0] = in[0];
595 out[1] = in[1];
596 out[2] = in[2];
597 out[3] = *alpha;
598 }
599 }
600
601 return true;
602 }
603
604 wxImage wxBitmap::ConvertToImage() const
605 {
606 wxImage image;
607
608 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
609
610 const int w = GetWidth();
611 const int h = GetHeight();
612 image.Create(w, h);
613 unsigned char *data = image.GetData();
614
615 wxCHECK_MSG(data != NULL, wxNullImage, wxT("couldn't create image") );
616
617 if (HasPixbuf())
618 {
619 GdkPixbuf *pixbuf = GetPixbuf();
620 wxASSERT( gdk_pixbuf_get_has_alpha(pixbuf) );
621
622 image.SetAlpha();
623
624 unsigned char *alpha = image.GetAlpha();
625 unsigned char *in = gdk_pixbuf_get_pixels(pixbuf);
626 unsigned char *out = data;
627 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * w;
628
629 for (int y = 0; y < h; y++, in += rowinc)
630 {
631 for (int x = 0; x < w; x++, in += 4, out += 3, alpha++)
632 {
633 out[0] = in[0];
634 out[1] = in[1];
635 out[2] = in[2];
636 *alpha = in[3];
637 }
638 }
639 }
640 else
641 {
642 GdkPixmap* pixmap = GetPixmap();
643 GdkPixmap* pixmap_invert = NULL;
644 #if 0
645 if (GetDepth() == 1)
646 {
647 // mono bitmaps are inverted
648 pixmap_invert = gdk_pixmap_new(pixmap, w, h, 1);
649 GdkGC* gc = gdk_gc_new(pixmap_invert);
650 gdk_gc_set_function(gc, GDK_COPY_INVERT);
651 gdk_draw_drawable(pixmap_invert, gc, pixmap, 0, 0, 0, 0, w, h);
652 g_object_unref(gc);
653 pixmap = pixmap_invert;
654 }
655 #endif
656 // create a pixbuf which shares data with the wxImage
657 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
658 data, GDK_COLORSPACE_RGB, false, 8, w, h, 3 * w, NULL, NULL);
659
660 gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
661
662 g_object_unref(pixbuf);
663 if (pixmap_invert != NULL)
664 g_object_unref(pixmap_invert);
665
666 if (GetMask())
667 {
668 // the colour used as transparent one in wxImage and the one it is
669 // replaced with when it really occurs in the bitmap
670 const int MASK_RED = 1;
671 const int MASK_GREEN = 2;
672 const int MASK_BLUE = 3;
673 const int MASK_BLUE_REPLACEMENT = 2;
674
675 image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
676 GdkImage* image_mask = gdk_drawable_get_image(GetMask()->GetBitmap(), 0, 0, w, h);
677
678 for (int y = 0; y < h; y++)
679 {
680 for (int x = 0; x < w; x++, data += 3)
681 {
682 if (gdk_image_get_pixel(image_mask, x, y) == 0)
683 {
684 data[0] = MASK_RED;
685 data[1] = MASK_GREEN;
686 data[2] = MASK_BLUE;
687 }
688 else if (data[0] == MASK_RED && data[1] == MASK_GREEN && data[2] == MASK_BLUE)
689 {
690 data[2] = MASK_BLUE_REPLACEMENT;
691 }
692 }
693 }
694 g_object_unref(image_mask);
695 }
696 }
697
698 return image;
699 }
700
701 wxBitmap::wxBitmap( const wxString &filename, wxBitmapType type )
702 {
703 LoadFile( filename, type );
704 }
705
706 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
707 {
708 if ( width > 0 && height > 0 )
709 {
710 SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, bits, width, height));
711
712 wxASSERT_MSG( M_BMPDATA->m_pixmap, wxT("couldn't create bitmap") );
713 }
714 }
715
716 wxBitmap::~wxBitmap()
717 {
718 }
719
720 bool wxBitmap::operator == ( const wxBitmap& bmp ) const
721 {
722 return m_refData == bmp.m_refData;
723 }
724
725 bool wxBitmap::operator != ( const wxBitmap& bmp ) const
726 {
727 return m_refData != bmp.m_refData;
728 }
729
730 bool wxBitmap::Ok() const
731 {
732 return (m_refData != NULL) &&
733 (
734 M_BMPDATA->m_pixbuf ||
735 M_BMPDATA->m_pixmap
736 );
737 }
738
739 int wxBitmap::GetHeight() const
740 {
741 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
742
743 return M_BMPDATA->m_height;
744 }
745
746 int wxBitmap::GetWidth() const
747 {
748 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
749
750 return M_BMPDATA->m_width;
751 }
752
753 int wxBitmap::GetDepth() const
754 {
755 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
756
757 return M_BMPDATA->m_bpp;
758 }
759
760 wxMask *wxBitmap::GetMask() const
761 {
762 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
763
764 return M_BMPDATA->m_mask;
765 }
766
767 void wxBitmap::SetMask( wxMask *mask )
768 {
769 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
770
771 if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
772
773 M_BMPDATA->m_mask = mask;
774 }
775
776 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
777 {
778 *this = icon;
779 return Ok();
780 }
781
782 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
783 {
784 wxBitmap ret;
785
786 wxCHECK_MSG( Ok() &&
787 (rect.x >= 0) && (rect.y >= 0) &&
788 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
789 ret, wxT("invalid bitmap or bitmap region") );
790
791 if (HasPixbuf())
792 {
793 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
794 true, //gdk_pixbuf_get_has_alpha(GetPixbuf()),
795 8, rect.width, rect.height);
796 ret.SetPixbuf(pixbuf);
797 ret.SetDepth(M_BMPDATA->m_bpp);
798 gdk_pixbuf_copy_area(GetPixbuf(),
799 rect.x, rect.y, rect.width, rect.height,
800 pixbuf, 0, 0);
801 }
802 else
803 {
804 ret = wxBitmap(rect.width, rect.height, M_BMPDATA->m_bpp);
805 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
806 gdk_draw_drawable( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
807 g_object_unref (gc);
808 }
809
810 if (GetMask())
811 {
812 wxMask *mask = new wxMask;
813 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
814
815 GdkGC *gc = gdk_gc_new( mask->m_bitmap );
816 gdk_draw_drawable(mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, rect.x, rect.y, 0, 0, rect.width, rect.height);
817 g_object_unref (gc);
818
819 ret.SetMask( mask );
820 }
821
822 return ret;
823 }
824
825 bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
826 {
827 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
828
829 // Try to save the bitmap via wxImage handlers:
830 wxImage image = ConvertToImage();
831 return image.Ok() && image.SaveFile(name, type);
832 }
833
834 bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
835 {
836 UnRef();
837
838 if (type == wxBITMAP_TYPE_XPM)
839 {
840 GdkBitmap *mask = (GdkBitmap*) NULL;
841 SetPixmap(gdk_pixmap_create_from_xpm(wxGetRootWindow()->window, &mask, NULL, name.fn_str()));
842
843 if (mask)
844 {
845 M_BMPDATA->m_mask = new wxMask;
846 M_BMPDATA->m_mask->m_bitmap = mask;
847 }
848 }
849 else // try if wxImage can load it
850 {
851 wxImage image;
852 if (image.LoadFile(name, type) && image.Ok())
853 *this = wxBitmap(image);
854 }
855
856 return Ok();
857 }
858
859 #if wxUSE_PALETTE
860 wxPalette *wxBitmap::GetPalette() const
861 {
862 if (!Ok())
863 return (wxPalette *) NULL;
864
865 return M_BMPDATA->m_palette;
866 }
867
868 void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
869 {
870 // TODO
871 }
872 #endif // wxUSE_PALETTE
873
874 void wxBitmap::SetHeight( int height )
875 {
876 if (!m_refData)
877 m_refData = new wxBitmapRefData;
878
879 M_BMPDATA->m_height = height;
880 }
881
882 void wxBitmap::SetWidth( int width )
883 {
884 if (!m_refData)
885 m_refData = new wxBitmapRefData;
886
887 M_BMPDATA->m_width = width;
888 }
889
890 void wxBitmap::SetDepth( int depth )
891 {
892 if (!m_refData)
893 m_refData = new wxBitmapRefData;
894
895 M_BMPDATA->m_bpp = depth;
896 }
897
898 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
899 {
900 if (!m_refData)
901 m_refData = new wxBitmapRefData;
902
903 wxASSERT(M_BMPDATA->m_pixmap == NULL);
904 M_BMPDATA->m_pixmap = pixmap;
905 gdk_drawable_get_size(pixmap, &M_BMPDATA->m_width, &M_BMPDATA->m_height);
906 M_BMPDATA->m_bpp = gdk_drawable_get_depth(pixmap);
907 PurgeOtherRepresentations(Pixmap);
908 }
909
910 GdkPixmap *wxBitmap::GetPixmap() const
911 {
912 wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
913
914 // create the pixmap on the fly if we use Pixbuf representation:
915 if (M_BMPDATA->m_pixmap == NULL)
916 {
917 delete M_BMPDATA->m_mask;
918 M_BMPDATA->m_mask = new wxMask;
919 gdk_pixbuf_render_pixmap_and_mask(M_BMPDATA->m_pixbuf,
920 &M_BMPDATA->m_pixmap,
921 &M_BMPDATA->m_mask->m_bitmap,
922 128 /*threshold*/);
923 }
924
925 return M_BMPDATA->m_pixmap;
926 }
927
928 bool wxBitmap::HasPixmap() const
929 {
930 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
931
932 return M_BMPDATA->m_pixmap != NULL;
933 }
934
935 GdkPixbuf *wxBitmap::GetPixbuf() const
936 {
937 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
938
939 if (M_BMPDATA->m_pixbuf == NULL)
940 {
941 int width = GetWidth();
942 int height = GetHeight();
943
944 // always create the alpha channel so raw bitmap access will work
945 // correctly
946 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
947 true, // GetMask() != NULL,
948 8, width, height);
949 M_BMPDATA->m_pixbuf =
950 gdk_pixbuf_get_from_drawable(pixbuf, M_BMPDATA->m_pixmap, NULL,
951 0, 0, 0, 0, width, height);
952
953 // apply the mask to created pixbuf:
954 if (M_BMPDATA->m_pixbuf && M_BMPDATA->m_mask)
955 {
956 GdkPixbuf *pmask =
957 gdk_pixbuf_get_from_drawable(NULL,
958 M_BMPDATA->m_mask->GetBitmap(),
959 NULL,
960 0, 0, 0, 0, width, height);
961 if (pmask)
962 {
963 guchar *bmp = gdk_pixbuf_get_pixels(pixbuf);
964 guchar *mask = gdk_pixbuf_get_pixels(pmask);
965 int bmprowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
966 int maskrowinc = gdk_pixbuf_get_rowstride(pmask) - 3 * width;
967
968 for (int y = 0; y < height;
969 y++, bmp += bmprowinc, mask += maskrowinc)
970 {
971 for (int x = 0; x < width; x++, bmp += 4, mask += 3)
972 {
973 if (mask[0] == 0 /*black pixel*/)
974 bmp[3] = 0;
975 }
976 }
977
978 g_object_unref (pmask);
979 }
980 }
981 }
982
983 return M_BMPDATA->m_pixbuf;
984 }
985
986 bool wxBitmap::HasPixbuf() const
987 {
988 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
989
990 return M_BMPDATA->m_pixbuf != NULL;
991 }
992
993 void wxBitmap::SetPixbuf( GdkPixbuf *pixbuf )
994 {
995 if (!m_refData)
996 m_refData = new wxBitmapRefData;
997
998 wxASSERT(M_BMPDATA->m_pixbuf == NULL);
999 M_BMPDATA->m_pixbuf = pixbuf;
1000 M_BMPDATA->m_width = gdk_pixbuf_get_width(pixbuf);
1001 M_BMPDATA->m_height = gdk_pixbuf_get_height(pixbuf);
1002 PurgeOtherRepresentations(Pixbuf);
1003 }
1004
1005 void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
1006 {
1007 if (keep == Pixmap && HasPixbuf())
1008 {
1009 g_object_unref (M_BMPDATA->m_pixbuf);
1010 M_BMPDATA->m_pixbuf = NULL;
1011 }
1012 if (keep == Pixbuf && HasPixmap())
1013 {
1014 g_object_unref (M_BMPDATA->m_pixmap);
1015 M_BMPDATA->m_pixmap = NULL;
1016 }
1017 }
1018
1019 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
1020 {
1021 if (bpp != 32)
1022 return NULL;
1023
1024 GdkPixbuf *pixbuf = GetPixbuf();
1025 if (!pixbuf)
1026 return NULL;
1027
1028 if (!gdk_pixbuf_get_has_alpha( pixbuf ))
1029 return NULL;
1030
1031 #if 0
1032 if (gdk_pixbuf_get_has_alpha( pixbuf ))
1033 wxPrintf( wxT("Has alpha, %d channels\n"), gdk_pixbuf_get_n_channels(pixbuf) );
1034 else
1035 wxPrintf( wxT("No alpha, %d channels.\n"), gdk_pixbuf_get_n_channels(pixbuf) );
1036 #endif
1037
1038 data.m_height = gdk_pixbuf_get_height( pixbuf );
1039 data.m_width = gdk_pixbuf_get_width( pixbuf );
1040 data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
1041
1042 return gdk_pixbuf_get_pixels( pixbuf );
1043 }
1044
1045 void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
1046 {
1047 }
1048
1049
1050 bool wxBitmap::HasAlpha() const
1051 {
1052 return HasPixbuf();
1053 }
1054
1055 void wxBitmap::UseAlpha()
1056 {
1057 GetPixbuf();
1058 }
1059
1060 //-----------------------------------------------------------------------------
1061 // wxBitmapHandler
1062 //-----------------------------------------------------------------------------
1063
1064 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler,wxBitmapHandlerBase)
1065
1066 wxBitmapHandler::~wxBitmapHandler()
1067 {
1068 }
1069
1070 bool wxBitmapHandler::Create(wxBitmap * WXUNUSED(bitmap),
1071 void * WXUNUSED(data),
1072 long WXUNUSED(type),
1073 int WXUNUSED(width),
1074 int WXUNUSED(height),
1075 int WXUNUSED(depth))
1076 {
1077 wxFAIL_MSG( _T("not implemented") );
1078
1079 return false;
1080 }
1081
1082 bool wxBitmapHandler::LoadFile(wxBitmap * WXUNUSED(bitmap),
1083 const wxString& WXUNUSED(name),
1084 long WXUNUSED(flags),
1085 int WXUNUSED(desiredWidth),
1086 int WXUNUSED(desiredHeight))
1087 {
1088 wxFAIL_MSG( _T("not implemented") );
1089
1090 return false;
1091 }
1092
1093 bool wxBitmapHandler::SaveFile(const wxBitmap * WXUNUSED(bitmap),
1094 const wxString& WXUNUSED(name),
1095 int WXUNUSED(type),
1096 const wxPalette * WXUNUSED(palette))
1097 {
1098 wxFAIL_MSG( _T("not implemented") );
1099
1100 return false;
1101 }
1102
1103 /* static */ void wxBitmap::InitStandardHandlers()
1104 {
1105 // TODO: Insert handler based on GdkPixbufs handler later
1106 }