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