Include wx/image.h according to precompiled headers of wx/wx.h (with other minor...
[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/dcmemory.h"
18 #include "wx/palette.h"
19 #include "wx/icon.h"
20 #include "wx/math.h"
21 #include "wx/image.h"
22 #endif
23
24 #include "wx/filefn.h"
25
26 #include "wx/rawbmp.h"
27 // need this to get gdk_image_new_bitmap()
28 #define GDK_ENABLE_BROKEN
29
30 #include <gdk/gdk.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkx.h>
33
34 #include <gdk/gdkimage.h>
35
36 extern void gdk_wx_draw_bitmap (GdkDrawable *drawable,
37 GdkGC *gc,
38 GdkDrawable *src,
39 gint xsrc,
40 gint ysrc,
41 gint xdest,
42 gint ydest,
43 gint width,
44 gint height);
45
46 //-----------------------------------------------------------------------------
47 // data
48 //-----------------------------------------------------------------------------
49
50 extern GtkWidget *wxGetRootWindow();
51
52 //-----------------------------------------------------------------------------
53 // wxMask
54 //-----------------------------------------------------------------------------
55
56 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
57
58 wxMask::wxMask()
59 {
60 m_bitmap = (GdkBitmap *) NULL;
61 }
62
63 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
64 {
65 m_bitmap = (GdkBitmap *) NULL;
66 Create( bitmap, colour );
67 }
68
69 #if wxUSE_PALETTE
70 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
71 {
72 m_bitmap = (GdkBitmap *) NULL;
73 Create( bitmap, paletteIndex );
74 }
75 #endif // wxUSE_PALETTE
76
77 wxMask::wxMask( const wxBitmap& bitmap )
78 {
79 m_bitmap = (GdkBitmap *) NULL;
80 Create( bitmap );
81 }
82
83 wxMask::~wxMask()
84 {
85 if (m_bitmap)
86 g_object_unref (m_bitmap);
87 }
88
89 bool wxMask::Create( const wxBitmap& bitmap,
90 const wxColour& colour )
91 {
92 if (m_bitmap)
93 {
94 g_object_unref (m_bitmap);
95 m_bitmap = (GdkBitmap*) NULL;
96 }
97
98 wxImage image = bitmap.ConvertToImage();
99 if (!image.Ok()) return false;
100
101 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, image.GetWidth(), image.GetHeight(), 1 );
102 GdkGC *gc = gdk_gc_new( m_bitmap );
103
104 GdkColor color;
105 color.red = 65000;
106 color.green = 65000;
107 color.blue = 65000;
108 color.pixel = 1;
109 gdk_gc_set_foreground( gc, &color );
110 gdk_gc_set_fill( gc, GDK_SOLID );
111 gdk_draw_rectangle( m_bitmap, gc, TRUE, 0, 0, image.GetWidth(), image.GetHeight() );
112
113 unsigned char *data = image.GetData();
114 int index = 0;
115
116 unsigned char red = colour.Red();
117 unsigned char green = colour.Green();
118 unsigned char blue = colour.Blue();
119
120 GdkVisual *visual = wxTheApp->GetGdkVisual();
121
122 int bpp = visual->depth;
123 if ((bpp == 16) && (visual->red_mask != 0xf800))
124 bpp = 15;
125 if (bpp == 15)
126 {
127 red = red & 0xf8;
128 green = green & 0xf8;
129 blue = blue & 0xf8;
130 }
131 else if (bpp == 16)
132 {
133 red = red & 0xf8;
134 green = green & 0xfc;
135 blue = blue & 0xf8;
136 }
137 else if (bpp == 12)
138 {
139 red = red & 0xf0;
140 green = green & 0xf0;
141 blue = blue & 0xf0;
142 }
143
144 color.red = 0;
145 color.green = 0;
146 color.blue = 0;
147 color.pixel = 0;
148 gdk_gc_set_foreground( gc, &color );
149
150 for (int j = 0; j < image.GetHeight(); j++)
151 {
152 int start_x = -1;
153 int i;
154 for (i = 0; i < image.GetWidth(); i++)
155 {
156 if ((data[index] == red) &&
157 (data[index+1] == green) &&
158 (data[index+2] == blue))
159 {
160 if (start_x == -1)
161 start_x = i;
162 }
163 else
164 {
165 if (start_x != -1)
166 {
167 gdk_draw_line( m_bitmap, gc, start_x, j, i-1, j );
168 start_x = -1;
169 }
170 }
171 index += 3;
172 }
173 if (start_x != -1)
174 gdk_draw_line( m_bitmap, gc, start_x, j, i, j );
175 }
176
177 g_object_unref (gc);
178
179 return true;
180 }
181
182 #if wxUSE_PALETTE
183 bool wxMask::Create( const wxBitmap& bitmap, int paletteIndex )
184 {
185 unsigned char r,g,b;
186 wxPalette *pal = bitmap.GetPalette();
187
188 wxCHECK_MSG( pal, false, wxT("Cannot create mask from bitmap without palette") );
189
190 pal->GetRGB(paletteIndex, &r, &g, &b);
191
192 return Create(bitmap, wxColour(r, g, b));
193 }
194 #endif // wxUSE_PALETTE
195
196 bool wxMask::Create( const wxBitmap& bitmap )
197 {
198 if (m_bitmap)
199 {
200 g_object_unref (m_bitmap);
201 m_bitmap = (GdkBitmap*) NULL;
202 }
203
204 if (!bitmap.Ok()) return false;
205
206 wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
207
208 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
209
210 if (!m_bitmap) return false;
211
212 GdkGC *gc = gdk_gc_new( m_bitmap );
213
214 gdk_wx_draw_bitmap( m_bitmap, gc, bitmap.GetPixmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight() );
215
216 g_object_unref (gc);
217
218 return true;
219 }
220
221 GdkBitmap *wxMask::GetBitmap() const
222 {
223 return m_bitmap;
224 }
225
226 //-----------------------------------------------------------------------------
227 // wxBitmap
228 //-----------------------------------------------------------------------------
229
230 class wxBitmapRefData: public wxObjectRefData
231 {
232 public:
233 wxBitmapRefData();
234 ~wxBitmapRefData();
235
236 GdkPixmap *m_pixmap;
237 GdkPixbuf *m_pixbuf;
238 wxMask *m_mask;
239 int m_width;
240 int m_height;
241 int m_bpp;
242 wxPalette *m_palette;
243 };
244
245 wxBitmapRefData::wxBitmapRefData()
246 {
247 m_pixmap = (GdkPixmap *) NULL;
248 m_pixbuf = (GdkPixbuf *) NULL;
249 m_mask = (wxMask *) NULL;
250 m_width = 0;
251 m_height = 0;
252 m_bpp = 0;
253 m_palette = (wxPalette *) NULL;
254 }
255
256 wxBitmapRefData::~wxBitmapRefData()
257 {
258 if (m_pixmap)
259 g_object_unref (m_pixmap);
260 if (m_pixbuf)
261 g_object_unref (m_pixbuf);
262 delete m_mask;
263 #if wxUSE_PALETTE
264 delete m_palette;
265 #endif // wxUSE_PALETTE
266 }
267
268 //-----------------------------------------------------------------------------
269
270 #define M_BMPDATA wx_static_cast(wxBitmapRefData*, m_refData)
271
272 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
273
274 wxBitmap::wxBitmap()
275 {
276 }
277
278 wxBitmap::wxBitmap( int width, int height, int depth )
279 {
280 Create( width, height, depth );
281 }
282
283 bool wxBitmap::Create( int width, int height, int depth )
284 {
285 UnRef();
286
287 if ( width <= 0 || height <= 0 )
288 {
289 return false;
290 }
291
292 GdkVisual *visual = wxTheApp->GetGdkVisual();
293
294 if (depth == -1)
295 depth = visual->depth;
296
297 wxCHECK_MSG( (depth == visual->depth) || (depth == 1) || (depth == 32), false,
298 wxT("invalid bitmap depth") );
299
300 m_refData = new wxBitmapRefData();
301 M_BMPDATA->m_mask = (wxMask *) NULL;
302 M_BMPDATA->m_width = width;
303 M_BMPDATA->m_height = height;
304 M_BMPDATA->m_bpp = depth;
305 if (depth == 32)
306 {
307 M_BMPDATA->m_pixbuf = gdk_pixbuf_new( GDK_COLORSPACE_RGB, true,
308 8, width, height);
309 }
310 else
311 {
312 M_BMPDATA->m_pixmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, depth );
313 }
314
315 return Ok();
316 }
317
318 bool wxBitmap::CreateFromXpm( const char **bits )
319 {
320 UnRef();
321
322 wxCHECK_MSG( bits != NULL, false, wxT("invalid bitmap data") );
323
324 GdkVisual *visual = wxTheApp->GetGdkVisual();
325
326 m_refData = new wxBitmapRefData();
327
328 GdkBitmap *mask = (GdkBitmap*) NULL;
329
330 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm_d( wxGetRootWindow()->window, &mask, NULL, (gchar **) bits );
331
332 wxCHECK_MSG( M_BMPDATA->m_pixmap, false, wxT("couldn't create pixmap") );
333
334 if (mask)
335 {
336 M_BMPDATA->m_mask = new wxMask();
337 M_BMPDATA->m_mask->m_bitmap = mask;
338 }
339
340 gdk_drawable_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
341
342 M_BMPDATA->m_bpp = visual->depth; // Can we get a different depth from create_from_xpm_d() ?
343
344 return true;
345 }
346
347 wxBitmap wxBitmap::Rescale( int clipx, int clipy, int clipwidth, int clipheight, int newx, int newy )
348 {
349 wxCHECK_MSG( Ok(), wxNullBitmap, wxT("invalid bitmap") );
350
351 if (newy==M_BMPDATA->m_width && newy==M_BMPDATA->m_height)
352 return *this;
353
354 int width = wxMax(newx, 1);
355 int height = wxMax(newy, 1);
356 width = wxMin(width, clipwidth);
357 height = wxMin(height, clipheight);
358
359 wxBitmap bmp;
360
361 if (HasPixbuf())
362 {
363 bmp.SetWidth(width);
364 bmp.SetHeight(height);
365 bmp.SetDepth(GetDepth());
366 bmp.SetPixbuf(gdk_pixbuf_new(GDK_COLORSPACE_RGB,
367 gdk_pixbuf_get_has_alpha(GetPixbuf()),
368 8, width, height));
369 gdk_pixbuf_scale(GetPixbuf(), bmp.GetPixbuf(),
370 0, 0, width, height,
371 clipx, clipy,
372 (double)newx/GetWidth(), (double)newy/GetHeight(),
373 GDK_INTERP_BILINEAR);
374 }
375 else
376 {
377 GdkImage *img = (GdkImage*) NULL;
378 if (GetPixmap())
379 img = gdk_image_get( GetPixmap(), 0, 0, GetWidth(), GetHeight() );
380 else
381 wxFAIL_MSG( wxT("Ill-formed bitmap") );
382
383 wxCHECK_MSG( img, wxNullBitmap, wxT("couldn't create image") );
384
385 int bpp = -1;
386
387
388 GdkGC *gc = NULL;
389 GdkPixmap *dstpix = NULL;
390 if (GetDepth() != 1)
391 {
392 GdkVisual *visual = gdk_drawable_get_visual( GetPixmap() );
393 if (visual == NULL)
394 visual = wxTheApp->GetGdkVisual();
395
396 bpp = visual->depth;
397 bmp = wxBitmap(width,height,bpp);
398 dstpix = bmp.GetPixmap();
399 gc = gdk_gc_new( dstpix );
400 }
401
402 char *dst = NULL;
403 long dstbyteperline = 0;
404
405 if (GetDepth() == 1)
406 {
407 bpp = 1;
408 dstbyteperline = width/8*M_BMPDATA->m_bpp;
409 if (width*M_BMPDATA->m_bpp % 8 != 0)
410 dstbyteperline++;
411 dst = (char*) malloc(dstbyteperline*height);
412 }
413
414 // be careful to use the right scaling factor
415 float scx = (float)M_BMPDATA->m_width/(float)newx;
416 float scy = (float)M_BMPDATA->m_height/(float)newy;
417 // prepare accel-tables
418 int *tablex = (int *)calloc(width,sizeof(int));
419 int *tabley = (int *)calloc(height,sizeof(int));
420
421 // accel table filled with clipped values
422 for (int x = 0; x < width; x++)
423 tablex[x] = (int) (scx * (x+clipx));
424 for (int y = 0; y < height; y++)
425 tabley[y] = (int) (scy * (y+clipy));
426
427 // Main rescaling routine starts here
428 for (int h = 0; h < height; h++)
429 {
430 char outbyte = 0;
431 int old_x = -1;
432 guint32 old_pixval = 0;
433
434 for (int w = 0; w < width; w++)
435 {
436 guint32 pixval;
437 int x = tablex[w];
438 if (x == old_x)
439 pixval = old_pixval;
440 else
441 {
442 pixval = gdk_image_get_pixel( img, x, tabley[h] );
443 old_pixval = pixval;
444 old_x = x;
445 }
446
447 if ( dst )
448 {
449 if (!pixval)
450 {
451 char bit=1;
452 char shift = bit << (w % 8);
453 outbyte |= shift;
454 }
455
456 if ((w+1)%8==0)
457 {
458 dst[h*dstbyteperline+w/8] = outbyte;
459 outbyte = 0;
460 }
461 }
462 else
463 {
464 GdkColor col;
465 col.pixel = pixval;
466 gdk_gc_set_foreground( gc, &col );
467 gdk_draw_point( dstpix, gc, w, h);
468 }
469 }
470
471 // do not forget the last byte
472 if ( dst && (width % 8 != 0) )
473 dst[h*dstbyteperline+width/8] = outbyte;
474 }
475
476 g_object_unref (img);
477 if (gc) g_object_unref (gc);
478
479 if ( dst )
480 {
481 bmp = wxBitmap( (const char *)dst, width, height, 1 );
482 free( dst );
483 }
484
485 if (GetMask())
486 {
487 dstbyteperline = width/8;
488 if (width % 8 != 0)
489 dstbyteperline++;
490 dst = (char*) malloc(dstbyteperline*height);
491 img = gdk_image_get( GetMask()->GetBitmap(), 0, 0, GetWidth(), GetHeight() );
492
493 for (int h = 0; h < height; h++)
494 {
495 char outbyte = 0;
496 int old_x = -1;
497 guint32 old_pixval = 0;
498
499 for (int w = 0; w < width; w++)
500 {
501 guint32 pixval;
502 int x = tablex[w];
503 if (x == old_x)
504 pixval = old_pixval;
505 else
506 {
507 pixval = gdk_image_get_pixel( img, x, tabley[h] );
508 old_pixval = pixval;
509 old_x = x;
510 }
511
512 if (pixval)
513 {
514 char bit=1;
515 char shift = bit << (w % 8);
516 outbyte |= shift;
517 }
518
519 if ((w+1)%8 == 0)
520 {
521 dst[h*dstbyteperline+w/8] = outbyte;
522 outbyte = 0;
523 }
524 }
525
526 // do not forget the last byte
527 if (width % 8 != 0)
528 dst[h*dstbyteperline+width/8] = outbyte;
529 }
530 wxMask* mask = new wxMask;
531 mask->m_bitmap = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) dst, width, height );
532 bmp.SetMask(mask);
533
534 free( dst );
535 g_object_unref (img);
536 }
537
538 free( tablex );
539 free( tabley );
540 }
541
542 return bmp;
543 }
544
545 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
546 {
547 UnRef();
548
549 wxCHECK_MSG( image.Ok(), false, wxT("invalid image") );
550 wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") );
551
552 if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
553 return false;
554
555 m_refData = new wxBitmapRefData();
556
557 if (depth == 1)
558 {
559 return CreateFromImageAsBitmap(image);
560 }
561 else
562 {
563 if (image.HasAlpha())
564 return CreateFromImageAsPixbuf(image);
565
566 return CreateFromImageAsPixmap(image);
567 }
568 }
569
570 // conversion to mono bitmap:
571 bool wxBitmap::CreateFromImageAsBitmap(const wxImage& img)
572 {
573 // convert alpha channel to mask, if it is present:
574 wxImage image(img);
575 image.ConvertAlphaToMask();
576
577 int width = image.GetWidth();
578 int height = image.GetHeight();
579
580 SetHeight( height );
581 SetWidth( width );
582
583 SetPixmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 ) );
584
585 SetDepth( 1 );
586
587 GdkVisual *visual = wxTheApp->GetGdkVisual();
588
589 // Create picture image
590
591 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
592
593 GdkImage *data_image =
594 gdk_image_new_bitmap( visual, data_data, width, height );
595
596 // Create mask image
597
598 GdkImage *mask_image = (GdkImage*) NULL;
599
600 if (image.HasMask())
601 {
602 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
603
604 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
605
606 wxMask *mask = new wxMask();
607 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
608
609 SetMask( mask );
610 }
611
612 int r_mask = image.GetMaskRed();
613 int g_mask = image.GetMaskGreen();
614 int b_mask = image.GetMaskBlue();
615
616 unsigned char* data = image.GetData();
617
618 int index = 0;
619 for (int y = 0; y < height; y++)
620 {
621 for (int x = 0; x < width; x++)
622 {
623 int r = data[index];
624 index++;
625 int g = data[index];
626 index++;
627 int b = data[index];
628 index++;
629
630 if (image.HasMask())
631 {
632 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
633 gdk_image_put_pixel( mask_image, x, y, 1 );
634 else
635 gdk_image_put_pixel( mask_image, x, y, 0 );
636 }
637
638 if ((r == 255) && (b == 255) && (g == 255))
639 gdk_image_put_pixel( data_image, x, y, 1 );
640 else
641 gdk_image_put_pixel( data_image, x, y, 0 );
642
643 } // for
644 } // for
645
646 // Blit picture
647
648 GdkGC *data_gc = gdk_gc_new( GetPixmap() );
649
650 gdk_draw_image( GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
651
652 g_object_unref (data_image);
653 g_object_unref (data_gc);
654
655 // Blit mask
656
657 if (image.HasMask())
658 {
659 GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
660
661 gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
662
663 g_object_unref (mask_image);
664 g_object_unref (mask_gc);
665 }
666
667 return true;
668 }
669
670 // conversion to colour bitmap:
671 bool wxBitmap::CreateFromImageAsPixmap(const wxImage& img)
672 {
673 // convert alpha channel to mask, if it is present:
674 wxImage image(img);
675 image.ConvertAlphaToMask();
676
677 int width = image.GetWidth();
678 int height = image.GetHeight();
679
680 SetHeight( height );
681 SetWidth( width );
682
683 SetPixmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, -1 ) );
684
685 GdkVisual *visual = wxTheApp->GetGdkVisual();
686
687 int bpp = visual->depth;
688
689 SetDepth( bpp );
690
691 GdkGC *gc = gdk_gc_new( GetPixmap() );
692
693 gdk_draw_rgb_image( GetPixmap(),
694 gc,
695 0, 0,
696 width, height,
697 GDK_RGB_DITHER_NONE,
698 image.GetData(),
699 width*3 );
700
701 g_object_unref (gc);
702
703 // Create mask image
704
705 GdkImage *mask_image = (GdkImage*) NULL;
706
707 if (!image.HasMask())
708 return true;
709
710 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
711
712 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
713
714 wxMask *mask = new wxMask();
715 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
716
717 SetMask( mask );
718
719 int r_mask = image.GetMaskRed();
720 int g_mask = image.GetMaskGreen();
721 int b_mask = image.GetMaskBlue();
722
723 unsigned char* data = image.GetData();
724
725 int index = 0;
726 for (int y = 0; y < height; y++)
727 {
728 for (int x = 0; x < width; x++)
729 {
730 int r = data[index];
731 index++;
732 int g = data[index];
733 index++;
734 int b = data[index];
735 index++;
736
737 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
738 gdk_image_put_pixel( mask_image, x, y, 1 );
739 else
740 gdk_image_put_pixel( mask_image, x, y, 0 );
741 } // for
742 } // for
743
744 // Blit mask
745
746 GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
747
748 gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
749
750 g_object_unref (mask_image);
751 g_object_unref (mask_gc);
752
753 return true;
754 }
755
756 bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
757 {
758 int width = image.GetWidth();
759 int height = image.GetHeight();
760
761 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
762 image.HasAlpha(),
763 8 /* bits per sample */,
764 width, height);
765 if (!pixbuf)
766 return false;
767
768 wxASSERT( image.HasAlpha() ); // for now
769 wxASSERT( gdk_pixbuf_get_n_channels(pixbuf) == 4 );
770 wxASSERT( gdk_pixbuf_get_width(pixbuf) == width );
771 wxASSERT( gdk_pixbuf_get_height(pixbuf) == height );
772
773 M_BMPDATA->m_pixbuf = pixbuf;
774 SetHeight(height);
775 SetWidth(width);
776 SetDepth(wxTheApp->GetGdkVisual()->depth);
777
778 // Copy the data:
779 unsigned char *in = image.GetData();
780 unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
781 unsigned char *alpha = image.GetAlpha();
782
783 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
784
785 for (int y = 0; y < height; y++, out += rowinc)
786 {
787 for (int x = 0; x < width; x++, alpha++, out += 4, in += 3)
788 {
789 out[0] = in[0];
790 out[1] = in[1];
791 out[2] = in[2];
792 out[3] = *alpha;
793 }
794 }
795
796 return true;
797 }
798
799 wxImage wxBitmap::ConvertToImage() const
800 {
801 wxImage image;
802
803 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
804
805 image.Create(GetWidth(), GetHeight());
806 unsigned char *data = image.GetData();
807
808 if (!data)
809 {
810 wxFAIL_MSG( wxT("couldn't create image") );
811 return wxNullImage;
812 }
813
814 if (HasPixbuf())
815 {
816 GdkPixbuf *pixbuf = GetPixbuf();
817 wxASSERT( gdk_pixbuf_get_has_alpha(pixbuf) );
818
819 int w = GetWidth();
820 int h = GetHeight();
821
822 image.SetAlpha();
823
824 unsigned char *alpha = image.GetAlpha();
825 unsigned char *in = gdk_pixbuf_get_pixels(pixbuf);
826 unsigned char *out = data;
827 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * w;
828
829 for (int y = 0; y < h; y++, in += rowinc)
830 {
831 for (int x = 0; x < w; x++, in += 4, out += 3, alpha++)
832 {
833 out[0] = in[0];
834 out[1] = in[1];
835 out[2] = in[2];
836 *alpha = in[3];
837 }
838 }
839 }
840 else
841 {
842 // the colour used as transparent one in wxImage and the one it is
843 // replaced with when it really occurs in the bitmap
844 static const int MASK_RED = 1;
845 static const int MASK_GREEN = 2;
846 static const int MASK_BLUE = 3;
847 static const int MASK_BLUE_REPLACEMENT = 2;
848
849 GdkImage *gdk_image = (GdkImage*) NULL;
850
851 if (HasPixmap())
852 {
853 gdk_image = gdk_image_get( GetPixmap(),
854 0, 0,
855 GetWidth(), GetHeight() );
856 }
857 else
858 {
859 wxFAIL_MSG( wxT("Ill-formed bitmap") );
860 }
861
862 wxCHECK_MSG( gdk_image, wxNullImage, wxT("couldn't create image") );
863
864 GdkImage *gdk_image_mask = (GdkImage*) NULL;
865 if (GetMask())
866 {
867 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
868 0, 0,
869 GetWidth(), GetHeight() );
870
871 image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
872 }
873
874 int bpp = -1;
875 int red_shift_right = 0;
876 int green_shift_right = 0;
877 int blue_shift_right = 0;
878 int red_shift_left = 0;
879 int green_shift_left = 0;
880 int blue_shift_left = 0;
881 bool use_shift = false;
882
883 if (GetDepth() != 1)
884 {
885 GdkVisual *visual = gdk_drawable_get_visual( GetPixmap() );
886 if (visual == NULL)
887 visual = wxTheApp->GetGdkVisual();
888
889 bpp = visual->depth;
890 if (bpp == 16)
891 bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
892 red_shift_right = visual->red_shift;
893 red_shift_left = 8-visual->red_prec;
894 green_shift_right = visual->green_shift;
895 green_shift_left = 8-visual->green_prec;
896 blue_shift_right = visual->blue_shift;
897 blue_shift_left = 8-visual->blue_prec;
898
899 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
900 }
901 else
902 {
903 bpp = 1;
904 }
905
906
907 GdkColormap *cmap = gtk_widget_get_default_colormap();
908
909 long pos = 0;
910 for (int j = 0; j < GetHeight(); j++)
911 {
912 for (int i = 0; i < GetWidth(); i++)
913 {
914 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
915 if (bpp == 1)
916 {
917 if (pixel == 0)
918 {
919 data[pos] = 0;
920 data[pos+1] = 0;
921 data[pos+2] = 0;
922 }
923 else
924 {
925 data[pos] = 255;
926 data[pos+1] = 255;
927 data[pos+2] = 255;
928 }
929 }
930 else if (use_shift)
931 {
932 data[pos] = (pixel >> red_shift_right) << red_shift_left;
933 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
934 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
935 }
936 else if (cmap->colors)
937 {
938 data[pos] = cmap->colors[pixel].red >> 8;
939 data[pos+1] = cmap->colors[pixel].green >> 8;
940 data[pos+2] = cmap->colors[pixel].blue >> 8;
941 }
942 else
943 {
944 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
945 }
946
947 if (gdk_image_mask)
948 {
949 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
950 if (mask_pixel == 0)
951 {
952 data[pos] = MASK_RED;
953 data[pos+1] = MASK_GREEN;
954 data[pos+2] = MASK_BLUE;
955 }
956 else if ( data[pos] == MASK_RED &&
957 data[pos+1] == MASK_GREEN &&
958 data[pos+2] == MASK_BLUE )
959 {
960 data[pos+2] = MASK_BLUE_REPLACEMENT;
961 }
962 }
963
964 pos += 3;
965 }
966 }
967
968 g_object_unref (gdk_image);
969 if (gdk_image_mask) g_object_unref (gdk_image_mask);
970 }
971
972 return image;
973 }
974
975 wxBitmap::wxBitmap( const wxString &filename, wxBitmapType type )
976 {
977 LoadFile( filename, type );
978 }
979
980 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
981 {
982 if ( width > 0 && height > 0 )
983 {
984 m_refData = new wxBitmapRefData();
985
986 M_BMPDATA->m_mask = (wxMask *) NULL;
987 M_BMPDATA->m_pixmap = gdk_bitmap_create_from_data
988 (
989 wxGetRootWindow()->window,
990 (gchar *) bits,
991 width,
992 height
993 );
994 M_BMPDATA->m_width = width;
995 M_BMPDATA->m_height = height;
996 M_BMPDATA->m_bpp = 1;
997
998 wxASSERT_MSG( M_BMPDATA->m_pixmap, wxT("couldn't create bitmap") );
999 }
1000 }
1001
1002 wxBitmap::~wxBitmap()
1003 {
1004 }
1005
1006 bool wxBitmap::operator == ( const wxBitmap& bmp ) const
1007 {
1008 return m_refData == bmp.m_refData;
1009 }
1010
1011 bool wxBitmap::operator != ( const wxBitmap& bmp ) const
1012 {
1013 return m_refData != bmp.m_refData;
1014 }
1015
1016 bool wxBitmap::Ok() const
1017 {
1018 return (m_refData != NULL) &&
1019 (
1020 M_BMPDATA->m_pixbuf ||
1021 M_BMPDATA->m_pixmap
1022 );
1023 }
1024
1025 int wxBitmap::GetHeight() const
1026 {
1027 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1028
1029 return M_BMPDATA->m_height;
1030 }
1031
1032 int wxBitmap::GetWidth() const
1033 {
1034 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1035
1036 return M_BMPDATA->m_width;
1037 }
1038
1039 int wxBitmap::GetDepth() const
1040 {
1041 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1042
1043 return M_BMPDATA->m_bpp;
1044 }
1045
1046 wxMask *wxBitmap::GetMask() const
1047 {
1048 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
1049
1050 return M_BMPDATA->m_mask;
1051 }
1052
1053 void wxBitmap::SetMask( wxMask *mask )
1054 {
1055 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
1056
1057 if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
1058
1059 M_BMPDATA->m_mask = mask;
1060 }
1061
1062 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
1063 {
1064 *this = icon;
1065 return true;
1066 }
1067
1068 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
1069 {
1070 wxCHECK_MSG( Ok() &&
1071 (rect.x >= 0) && (rect.y >= 0) &&
1072 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
1073 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
1074
1075 wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
1076 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
1077
1078 if (HasPixbuf())
1079 {
1080 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1081 gdk_pixbuf_get_has_alpha(GetPixbuf()),
1082 8, rect.width, rect.height);
1083 ret.SetPixbuf(pixbuf);
1084 gdk_pixbuf_copy_area(GetPixbuf(),
1085 rect.x, rect.y, rect.width, rect.height,
1086 pixbuf, 0, 0);
1087 }
1088 else
1089 {
1090 if (ret.GetDepth() != 1)
1091 {
1092 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
1093 gdk_draw_drawable( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1094 g_object_unref (gc);
1095 }
1096 else
1097 {
1098 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
1099 GdkColor col;
1100 col.pixel = 0xFFFFFF;
1101 gdk_gc_set_foreground( gc, &col );
1102 col.pixel = 0;
1103 gdk_gc_set_background( gc, &col );
1104 gdk_wx_draw_bitmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1105 g_object_unref (gc);
1106 }
1107 }
1108
1109 if (GetMask())
1110 {
1111 wxMask *mask = new wxMask;
1112 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
1113
1114 GdkGC *gc = gdk_gc_new( mask->m_bitmap );
1115 GdkColor col;
1116 col.pixel = 0xFFFFFF;
1117 gdk_gc_set_foreground( gc, &col );
1118 col.pixel = 0;
1119 gdk_gc_set_background( gc, &col );
1120 gdk_wx_draw_bitmap( mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, rect.x, rect.y, 0, 0, rect.width, rect.height );
1121 g_object_unref (gc);
1122
1123 ret.SetMask( mask );
1124 }
1125
1126 return ret;
1127 }
1128
1129 bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
1130 {
1131 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1132
1133 // Try to save the bitmap via wxImage handlers:
1134 {
1135 wxImage image = ConvertToImage();
1136 if (image.Ok()) return image.SaveFile( name, type );
1137 }
1138
1139 return false;
1140 }
1141
1142 bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
1143 {
1144 UnRef();
1145
1146 if (!wxFileExists(name))
1147 return false;
1148
1149 GdkVisual *visual = wxTheApp->GetGdkVisual();
1150
1151 if (type == wxBITMAP_TYPE_XPM)
1152 {
1153 m_refData = new wxBitmapRefData();
1154
1155 GdkBitmap *mask = (GdkBitmap*) NULL;
1156
1157 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm
1158 (
1159 wxGetRootWindow()->window,
1160 &mask,
1161 NULL,
1162 name.fn_str()
1163 );
1164
1165 if (mask)
1166 {
1167 M_BMPDATA->m_mask = new wxMask();
1168 M_BMPDATA->m_mask->m_bitmap = mask;
1169 }
1170
1171 gdk_drawable_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
1172
1173 M_BMPDATA->m_bpp = visual->depth;
1174 }
1175 else // try if wxImage can load it
1176 {
1177 wxImage image;
1178 if ( !image.LoadFile( name, type ) || !image.Ok() )
1179 return false;
1180
1181 *this = wxBitmap(image);
1182 }
1183
1184 return true;
1185 }
1186
1187 #if wxUSE_PALETTE
1188 wxPalette *wxBitmap::GetPalette() const
1189 {
1190 if (!Ok())
1191 return (wxPalette *) NULL;
1192
1193 return M_BMPDATA->m_palette;
1194 }
1195
1196 void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
1197 {
1198 // TODO
1199 }
1200 #endif // wxUSE_PALETTE
1201
1202 void wxBitmap::SetHeight( int height )
1203 {
1204 if (!m_refData)
1205 m_refData = new wxBitmapRefData();
1206
1207 M_BMPDATA->m_height = height;
1208 }
1209
1210 void wxBitmap::SetWidth( int width )
1211 {
1212 if (!m_refData)
1213 m_refData = new wxBitmapRefData();
1214
1215 M_BMPDATA->m_width = width;
1216 }
1217
1218 void wxBitmap::SetDepth( int depth )
1219 {
1220 if (!m_refData)
1221 m_refData = new wxBitmapRefData();
1222
1223 M_BMPDATA->m_bpp = depth;
1224 }
1225
1226 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
1227 {
1228 if (!m_refData)
1229 m_refData = new wxBitmapRefData();
1230
1231 M_BMPDATA->m_pixmap = pixmap;
1232 PurgeOtherRepresentations(Pixmap);
1233 }
1234
1235 GdkPixmap *wxBitmap::GetPixmap() const
1236 {
1237 wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
1238
1239 // create the pixmap on the fly if we use Pixbuf representation:
1240 if (HasPixbuf() && !HasPixmap())
1241 {
1242 delete M_BMPDATA->m_mask;
1243 M_BMPDATA->m_mask = new wxMask();
1244 gdk_pixbuf_render_pixmap_and_mask(M_BMPDATA->m_pixbuf,
1245 &M_BMPDATA->m_pixmap,
1246 &M_BMPDATA->m_mask->m_bitmap,
1247 128 /*threshold*/);
1248 }
1249
1250 return M_BMPDATA->m_pixmap;
1251 }
1252
1253 bool wxBitmap::HasPixmap() const
1254 {
1255 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1256
1257 return M_BMPDATA->m_pixmap != NULL;
1258 }
1259
1260 GdkPixbuf *wxBitmap::GetPixbuf() const
1261 {
1262 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
1263
1264 if (HasPixmap() && !HasPixbuf())
1265 {
1266 int width = GetWidth();
1267 int height = GetHeight();
1268
1269 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1270 GetMask() != NULL,
1271 8, width, height);
1272 M_BMPDATA->m_pixbuf =
1273 gdk_pixbuf_get_from_drawable(pixbuf, M_BMPDATA->m_pixmap, NULL,
1274 0, 0, 0, 0, width, height);
1275
1276 // apply the mask to created pixbuf:
1277 if (M_BMPDATA->m_pixbuf && M_BMPDATA->m_mask)
1278 {
1279 GdkPixbuf *pmask =
1280 gdk_pixbuf_get_from_drawable(NULL,
1281 M_BMPDATA->m_mask->GetBitmap(),
1282 NULL,
1283 0, 0, 0, 0, width, height);
1284 if (pmask)
1285 {
1286 guchar *bmp = gdk_pixbuf_get_pixels(pixbuf);
1287 guchar *mask = gdk_pixbuf_get_pixels(pmask);
1288 int bmprowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
1289 int maskrowinc = gdk_pixbuf_get_rowstride(pmask) - 3 * width;
1290
1291 for (int y = 0; y < height;
1292 y++, bmp += bmprowinc, mask += maskrowinc)
1293 {
1294 for (int x = 0; x < width; x++, bmp += 4, mask += 3)
1295 {
1296 if (mask[0] == 0 /*black pixel*/)
1297 bmp[3] = 0;
1298 }
1299 }
1300
1301 g_object_unref (pmask);
1302 }
1303 }
1304 }
1305
1306 return M_BMPDATA->m_pixbuf;
1307 }
1308
1309 bool wxBitmap::HasPixbuf() const
1310 {
1311 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1312
1313 return M_BMPDATA->m_pixbuf != NULL;
1314 }
1315
1316 void wxBitmap::SetPixbuf( GdkPixbuf *pixbuf )
1317 {
1318 if (!m_refData)
1319 m_refData = new wxBitmapRefData();
1320
1321 M_BMPDATA->m_pixbuf = pixbuf;
1322 PurgeOtherRepresentations(Pixbuf);
1323 }
1324
1325 void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
1326 {
1327 if (keep == Pixmap && HasPixbuf())
1328 {
1329 g_object_unref (M_BMPDATA->m_pixbuf);
1330 M_BMPDATA->m_pixbuf = NULL;
1331 }
1332 if (keep == Pixbuf && HasPixmap())
1333 {
1334 g_object_unref (M_BMPDATA->m_pixmap);
1335 M_BMPDATA->m_pixmap = NULL;
1336 }
1337 }
1338
1339 void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
1340 {
1341 if (bpp != 32)
1342 return NULL;
1343
1344 GdkPixbuf *pixbuf = GetPixbuf();
1345 if (!pixbuf)
1346 return NULL;
1347
1348 #if 0
1349 if (gdk_pixbuf_get_has_alpha( pixbuf ))
1350 wxPrintf( wxT("Has alpha\n") );
1351 else
1352 wxPrintf( wxT("No alpha.\n") );
1353 #endif
1354
1355 data.m_height = gdk_pixbuf_get_height( pixbuf );
1356 data.m_width = gdk_pixbuf_get_width( pixbuf );
1357 data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
1358
1359 return gdk_pixbuf_get_pixels( pixbuf );
1360 }
1361
1362 void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
1363 {
1364 }
1365
1366
1367 bool wxBitmap::HasAlpha() const
1368 {
1369 return HasPixbuf();
1370 }
1371
1372 void wxBitmap::UseAlpha()
1373 {
1374 GetPixbuf();
1375 }
1376
1377 //-----------------------------------------------------------------------------
1378 // wxBitmapHandler
1379 //-----------------------------------------------------------------------------
1380
1381 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler,wxBitmapHandlerBase)
1382
1383 wxBitmapHandler::~wxBitmapHandler()
1384 {
1385 }
1386
1387 bool wxBitmapHandler::Create(wxBitmap * WXUNUSED(bitmap),
1388 void * WXUNUSED(data),
1389 long WXUNUSED(type),
1390 int WXUNUSED(width),
1391 int WXUNUSED(height),
1392 int WXUNUSED(depth))
1393 {
1394 wxFAIL_MSG( _T("not implemented") );
1395
1396 return false;
1397 }
1398
1399 bool wxBitmapHandler::LoadFile(wxBitmap * WXUNUSED(bitmap),
1400 const wxString& WXUNUSED(name),
1401 long WXUNUSED(flags),
1402 int WXUNUSED(desiredWidth),
1403 int WXUNUSED(desiredHeight))
1404 {
1405 wxFAIL_MSG( _T("not implemented") );
1406
1407 return false;
1408 }
1409
1410 bool wxBitmapHandler::SaveFile(const wxBitmap * WXUNUSED(bitmap),
1411 const wxString& WXUNUSED(name),
1412 int WXUNUSED(type),
1413 const wxPalette * WXUNUSED(palette))
1414 {
1415 wxFAIL_MSG( _T("not implemented") );
1416
1417 return false;
1418 }
1419
1420 /* static */ void wxBitmap::InitStandardHandlers()
1421 {
1422 // TODO: Insert handler based on GdkPixbufs handler later
1423 }