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