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