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