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