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