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