]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/bitmap.cpp
made wx-config work in place on systems where /bin/sh is a Bourne shell (such as...
[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"
83624f79 26
9e691f46 27#ifdef __WXGTK20__
5696ebb3 28#include "wx/rawbmp.h"
9e691f46
VZ
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();
902725ee 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
902725ee 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
902725ee 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
902725ee 209 if (!bitmap.Ok()) return false;
284b4c88 210
902725ee 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
902725ee 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
902725ee 223 return true;
91b8de8d
RR
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
902725ee 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
902725ee 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
902725ee 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
902725ee 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;
902725ee 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);
902725ee 379
feac7937 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 392 0, 0, width, height,
902725ee 393 clipx, clipy,
feac7937
VS
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
902725ee 412
feac7937
VS
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;
902725ee 429
feac7937
VS
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 }
902725ee 438
feac7937
VS
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 }
902725ee 471
feac7937 472 if (bpp == 1)
783da845 473 {
feac7937
VS
474 if (!pixval)
475 {
476 char bit=1;
d0ee33f5 477 char shift = bit << (w % 8);
feac7937
VS
478 outbyte |= shift;
479 }
902725ee 480
feac7937
VS
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 }
902725ee 495
783da845 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 }
902725ee 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 }
902725ee 509
feac7937
VS
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;
902725ee 523
feac7937
VS
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 }
902725ee 536
feac7937
VS
537 if (pixval)
538 {
539 char bit=1;
d0ee33f5 540 char shift = bit << (w % 8);
feac7937
VS
541 outbyte |= shift;
542 }
902725ee 543
feac7937
VS
544 if ((w+1)%8 == 0)
545 {
546 dst[h*dstbyteperline+w/8] = outbyte;
547 outbyte = 0;
548 }
549 }
902725ee 550
feac7937
VS
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 }
902725ee
WS
566
567 return bmp;
783da845
RR
568}
569
feac7937 570bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
b5f01ae0 571{
a11672a4
RR
572 UnRef();
573
902725ee
WS
574 wxCHECK_MSG( image.Ok(), false, wxT("invalid image") )
575 wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") )
b5f01ae0 576
feac7937
VS
577 if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
578 return false;
902725ee 579
feac7937 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();
902725ee 602
feac7937
VS
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}
902725ee 695
feac7937
VS
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();
902725ee 702
feac7937
VS
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 730 {
902725ee 731 static bool s_hasInitialized = false;
b5f01ae0 732
feac7937
VS
733 if (!s_hasInitialized)
734 {
735 gdk_rgb_init();
902725ee 736 s_hasInitialized = true;
feac7937 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 749 gdk_gc_unref( gc );
902725ee 750 return true;
feac7937 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 );
902725ee 905 break;
b5f01ae0 906 }
feac7937
VS
907 default: break;
908 }
909 } // for
910 } // for
b5f01ae0 911
feac7937 912 // Blit picture
b5f01ae0 913
feac7937 914 GdkGC *data_gc = gdk_gc_new( GetPixmap() );
b5f01ae0 915
feac7937 916 gdk_draw_image( GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
b5f01ae0 917
feac7937
VS
918 gdk_image_destroy( data_image );
919 gdk_gc_unref( data_gc );
b5f01ae0 920
feac7937 921 // Blit mask
b5f01ae0 922
feac7937
VS
923 if (image.HasMask())
924 {
925 GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
b5f01ae0 926
feac7937 927 gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
b5f01ae0 928
feac7937
VS
929 gdk_image_destroy( mask_image );
930 gdk_gc_unref( mask_gc );
b5f01ae0
VS
931 }
932
feac7937 933 return true;
b5f01ae0
VS
934}
935
feac7937
VS
936#ifdef __WXGTK20__
937bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
b5f01ae0 938{
feac7937
VS
939 int width = image.GetWidth();
940 int height = image.GetHeight();
2eefae6e 941
feac7937
VS
942 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
943 image.HasAlpha(),
944 8 /* bits per sample */,
945 width, height);
946 if (!pixbuf)
947 return false;
c2fa61e8 948
6db34764 949 wxASSERT( image.HasAlpha() ); // for now
feac7937
VS
950 wxASSERT( gdk_pixbuf_get_n_channels(pixbuf) == 4 );
951 wxASSERT( gdk_pixbuf_get_width(pixbuf) == width );
952 wxASSERT( gdk_pixbuf_get_height(pixbuf) == height );
902725ee 953
feac7937
VS
954 M_BMPDATA->m_pixbuf = pixbuf;
955 SetHeight(height);
956 SetWidth(width);
957 SetDepth(wxTheApp->GetGdkVisual()->depth);
902725ee 958
feac7937
VS
959 // Copy the data:
960 unsigned char *in = image.GetData();
961 unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
962 unsigned char *alpha = image.GetAlpha();
902725ee 963
feac7937 964 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
b5f01ae0 965
feac7937 966 for (int y = 0; y < height; y++, out += rowinc)
b5f01ae0 967 {
feac7937
VS
968 for (int x = 0; x < width; x++, alpha++, out += 4, in += 3)
969 {
970 out[0] = in[0];
971 out[1] = in[1];
972 out[2] = in[2];
973 out[3] = *alpha;
974 }
b5f01ae0 975 }
902725ee 976
feac7937
VS
977 return true;
978}
979#endif // __WXGTK20__
b5f01ae0 980
feac7937
VS
981wxImage wxBitmap::ConvertToImage() const
982{
983 wxImage image;
c2fa61e8 984
feac7937 985 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
902725ee 986
feac7937
VS
987 image.Create(GetWidth(), GetHeight());
988 unsigned char *data = image.GetData();
2eefae6e 989
b5f01ae0
VS
990 if (!data)
991 {
b5f01ae0
VS
992 wxFAIL_MSG( wxT("couldn't create image") );
993 return wxNullImage;
994 }
995
feac7937
VS
996#ifdef __WXGTK20__
997 if (HasPixbuf())
b5f01ae0 998 {
feac7937
VS
999 GdkPixbuf *pixbuf = GetPixbuf();
1000 wxASSERT( gdk_pixbuf_get_has_alpha(pixbuf) );
902725ee 1001
feac7937
VS
1002 int w = GetWidth();
1003 int h = GetHeight();
902725ee 1004
feac7937 1005 image.SetAlpha();
b5f01ae0 1006
feac7937
VS
1007 unsigned char *alpha = image.GetAlpha();
1008 unsigned char *in = gdk_pixbuf_get_pixels(pixbuf);
1009 unsigned char *out = data;
1010 int rowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * w;
b5f01ae0 1011
feac7937
VS
1012 for (int y = 0; y < h; y++, in += rowinc)
1013 {
1014 for (int x = 0; x < w; x++, in += 4, out += 3, alpha++)
1015 {
1016 out[0] = in[0];
1017 out[1] = in[1];
1018 out[2] = in[2];
1019 *alpha = in[3];
1020 }
1021 }
b5f01ae0 1022 }
feac7937
VS
1023 else
1024#endif // __WXGTK20__
b5f01ae0 1025 {
feac7937
VS
1026 // the colour used as transparent one in wxImage and the one it is
1027 // replaced with when it really occurs in the bitmap
1028 static const int MASK_RED = 1;
1029 static const int MASK_GREEN = 2;
1030 static const int MASK_BLUE = 3;
1031 static const int MASK_BLUE_REPLACEMENT = 2;
b5f01ae0 1032
feac7937 1033 GdkImage *gdk_image = (GdkImage*) NULL;
b5f01ae0 1034
feac7937
VS
1035 if (HasPixmap())
1036 {
1037 gdk_image = gdk_image_get( GetPixmap(),
1038 0, 0,
1039 GetWidth(), GetHeight() );
1040 }
1041 else if (GetBitmap())
1042 {
1043 gdk_image = gdk_image_get( GetBitmap(),
1044 0, 0,
1045 GetWidth(), GetHeight() );
1046 }
1047 else
1048 {
1049 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1050 }
b5f01ae0 1051
feac7937
VS
1052 wxCHECK_MSG( gdk_image, wxNullImage, wxT("couldn't create image") );
1053
1054 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1055 if (GetMask())
b5f01ae0 1056 {
feac7937
VS
1057 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
1058 0, 0,
1059 GetWidth(), GetHeight() );
1060
1061 image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
1062 }
1063
1064 int bpp = -1;
1065 int red_shift_right = 0;
1066 int green_shift_right = 0;
1067 int blue_shift_right = 0;
1068 int red_shift_left = 0;
1069 int green_shift_left = 0;
1070 int blue_shift_left = 0;
902725ee 1071 bool use_shift = false;
feac7937
VS
1072
1073 if (GetPixmap())
1074 {
1075 GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
1076 if (visual == NULL)
1077 visual = wxTheApp->GetGdkVisual();
1078
1079 bpp = visual->depth;
1080 if (bpp == 16)
1081 bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1082 red_shift_right = visual->red_shift;
1083 red_shift_left = 8-visual->red_prec;
1084 green_shift_right = visual->green_shift;
1085 green_shift_left = 8-visual->green_prec;
1086 blue_shift_right = visual->blue_shift;
1087 blue_shift_left = 8-visual->blue_prec;
1088
1089 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
1090 }
1091 if (GetBitmap())
1092 {
1093 bpp = 1;
1094 }
1095
1096
1097 GdkColormap *cmap = gtk_widget_get_default_colormap();
1098
1099 long pos = 0;
1100 for (int j = 0; j < GetHeight(); j++)
1101 {
1102 for (int i = 0; i < GetWidth(); i++)
8ab696e0 1103 {
feac7937
VS
1104 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
1105 if (bpp == 1)
b5f01ae0 1106 {
feac7937
VS
1107 if (pixel == 0)
1108 {
1109 data[pos] = 0;
1110 data[pos+1] = 0;
1111 data[pos+2] = 0;
1112 }
1113 else
1114 {
1115 data[pos] = 255;
1116 data[pos+1] = 255;
1117 data[pos+2] = 255;
1118 }
8ab696e0 1119 }
feac7937 1120 else if (use_shift)
8ab696e0 1121 {
feac7937
VS
1122 data[pos] = (pixel >> red_shift_right) << red_shift_left;
1123 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1124 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
8ab696e0 1125 }
feac7937 1126 else if (cmap->colors)
b5f01ae0 1127 {
feac7937
VS
1128 data[pos] = cmap->colors[pixel].red >> 8;
1129 data[pos+1] = cmap->colors[pixel].green >> 8;
1130 data[pos+2] = cmap->colors[pixel].blue >> 8;
2eefae6e 1131 }
feac7937 1132 else
2eefae6e 1133 {
feac7937 1134 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
b5f01ae0 1135 }
b5f01ae0 1136
feac7937
VS
1137 if (gdk_image_mask)
1138 {
1139 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1140 if (mask_pixel == 0)
1141 {
1142 data[pos] = MASK_RED;
1143 data[pos+1] = MASK_GREEN;
1144 data[pos+2] = MASK_BLUE;
1145 }
1146 else if ( data[pos] == MASK_RED &&
1147 data[pos+1] == MASK_GREEN &&
1148 data[pos+2] == MASK_BLUE )
1149 {
1150 data[pos+2] = MASK_BLUE_REPLACEMENT;
1151 }
1152 }
1153
1154 pos += 3;
1155 }
b5f01ae0 1156 }
b5f01ae0 1157
feac7937
VS
1158 gdk_image_destroy( gdk_image );
1159 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1160 }
b5f01ae0
VS
1161
1162 return image;
1163}
1164
c801d85f 1165wxBitmap::wxBitmap( const wxBitmap& bmp )
4611dd06 1166 : wxBitmapBase()
c801d85f 1167{
fd0eed64 1168 Ref( bmp );
ff7b1510 1169}
6f65e337 1170
4611dd06 1171wxBitmap::wxBitmap( const wxString &filename, wxBitmapType type )
c801d85f 1172{
fd0eed64 1173 LoadFile( filename, type );
ff7b1510 1174}
c801d85f 1175
debe6624 1176wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
6f65e337 1177{
3ebcd89d
VZ
1178 if ( width > 0 && height > 0 )
1179 {
1180 m_refData = new wxBitmapRefData();
6f65e337 1181
3ebcd89d
VZ
1182 M_BMPDATA->m_mask = (wxMask *) NULL;
1183 M_BMPDATA->m_bitmap = gdk_bitmap_create_from_data
1184 (
1185 wxGetRootWindow()->window,
1186 (gchar *) bits,
1187 width,
1188 height
1189 );
1190 M_BMPDATA->m_width = width;
1191 M_BMPDATA->m_height = height;
1192 M_BMPDATA->m_bpp = 1;
6f65e337 1193
3ebcd89d
VZ
1194 wxASSERT_MSG( M_BMPDATA->m_bitmap, wxT("couldn't create bitmap") );
1195 }
6f65e337 1196}
8bbe427f
VZ
1197
1198wxBitmap::~wxBitmap()
c801d85f 1199{
ff7b1510 1200}
8bbe427f 1201
c801d85f
KB
1202wxBitmap& wxBitmap::operator = ( const wxBitmap& bmp )
1203{
7ecb8b06
VZ
1204 if ( m_refData != bmp.m_refData )
1205 Ref( bmp );
1206
8bbe427f 1207 return *this;
ff7b1510 1208}
8bbe427f 1209
f6bcfd97 1210bool wxBitmap::operator == ( const wxBitmap& bmp ) const
c801d85f 1211{
8bbe427f 1212 return m_refData == bmp.m_refData;
ff7b1510 1213}
8bbe427f 1214
f6bcfd97 1215bool wxBitmap::operator != ( const wxBitmap& bmp ) const
c801d85f 1216{
8bbe427f 1217 return m_refData != bmp.m_refData;
ff7b1510 1218}
8bbe427f 1219
91b8de8d 1220bool wxBitmap::Ok() const
c801d85f 1221{
902725ee 1222 return (m_refData != NULL) &&
feac7937
VS
1223 (
1224#ifdef __WXGTK20__
1225 M_BMPDATA->m_pixbuf ||
1226#endif
902725ee 1227 M_BMPDATA->m_bitmap || M_BMPDATA->m_pixmap
feac7937 1228 );
ff7b1510 1229}
8bbe427f 1230
91b8de8d 1231int wxBitmap::GetHeight() const
c801d85f 1232{
223d09f6 1233 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
e55ad60e 1234
fd0eed64 1235 return M_BMPDATA->m_height;
ff7b1510 1236}
c801d85f 1237
91b8de8d 1238int wxBitmap::GetWidth() const
c801d85f 1239{
223d09f6 1240 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
8bbe427f 1241
fd0eed64 1242 return M_BMPDATA->m_width;
ff7b1510 1243}
c801d85f 1244
91b8de8d 1245int wxBitmap::GetDepth() const
c801d85f 1246{
223d09f6 1247 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
8bbe427f 1248
fd0eed64 1249 return M_BMPDATA->m_bpp;
ff7b1510 1250}
c801d85f 1251
91b8de8d 1252wxMask *wxBitmap::GetMask() const
c801d85f 1253{
223d09f6 1254 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
8bbe427f 1255
fd0eed64 1256 return M_BMPDATA->m_mask;
ff7b1510 1257}
c801d85f
KB
1258
1259void wxBitmap::SetMask( wxMask *mask )
1260{
223d09f6 1261 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
8bbe427f 1262
fd0eed64 1263 if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
8bbe427f 1264
fd0eed64 1265 M_BMPDATA->m_mask = mask;
ff7b1510 1266}
c801d85f 1267
db0aec83
VS
1268bool wxBitmap::CopyFromIcon(const wxIcon& icon)
1269{
1270 *this = icon;
902725ee 1271 return true;
db0aec83
VS
1272}
1273
17bec151
RR
1274wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
1275{
1276 wxCHECK_MSG( Ok() &&
13111b2a
VZ
1277 (rect.x >= 0) && (rect.y >= 0) &&
1278 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
17bec151 1279 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
13111b2a 1280
17bec151
RR
1281 wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
1282 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
13111b2a 1283
feac7937
VS
1284#ifdef __WXGTK20__
1285 if (HasPixbuf())
17bec151 1286 {
feac7937 1287 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
6db34764 1288 gdk_pixbuf_get_has_alpha(GetPixbuf()),
feac7937
VS
1289 8, GetWidth(), GetHeight());
1290 ret.SetPixbuf(pixbuf);
6db34764 1291 gdk_pixbuf_copy_area(GetPixbuf(),
feac7937
VS
1292 rect.x, rect.y, rect.width, rect.height,
1293 pixbuf, 0, 0);
17bec151
RR
1294 }
1295 else
feac7937 1296#endif // __WXGTK20__
17bec151 1297 {
feac7937
VS
1298 if (ret.GetPixmap())
1299 {
1300 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
1301 gdk_draw_pixmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1302 gdk_gc_destroy( gc );
1303 }
1304 else
1305 {
1306 GdkGC *gc = gdk_gc_new( ret.GetBitmap() );
1307 GdkColor col;
1308 col.pixel = 0xFFFFFF;
1309 gdk_gc_set_foreground( gc, &col );
1310 col.pixel = 0;
1311 gdk_gc_set_background( gc, &col );
1312 gdk_wx_draw_bitmap( ret.GetBitmap(), gc, GetBitmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1313 gdk_gc_destroy( gc );
1314 }
17bec151 1315 }
13111b2a 1316
17bec151
RR
1317 if (GetMask())
1318 {
1319 wxMask *mask = new wxMask;
c2fa61e8 1320 mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
13111b2a 1321
17bec151 1322 GdkGC *gc = gdk_gc_new( mask->m_bitmap );
f9ebac93
RR
1323 GdkColor col;
1324 col.pixel = 0xFFFFFF;
1325 gdk_gc_set_foreground( gc, &col );
1326 col.pixel = 0;
1327 gdk_gc_set_background( gc, &col );
1328 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
1329 gdk_gc_destroy( gc );
1330
1331 ret.SetMask( mask );
17bec151 1332 }
13111b2a 1333
17bec151
RR
1334 return ret;
1335}
1336
4611dd06 1337bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
c801d85f 1338{
902725ee 1339 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
8bbe427f 1340
b75dd496 1341 // Try to save the bitmap via wxImage handlers:
fd0eed64 1342 {
368d59f0 1343 wxImage image = ConvertToImage();
284b4c88 1344 if (image.Ok()) return image.SaveFile( name, type );
fd0eed64 1345 }
8bbe427f 1346
902725ee 1347 return false;
ff7b1510 1348}
c801d85f 1349
4611dd06 1350bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
c801d85f 1351{
fd0eed64 1352 UnRef();
8bbe427f 1353
3ebcd89d 1354 if (!wxFileExists(name))
902725ee 1355 return false;
8bbe427f 1356
005f5d18 1357 GdkVisual *visual = wxTheApp->GetGdkVisual();
c2fa61e8 1358
fd0eed64
RR
1359 if (type == wxBITMAP_TYPE_XPM)
1360 {
1361 m_refData = new wxBitmapRefData();
8bbe427f 1362
fd0eed64 1363 GdkBitmap *mask = (GdkBitmap*) NULL;
8bbe427f 1364
3ebcd89d
VZ
1365 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm
1366 (
1367 wxGetRootWindow()->window,
1368 &mask,
1369 NULL,
1370 name.fn_str()
1371 );
8bbe427f 1372
fd0eed64
RR
1373 if (mask)
1374 {
1375 M_BMPDATA->m_mask = new wxMask();
1376 M_BMPDATA->m_mask->m_bitmap = mask;
1377 }
8bbe427f 1378
fd0eed64 1379 gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
c2fa61e8 1380
103aab26 1381 M_BMPDATA->m_bpp = visual->depth;
fd0eed64 1382 }
b75dd496 1383 else // try if wxImage can load it
fd0eed64
RR
1384 {
1385 wxImage image;
3ebcd89d 1386 if ( !image.LoadFile( name, type ) || !image.Ok() )
902725ee 1387 return false;
3ebcd89d
VZ
1388
1389 *this = wxBitmap(image);
fd0eed64 1390 }
8bbe427f 1391
902725ee 1392 return true;
ff7b1510 1393}
8bbe427f 1394
91b8de8d 1395wxPalette *wxBitmap::GetPalette() const
c801d85f 1396{
3ebcd89d
VZ
1397 if (!Ok())
1398 return (wxPalette *) NULL;
8bbe427f 1399
fd0eed64 1400 return M_BMPDATA->m_palette;
ff7b1510 1401}
c801d85f 1402
4611dd06
RR
1403void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
1404{
1405 // TODO
1406}
1407
4bc67cc5
RR
1408void wxBitmap::SetHeight( int height )
1409{
3ebcd89d
VZ
1410 if (!m_refData)
1411 m_refData = new wxBitmapRefData();
4bc67cc5
RR
1412
1413 M_BMPDATA->m_height = height;
1414}
1415
1416void wxBitmap::SetWidth( int width )
1417{
3ebcd89d
VZ
1418 if (!m_refData)
1419 m_refData = new wxBitmapRefData();
4bc67cc5
RR
1420
1421 M_BMPDATA->m_width = width;
1422}
1423
1424void wxBitmap::SetDepth( int depth )
1425{
3ebcd89d
VZ
1426 if (!m_refData)
1427 m_refData = new wxBitmapRefData();
4bc67cc5
RR
1428
1429 M_BMPDATA->m_bpp = depth;
1430}
1431
1432void wxBitmap::SetPixmap( GdkPixmap *pixmap )
1433{
3ebcd89d
VZ
1434 if (!m_refData)
1435 m_refData = new wxBitmapRefData();
4bc67cc5
RR
1436
1437 M_BMPDATA->m_pixmap = pixmap;
6db34764
VS
1438#ifdef __WXGTK20__
1439 PurgeOtherRepresentations(Pixmap);
1440#endif
4bc67cc5
RR
1441}
1442
82ea63e6
RR
1443void wxBitmap::SetBitmap( GdkPixmap *bitmap )
1444{
3ebcd89d
VZ
1445 if (!m_refData)
1446 m_refData = new wxBitmapRefData();
82ea63e6
RR
1447
1448 M_BMPDATA->m_bitmap = bitmap;
6db34764
VS
1449#ifdef __WXGTK20__
1450 PurgeOtherRepresentations(Pixmap);
1451#endif
82ea63e6
RR
1452}
1453
91b8de8d 1454GdkPixmap *wxBitmap::GetPixmap() const
c801d85f 1455{
223d09f6 1456 wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
8bbe427f 1457
feac7937
VS
1458#ifdef __WXGTK20__
1459 // create the pixmap on the fly if we use Pixbuf representation:
1460 if (HasPixbuf() && !HasPixmap())
1461 {
70dcce79
VS
1462 delete M_BMPDATA->m_mask;
1463 M_BMPDATA->m_mask = new wxMask();
feac7937
VS
1464 gdk_pixbuf_render_pixmap_and_mask(M_BMPDATA->m_pixbuf,
1465 &M_BMPDATA->m_pixmap,
70dcce79 1466 &M_BMPDATA->m_mask->m_bitmap,
feac7937
VS
1467 128 /*threshold*/);
1468 }
1469#endif // __WXGTK20__
1470
fd0eed64 1471 return M_BMPDATA->m_pixmap;
ff7b1510 1472}
8bbe427f 1473
feac7937
VS
1474bool wxBitmap::HasPixmap() const
1475{
1476 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1477
1478 return M_BMPDATA->m_pixmap != NULL;
1479}
1480
91b8de8d 1481GdkBitmap *wxBitmap::GetBitmap() const
6f65e337 1482{
223d09f6 1483 wxCHECK_MSG( Ok(), (GdkBitmap *) NULL, wxT("invalid bitmap") );
8bbe427f 1484
fd0eed64 1485 return M_BMPDATA->m_bitmap;
ff7b1510 1486}
feac7937
VS
1487
1488#ifdef __WXGTK20__
1489GdkPixbuf *wxBitmap::GetPixbuf() const
1490{
1491 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
1492
6db34764
VS
1493 if (HasPixmap() && !HasPixbuf())
1494 {
1495 int width = GetWidth();
1496 int height = GetHeight();
902725ee 1497
6db34764
VS
1498 GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1499 GetMask() != NULL,
1500 8, width, height);
902725ee 1501 M_BMPDATA->m_pixbuf =
6db34764
VS
1502 gdk_pixbuf_get_from_drawable(pixbuf, M_BMPDATA->m_pixmap, NULL,
1503 0, 0, 0, 0, width, height);
902725ee 1504
6db34764
VS
1505 // apply the mask to created pixbuf:
1506 if (M_BMPDATA->m_pixbuf && M_BMPDATA->m_mask)
1507 {
902725ee 1508 GdkPixbuf *pmask =
6db34764
VS
1509 gdk_pixbuf_get_from_drawable(NULL,
1510 M_BMPDATA->m_mask->GetBitmap(),
1511 NULL,
1512 0, 0, 0, 0, width, height);
1513 if (pmask)
1514 {
1515 guchar *bmp = gdk_pixbuf_get_pixels(pixbuf);
1516 guchar *mask = gdk_pixbuf_get_pixels(pmask);
1517 int bmprowinc = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
1518 int maskrowinc = gdk_pixbuf_get_rowstride(pmask) - 3 * width;
1519
1520 for (int y = 0; y < height;
1521 y++, bmp += bmprowinc, mask += maskrowinc)
1522 {
1523 for (int x = 0; x < width; x++, bmp += 4, mask += 3)
1524 {
1525 if (mask[0] == 0 /*black pixel*/)
1526 bmp[3] = 0;
1527 }
1528 }
902725ee 1529
6db34764
VS
1530 gdk_pixbuf_unref(pmask);
1531 }
1532 }
1533 }
1534
feac7937
VS
1535 return M_BMPDATA->m_pixbuf;
1536}
1537
1538bool wxBitmap::HasPixbuf() const
1539{
1540 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1541
1542 return M_BMPDATA->m_pixbuf != NULL;
1543}
1544
1545void wxBitmap::SetPixbuf( GdkPixbuf *pixbuf )
1546{
1547 if (!m_refData)
1548 m_refData = new wxBitmapRefData();
1549
1550 M_BMPDATA->m_pixbuf = pixbuf;
6db34764 1551 PurgeOtherRepresentations(Pixbuf);
feac7937
VS
1552}
1553
1554void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
1555{
1556 if (keep == Pixmap && HasPixbuf())
1557 {
1558 gdk_pixbuf_unref( M_BMPDATA->m_pixbuf );
1559 M_BMPDATA->m_pixbuf = NULL;
1560 }
1561 if (keep == Pixbuf && HasPixmap())
1562 {
1563 gdk_pixmap_unref( M_BMPDATA->m_pixmap );
1564 M_BMPDATA->m_pixmap = NULL;
1565 }
1566}
1567
709feaf7
RR
1568#endif // __WXGTK20__
1569
284f2b59
RR
1570void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
1571{
1572#ifdef __WXGTK20__
1573 if (bpp != 32)
1574 return NULL;
902725ee 1575
284f2b59
RR
1576 GdkPixbuf *pixbuf = GetPixbuf();
1577 if (!pixbuf)
1578 return NULL;
1579
902725ee 1580#if 0
284f2b59
RR
1581 if (gdk_pixbuf_get_has_alpha( pixbuf ))
1582 wxPrintf( wxT("Has alpha\n") );
1583 else
1584 wxPrintf( wxT("No alpha.\n") );
1585#endif
1586
902725ee
WS
1587 data.m_height = gdk_pixbuf_get_height( pixbuf );
1588 data.m_width = gdk_pixbuf_get_width( pixbuf );
1589 data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
1590
284f2b59
RR
1591 return gdk_pixbuf_get_pixels( pixbuf );
1592#else
1593 return NULL;
902725ee 1594#endif
284f2b59
RR
1595}
1596
1597void wxBitmap::UngetRawData(wxPixelDataBase& data)
1598{
1599}
1600
0ff2a74d 1601
902725ee 1602bool wxBitmap::HasAlpha() const
0ff2a74d
RR
1603{
1604#ifdef __WXGTK20__
1605 return HasPixbuf();
1606#else
1607 return false;
1608#endif
1609}
1610
1611void wxBitmap::UseAlpha()
902725ee 1612{
0ff2a74d
RR
1613#ifdef __WXGTK20__
1614 GetPixbuf();
1615#endif
1616}
1617
4b61c88d
RR
1618//-----------------------------------------------------------------------------
1619// wxBitmapHandler
1620//-----------------------------------------------------------------------------
1621
1622IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler,wxBitmapHandlerBase)
1623
1624wxBitmapHandler::~wxBitmapHandler()
1625{
1626}
1627
1628bool wxBitmapHandler::Create(wxBitmap *bitmap, void *data, long type, int width, int height, int depth)
1629{
902725ee 1630 return false;
4b61c88d
RR
1631}
1632
1633bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1634 int desiredWidth, int desiredHeight)
1635{
902725ee 1636 return false;
4b61c88d
RR
1637}
1638
1639bool wxBitmapHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette)
1640{
902725ee 1641 return false;
4b61c88d
RR
1642}
1643
1644/* static */ void wxBitmap::InitStandardHandlers()
1645{
1646 // TODO: Insert handler based on GdkPixbufs handler later
1647}
1648
1649