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