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