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