bitmaps of size 0 shouldn't be valid
[wxWidgets.git] / src / gtk1 / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #ifdef __GNUG__
11 #pragma implementation "bitmap.h"
12 #endif
13
14 #include "wx/defs.h"
15
16 #include "wx/palette.h"
17 #include "wx/bitmap.h"
18 #include "wx/icon.h"
19 #include "wx/filefn.h"
20 #include "wx/image.h"
21 #include "wx/dcmemory.h"
22 #include "wx/app.h"
23
24 #ifdef __WXGTK20__
25 // need this to get gdk_image_new_bitmap()
26 #define GDK_ENABLE_BROKEN
27 #endif
28
29 #include <gdk/gdk.h>
30 #include <gtk/gtk.h>
31 #include <gdk/gdkx.h>
32
33 #ifdef __WXGTK20__
34 #include <gdk/gdkimage.h>
35 #else // GTK+ 1.2
36 #include <gdk/gdkrgb.h>
37 #endif // GTK+ 2.0/1.2
38
39 extern void gdk_wx_draw_bitmap (GdkDrawable *drawable,
40 GdkGC *gc,
41 GdkDrawable *src,
42 gint xsrc,
43 gint ysrc,
44 gint xdest,
45 gint ydest,
46 gint width,
47 gint height);
48
49 //-----------------------------------------------------------------------------
50 // data
51 //-----------------------------------------------------------------------------
52
53 extern GtkWidget *wxGetRootWindow();
54
55 //-----------------------------------------------------------------------------
56 // wxMask
57 //-----------------------------------------------------------------------------
58
59 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
60
61 wxMask::wxMask()
62 {
63 m_bitmap = (GdkBitmap *) NULL;
64 }
65
66 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
67 {
68 m_bitmap = (GdkBitmap *) NULL;
69 Create( bitmap, colour );
70 }
71
72 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
73 {
74 m_bitmap = (GdkBitmap *) NULL;
75 Create( bitmap, paletteIndex );
76 }
77
78 wxMask::wxMask( const wxBitmap& bitmap )
79 {
80 m_bitmap = (GdkBitmap *) NULL;
81 Create( bitmap );
82 }
83
84 wxMask::~wxMask()
85 {
86 if (m_bitmap)
87 gdk_bitmap_unref( m_bitmap );
88 }
89
90 bool wxMask::Create( const wxBitmap& bitmap,
91 const wxColour& colour )
92 {
93 if (m_bitmap)
94 {
95 gdk_bitmap_unref( m_bitmap );
96 m_bitmap = (GdkBitmap*) NULL;
97 }
98
99 wxImage image = bitmap.ConvertToImage();
100 if (!image.Ok()) return FALSE;
101
102 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, image.GetWidth(), image.GetHeight(), 1 );
103 GdkGC *gc = gdk_gc_new( m_bitmap );
104
105 GdkColor color;
106 color.red = 65000;
107 color.green = 65000;
108 color.blue = 65000;
109 color.pixel = 1;
110 gdk_gc_set_foreground( gc, &color );
111 gdk_gc_set_fill( gc, GDK_SOLID );
112 gdk_draw_rectangle( m_bitmap, gc, TRUE, 0, 0, image.GetWidth(), image.GetHeight() );
113
114 unsigned char *data = image.GetData();
115 int index = 0;
116
117 unsigned char red = colour.Red();
118 unsigned char green = colour.Green();
119 unsigned char blue = colour.Blue();
120
121 GdkVisual *visual = wxTheApp->GetGdkVisual();
122
123 int bpp = visual->depth;
124 if ((bpp == 16) && (visual->red_mask != 0xf800))
125 bpp = 15;
126 if (bpp == 15)
127 {
128 red = red & 0xf8;
129 green = green & 0xf8;
130 blue = blue & 0xf8;
131 }
132 else if (bpp == 16)
133 {
134 red = red & 0xf8;
135 green = green & 0xfc;
136 blue = blue & 0xf8;
137 }
138 else if (bpp == 12)
139 {
140 red = red & 0xf0;
141 green = green & 0xf0;
142 blue = blue & 0xf0;
143 }
144
145 color.red = 0;
146 color.green = 0;
147 color.blue = 0;
148 color.pixel = 0;
149 gdk_gc_set_foreground( gc, &color );
150
151 for (int j = 0; j < image.GetHeight(); j++)
152 {
153 int start_x = -1;
154 int i;
155 for (i = 0; i < image.GetWidth(); i++)
156 {
157 if ((data[index] == red) &&
158 (data[index+1] == green) &&
159 (data[index+2] == blue))
160 {
161 if (start_x == -1)
162 start_x = i;
163 }
164 else
165 {
166 if (start_x != -1)
167 {
168 gdk_draw_line( m_bitmap, gc, start_x, j, i-1, j );
169 start_x = -1;
170 }
171 }
172 index += 3;
173 }
174 if (start_x != -1)
175 gdk_draw_line( m_bitmap, gc, start_x, j, i, j );
176 }
177
178 gdk_gc_unref( gc );
179
180 return TRUE;
181 }
182
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
195 bool wxMask::Create( const wxBitmap& bitmap )
196 {
197 if (m_bitmap)
198 {
199 gdk_bitmap_unref( m_bitmap );
200 m_bitmap = (GdkBitmap*) NULL;
201 }
202
203 if (!bitmap.Ok()) return FALSE;
204
205 wxCHECK_MSG( bitmap.GetBitmap(), FALSE, wxT("Cannot create mask from colour bitmap") );
206
207 m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
208
209 if (!m_bitmap) return FALSE;
210
211 GdkGC *gc = gdk_gc_new( m_bitmap );
212
213 gdk_wx_draw_bitmap( m_bitmap, gc, bitmap.GetBitmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight() );
214
215 gdk_gc_unref( gc );
216
217 return TRUE;
218 }
219
220 GdkBitmap *wxMask::GetBitmap() const
221 {
222 return m_bitmap;
223 }
224
225 //-----------------------------------------------------------------------------
226 // wxBitmap
227 //-----------------------------------------------------------------------------
228
229 class wxBitmapRefData: public wxObjectRefData
230 {
231 public:
232 wxBitmapRefData();
233 ~wxBitmapRefData();
234
235 GdkPixmap *m_pixmap;
236 GdkBitmap *m_bitmap;
237 wxMask *m_mask;
238 int m_width;
239 int m_height;
240 int m_bpp;
241 wxPalette *m_palette;
242 };
243
244 wxBitmapRefData::wxBitmapRefData()
245 {
246 m_pixmap = (GdkPixmap *) NULL;
247 m_bitmap = (GdkBitmap *) NULL;
248 m_mask = (wxMask *) NULL;
249 m_width = 0;
250 m_height = 0;
251 m_bpp = 0;
252 m_palette = (wxPalette *) NULL;
253 }
254
255 wxBitmapRefData::~wxBitmapRefData()
256 {
257 if (m_pixmap)
258 gdk_pixmap_unref( m_pixmap );
259 if (m_bitmap)
260 gdk_bitmap_unref( m_bitmap );
261 delete m_mask;
262 delete m_palette;
263 }
264
265 //-----------------------------------------------------------------------------
266
267 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
268
269 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
270
271 wxBitmap::wxBitmap()
272 {
273 }
274
275 wxBitmap::wxBitmap( int width, int height, int depth )
276 {
277 Create( width, height, depth );
278 }
279
280 bool wxBitmap::Create( int width, int height, int depth )
281 {
282 UnRef();
283
284 if ( width <= 0 || height <= 0 )
285 {
286 return false;
287 }
288
289 GdkVisual *visual = wxTheApp->GetGdkVisual();
290
291 if (depth == -1)
292 depth = visual->depth;
293
294 wxCHECK_MSG( (depth == visual->depth) || (depth == 1), FALSE,
295 wxT("invalid bitmap depth") )
296
297 m_refData = new wxBitmapRefData();
298 M_BMPDATA->m_mask = (wxMask *) NULL;
299 M_BMPDATA->m_width = width;
300 M_BMPDATA->m_height = height;
301 if (depth == 1)
302 {
303 M_BMPDATA->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
304 M_BMPDATA->m_bpp = 1;
305 }
306 else
307 {
308 M_BMPDATA->m_pixmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, depth );
309 M_BMPDATA->m_bpp = visual->depth;
310 }
311
312 return Ok();
313 }
314
315 bool wxBitmap::CreateFromXpm( const char **bits )
316 {
317 UnRef();
318
319 wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid bitmap data") )
320
321 GdkVisual *visual = wxTheApp->GetGdkVisual();
322
323 m_refData = new wxBitmapRefData();
324
325 GdkBitmap *mask = (GdkBitmap*) NULL;
326
327 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm_d( wxGetRootWindow()->window, &mask, NULL, (gchar **) bits );
328
329 wxCHECK_MSG( M_BMPDATA->m_pixmap, FALSE, wxT("couldn't create pixmap") );
330
331 if (mask)
332 {
333 M_BMPDATA->m_mask = new wxMask();
334 M_BMPDATA->m_mask->m_bitmap = mask;
335 }
336
337 gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
338
339 M_BMPDATA->m_bpp = visual->depth; // Can we get a different depth from create_from_xpm_d() ?
340
341 return TRUE;
342 }
343
344 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
345 {
346 UnRef();
347
348 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
349 wxCHECK_MSG( depth == -1 || depth == 1, FALSE, wxT("invalid bitmap depth") )
350
351 int width = image.GetWidth();
352 int height = image.GetHeight();
353
354 if ( width <= 0 || height <= 0 )
355 {
356 return false;
357 }
358
359 m_refData = new wxBitmapRefData();
360
361 SetHeight( height );
362 SetWidth( width );
363
364 // ------
365 // conversion to mono bitmap:
366 // ------
367 if (depth == 1)
368 {
369 SetBitmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 ) );
370
371 SetDepth( 1 );
372
373 GdkVisual *visual = wxTheApp->GetGdkVisual();
374
375 // Create picture image
376
377 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
378
379 GdkImage *data_image =
380 gdk_image_new_bitmap( visual, data_data, width, height );
381
382 // Create mask image
383
384 GdkImage *mask_image = (GdkImage*) NULL;
385
386 if (image.HasMask())
387 {
388 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
389
390 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
391
392 wxMask *mask = new wxMask();
393 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
394
395 SetMask( mask );
396 }
397
398 int r_mask = image.GetMaskRed();
399 int g_mask = image.GetMaskGreen();
400 int b_mask = image.GetMaskBlue();
401
402 unsigned char* data = image.GetData();
403
404 int index = 0;
405 for (int y = 0; y < height; y++)
406 {
407 for (int x = 0; x < width; x++)
408 {
409 int r = data[index];
410 index++;
411 int g = data[index];
412 index++;
413 int b = data[index];
414 index++;
415
416 if (image.HasMask())
417 {
418 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
419 gdk_image_put_pixel( mask_image, x, y, 1 );
420 else
421 gdk_image_put_pixel( mask_image, x, y, 0 );
422 }
423
424 if ((r == 255) && (b == 255) && (g == 255))
425 gdk_image_put_pixel( data_image, x, y, 1 );
426 else
427 gdk_image_put_pixel( data_image, x, y, 0 );
428
429 } // for
430 } // for
431
432 // Blit picture
433
434 GdkGC *data_gc = gdk_gc_new( GetBitmap() );
435
436 gdk_draw_image( GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
437
438 gdk_image_destroy( data_image );
439 gdk_gc_unref( data_gc );
440
441 // Blit mask
442
443 if (image.HasMask())
444 {
445 GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
446
447 gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
448
449 gdk_image_destroy( mask_image );
450 gdk_gc_unref( mask_gc );
451 }
452 }
453
454 // ------
455 // conversion to colour bitmap:
456 // ------
457 else
458 {
459 SetPixmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, -1 ) );
460
461 GdkVisual *visual = wxTheApp->GetGdkVisual();
462
463 int bpp = visual->depth;
464
465 SetDepth( bpp );
466
467 if ((bpp == 16) && (visual->red_mask != 0xf800))
468 bpp = 15;
469 else if (bpp < 8)
470 bpp = 8;
471
472 // We handle 8-bit bitmaps ourselves using the colour cube, 12-bit
473 // visuals are not supported by GDK so we do these ourselves, too.
474 // 15-bit and 16-bit should actually work and 24-bit certainly does.
475 #ifdef __sgi
476 if (!image.HasMask() && (bpp > 16))
477 #else
478 if (!image.HasMask() && (bpp > 12))
479 #endif
480 {
481 static bool s_hasInitialized = FALSE;
482
483 if (!s_hasInitialized)
484 {
485 gdk_rgb_init();
486 s_hasInitialized = TRUE;
487 }
488
489 GdkGC *gc = gdk_gc_new( GetPixmap() );
490
491 gdk_draw_rgb_image( GetPixmap(),
492 gc,
493 0, 0,
494 width, height,
495 GDK_RGB_DITHER_NONE,
496 image.GetData(),
497 width*3 );
498
499 gdk_gc_unref( gc );
500 return TRUE;
501 }
502
503 // Create picture image
504
505 GdkImage *data_image =
506 gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
507
508 // Create mask image
509
510 GdkImage *mask_image = (GdkImage*) NULL;
511
512 if (image.HasMask())
513 {
514 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
515
516 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
517
518 wxMask *mask = new wxMask();
519 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
520
521 SetMask( mask );
522 }
523
524 // Render
525
526 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
527 byte_order b_o = RGB;
528
529 if (bpp > 8)
530 {
531 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
532 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RBG;
533 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
534 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
535 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
536 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
537 }
538
539 int r_mask = image.GetMaskRed();
540 int g_mask = image.GetMaskGreen();
541 int b_mask = image.GetMaskBlue();
542
543 unsigned char* data = image.GetData();
544
545 int index = 0;
546 for (int y = 0; y < height; y++)
547 {
548 for (int x = 0; x < width; x++)
549 {
550 int r = data[index];
551 index++;
552 int g = data[index];
553 index++;
554 int b = data[index];
555 index++;
556
557 if (image.HasMask())
558 {
559 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
560 gdk_image_put_pixel( mask_image, x, y, 1 );
561 else
562 gdk_image_put_pixel( mask_image, x, y, 0 );
563 }
564
565 switch (bpp)
566 {
567 case 8:
568 {
569 int pixel = -1;
570 if (wxTheApp->m_colorCube)
571 {
572 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
573 }
574 else
575 {
576 GdkColormap *cmap = gtk_widget_get_default_colormap();
577 GdkColor *colors = cmap->colors;
578 int max = 3 * (65536);
579
580 for (int i = 0; i < cmap->size; i++)
581 {
582 int rdiff = (r << 8) - colors[i].red;
583 int gdiff = (g << 8) - colors[i].green;
584 int bdiff = (b << 8) - colors[i].blue;
585 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
586 if (sum < max) { pixel = i; max = sum; }
587 }
588 }
589
590 gdk_image_put_pixel( data_image, x, y, pixel );
591
592 break;
593 }
594 case 12: // SGI only
595 {
596 guint32 pixel = 0;
597 switch (b_o)
598 {
599 case RGB: pixel = ((r & 0xf0) << 4) | (g & 0xf0) | ((b & 0xf0) >> 4); break;
600 case RBG: pixel = ((r & 0xf0) << 4) | (b & 0xf0) | ((g & 0xf0) >> 4); break;
601 case GRB: pixel = ((g & 0xf0) << 4) | (r & 0xf0) | ((b & 0xf0) >> 4); break;
602 case GBR: pixel = ((g & 0xf0) << 4) | (b & 0xf0) | ((r & 0xf0) >> 4); break;
603 case BRG: pixel = ((b & 0xf0) << 4) | (r & 0xf0) | ((g & 0xf0) >> 4); break;
604 case BGR: pixel = ((b & 0xf0) << 4) | (g & 0xf0) | ((r & 0xf0) >> 4); break;
605 }
606 gdk_image_put_pixel( data_image, x, y, pixel );
607 break;
608 }
609 case 15:
610 {
611 guint32 pixel = 0;
612 switch (b_o)
613 {
614 case RGB: pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
615 case RBG: pixel = ((r & 0xf8) << 7) | ((b & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
616 case GRB: pixel = ((g & 0xf8) << 7) | ((r & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
617 case GBR: pixel = ((g & 0xf8) << 7) | ((b & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
618 case BRG: pixel = ((b & 0xf8) << 7) | ((r & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
619 case BGR: pixel = ((b & 0xf8) << 7) | ((g & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
620 }
621 gdk_image_put_pixel( data_image, x, y, pixel );
622 break;
623 }
624 case 16:
625 {
626 // I actually don't know if for 16-bit displays, it is alway the green
627 // component or the second component which has 6 bits.
628 guint32 pixel = 0;
629 switch (b_o)
630 {
631 case RGB: pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
632 case RBG: pixel = ((r & 0xf8) << 8) | ((b & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
633 case GRB: pixel = ((g & 0xf8) << 8) | ((r & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
634 case GBR: pixel = ((g & 0xf8) << 8) | ((b & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
635 case BRG: pixel = ((b & 0xf8) << 8) | ((r & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
636 case BGR: pixel = ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
637 }
638 gdk_image_put_pixel( data_image, x, y, pixel );
639 break;
640 }
641 case 32:
642 case 24:
643 {
644 guint32 pixel = 0;
645 switch (b_o)
646 {
647 case RGB: pixel = (r << 16) | (g << 8) | b; break;
648 case RBG: pixel = (r << 16) | (b << 8) | g; break;
649 case BRG: pixel = (b << 16) | (r << 8) | g; break;
650 case BGR: pixel = (b << 16) | (g << 8) | r; break;
651 case GRB: pixel = (g << 16) | (r << 8) | b; break;
652 case GBR: pixel = (g << 16) | (b << 8) | r; break;
653 }
654 gdk_image_put_pixel( data_image, x, y, pixel );
655 }
656 default: break;
657 }
658 } // for
659 } // for
660
661 // Blit picture
662
663 GdkGC *data_gc = gdk_gc_new( GetPixmap() );
664
665 gdk_draw_image( GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
666
667 gdk_image_destroy( data_image );
668 gdk_gc_unref( data_gc );
669
670 // Blit mask
671
672 if (image.HasMask())
673 {
674 GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
675
676 gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
677
678 gdk_image_destroy( mask_image );
679 gdk_gc_unref( mask_gc );
680 }
681 }
682
683 return TRUE;
684 }
685
686 wxImage wxBitmap::ConvertToImage() const
687 {
688 // the colour used as transparent one in wxImage and the one it is replaced
689 // with when it really occurs in the bitmap
690 static const int MASK_RED = 1;
691 static const int MASK_GREEN = 2;
692 static const int MASK_BLUE = 3;
693 static const int MASK_BLUE_REPLACEMENT = 2;
694
695 wxImage image;
696
697 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
698
699 GdkImage *gdk_image = (GdkImage*) NULL;
700 if (GetPixmap())
701 {
702 gdk_image = gdk_image_get( GetPixmap(),
703 0, 0,
704 GetWidth(), GetHeight() );
705 }
706 else if (GetBitmap())
707 {
708 gdk_image = gdk_image_get( GetBitmap(),
709 0, 0,
710 GetWidth(), GetHeight() );
711 }
712 else
713 {
714 wxFAIL_MSG( wxT("Ill-formed bitmap") );
715 }
716
717 wxCHECK_MSG( gdk_image, wxNullImage, wxT("couldn't create image") );
718
719 image.Create( GetWidth(), GetHeight() );
720 char unsigned *data = image.GetData();
721
722 if (!data)
723 {
724 gdk_image_destroy( gdk_image );
725 wxFAIL_MSG( wxT("couldn't create image") );
726 return wxNullImage;
727 }
728
729 GdkImage *gdk_image_mask = (GdkImage*) NULL;
730 if (GetMask())
731 {
732 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
733 0, 0,
734 GetWidth(), GetHeight() );
735
736 image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
737 }
738
739 int bpp = -1;
740 int red_shift_right = 0;
741 int green_shift_right = 0;
742 int blue_shift_right = 0;
743 int red_shift_left = 0;
744 int green_shift_left = 0;
745 int blue_shift_left = 0;
746 bool use_shift = FALSE;
747
748 if (GetPixmap())
749 {
750 GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
751 if (visual == NULL)
752 visual = wxTheApp->GetGdkVisual();
753
754 bpp = visual->depth;
755 if (bpp == 16)
756 bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
757 red_shift_right = visual->red_shift;
758 red_shift_left = 8-visual->red_prec;
759 green_shift_right = visual->green_shift;
760 green_shift_left = 8-visual->green_prec;
761 blue_shift_right = visual->blue_shift;
762 blue_shift_left = 8-visual->blue_prec;
763
764 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
765 }
766 if (GetBitmap())
767 {
768 bpp = 1;
769 }
770
771
772 GdkColormap *cmap = gtk_widget_get_default_colormap();
773
774 long pos = 0;
775 for (int j = 0; j < GetHeight(); j++)
776 {
777 for (int i = 0; i < GetWidth(); i++)
778 {
779 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
780 if (bpp == 1)
781 {
782 if (pixel == 0)
783 {
784 data[pos] = 0;
785 data[pos+1] = 0;
786 data[pos+2] = 0;
787 }
788 else
789 {
790 data[pos] = 255;
791 data[pos+1] = 255;
792 data[pos+2] = 255;
793 }
794 }
795 else if (use_shift)
796 {
797 data[pos] = (pixel >> red_shift_right) << red_shift_left;
798 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
799 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
800 }
801 else if (cmap->colors)
802 {
803 data[pos] = cmap->colors[pixel].red >> 8;
804 data[pos+1] = cmap->colors[pixel].green >> 8;
805 data[pos+2] = cmap->colors[pixel].blue >> 8;
806 }
807 else
808 {
809 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
810 }
811
812 if (gdk_image_mask)
813 {
814 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
815 if (mask_pixel == 0)
816 {
817 data[pos] = MASK_RED;
818 data[pos+1] = MASK_GREEN;
819 data[pos+2] = MASK_BLUE;
820 }
821 else if ( data[pos] == MASK_RED &&
822 data[pos+1] == MASK_GREEN &&
823 data[pos+2] == MASK_BLUE )
824 {
825 data[pos+2] = MASK_BLUE_REPLACEMENT;
826 }
827 }
828
829 pos += 3;
830 }
831 }
832
833 gdk_image_destroy( gdk_image );
834 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
835
836 return image;
837 }
838
839 wxBitmap::wxBitmap( const wxBitmap& bmp )
840 : wxGDIObject()
841 {
842 Ref( bmp );
843 }
844
845 wxBitmap::wxBitmap( const wxString &filename, int type )
846 {
847 LoadFile( filename, type );
848 }
849
850 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
851 {
852 if ( width > 0 && height > 0 )
853 {
854 m_refData = new wxBitmapRefData();
855
856 M_BMPDATA->m_mask = (wxMask *) NULL;
857 M_BMPDATA->m_bitmap = gdk_bitmap_create_from_data
858 (
859 wxGetRootWindow()->window,
860 (gchar *) bits,
861 width,
862 height
863 );
864 M_BMPDATA->m_width = width;
865 M_BMPDATA->m_height = height;
866 M_BMPDATA->m_bpp = 1;
867
868 wxASSERT_MSG( M_BMPDATA->m_bitmap, wxT("couldn't create bitmap") );
869 }
870 }
871
872 wxBitmap::~wxBitmap()
873 {
874 }
875
876 wxBitmap& wxBitmap::operator = ( const wxBitmap& bmp )
877 {
878 if ( m_refData != bmp.m_refData )
879 Ref( bmp );
880
881 return *this;
882 }
883
884 bool wxBitmap::operator == ( const wxBitmap& bmp ) const
885 {
886 return m_refData == bmp.m_refData;
887 }
888
889 bool wxBitmap::operator != ( const wxBitmap& bmp ) const
890 {
891 return m_refData != bmp.m_refData;
892 }
893
894 bool wxBitmap::Ok() const
895 {
896 return (m_refData != NULL);
897 }
898
899 int wxBitmap::GetHeight() const
900 {
901 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
902
903 return M_BMPDATA->m_height;
904 }
905
906 int wxBitmap::GetWidth() const
907 {
908 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
909
910 return M_BMPDATA->m_width;
911 }
912
913 int wxBitmap::GetDepth() const
914 {
915 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
916
917 return M_BMPDATA->m_bpp;
918 }
919
920 wxMask *wxBitmap::GetMask() const
921 {
922 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
923
924 return M_BMPDATA->m_mask;
925 }
926
927 void wxBitmap::SetMask( wxMask *mask )
928 {
929 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
930
931 if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
932
933 M_BMPDATA->m_mask = mask;
934 }
935
936 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
937 {
938 *this = icon;
939 return TRUE;
940 }
941
942 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
943 {
944 wxCHECK_MSG( Ok() &&
945 (rect.x >= 0) && (rect.y >= 0) &&
946 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
947 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
948
949 wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
950 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
951
952 if (ret.GetPixmap())
953 {
954 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
955 gdk_draw_pixmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
956 gdk_gc_destroy( gc );
957 }
958 else
959 {
960 GdkGC *gc = gdk_gc_new( ret.GetBitmap() );
961 gdk_wx_draw_bitmap( ret.GetBitmap(), gc, GetBitmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
962 gdk_gc_destroy( gc );
963 }
964
965 if (GetMask())
966 {
967 wxMask *mask = new wxMask;
968 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
969
970 GdkGC *gc = gdk_gc_new( mask->m_bitmap );
971 gdk_wx_draw_bitmap( mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, 0, 0, rect.x, rect.y, rect.width, rect.height );
972 gdk_gc_destroy( gc );
973
974 ret.SetMask( mask );
975 }
976
977 return ret;
978 }
979
980 bool wxBitmap::SaveFile( const wxString &name, int type, wxPalette *WXUNUSED(palette) )
981 {
982 wxCHECK_MSG( Ok(), FALSE, wxT("invalid bitmap") );
983
984 // Try to save the bitmap via wxImage handlers:
985 {
986 wxImage image = ConvertToImage();
987 if (image.Ok()) return image.SaveFile( name, type );
988 }
989
990 return FALSE;
991 }
992
993 bool wxBitmap::LoadFile( const wxString &name, int type )
994 {
995 UnRef();
996
997 if (!wxFileExists(name))
998 return FALSE;
999
1000 GdkVisual *visual = wxTheApp->GetGdkVisual();
1001
1002 if (type == wxBITMAP_TYPE_XPM)
1003 {
1004 m_refData = new wxBitmapRefData();
1005
1006 GdkBitmap *mask = (GdkBitmap*) NULL;
1007
1008 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm
1009 (
1010 wxGetRootWindow()->window,
1011 &mask,
1012 NULL,
1013 name.fn_str()
1014 );
1015
1016 if (mask)
1017 {
1018 M_BMPDATA->m_mask = new wxMask();
1019 M_BMPDATA->m_mask->m_bitmap = mask;
1020 }
1021
1022 gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
1023
1024 M_BMPDATA->m_bpp = visual->depth;
1025 }
1026 else // try if wxImage can load it
1027 {
1028 wxImage image;
1029 if ( !image.LoadFile( name, type ) || !image.Ok() )
1030 return FALSE;
1031
1032 *this = wxBitmap(image);
1033 }
1034
1035 return TRUE;
1036 }
1037
1038 wxPalette *wxBitmap::GetPalette() const
1039 {
1040 if (!Ok())
1041 return (wxPalette *) NULL;
1042
1043 return M_BMPDATA->m_palette;
1044 }
1045
1046 void wxBitmap::SetHeight( int height )
1047 {
1048 if (!m_refData)
1049 m_refData = new wxBitmapRefData();
1050
1051 M_BMPDATA->m_height = height;
1052 }
1053
1054 void wxBitmap::SetWidth( int width )
1055 {
1056 if (!m_refData)
1057 m_refData = new wxBitmapRefData();
1058
1059 M_BMPDATA->m_width = width;
1060 }
1061
1062 void wxBitmap::SetDepth( int depth )
1063 {
1064 if (!m_refData)
1065 m_refData = new wxBitmapRefData();
1066
1067 M_BMPDATA->m_bpp = depth;
1068 }
1069
1070 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
1071 {
1072 if (!m_refData)
1073 m_refData = new wxBitmapRefData();
1074
1075 M_BMPDATA->m_pixmap = pixmap;
1076 }
1077
1078 void wxBitmap::SetBitmap( GdkPixmap *bitmap )
1079 {
1080 if (!m_refData)
1081 m_refData = new wxBitmapRefData();
1082
1083 M_BMPDATA->m_bitmap = bitmap;
1084 }
1085
1086 GdkPixmap *wxBitmap::GetPixmap() const
1087 {
1088 wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
1089
1090 return M_BMPDATA->m_pixmap;
1091 }
1092
1093 GdkBitmap *wxBitmap::GetBitmap() const
1094 {
1095 wxCHECK_MSG( Ok(), (GdkBitmap *) NULL, wxT("invalid bitmap") );
1096
1097 return M_BMPDATA->m_bitmap;
1098 }