wxX11:
[wxWidgets.git] / src / x11 / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: bitmap.cpp
3 // Purpose: wxBitmap
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "bitmap.h"
14 #endif
15
16 #include "wx/setup.h"
17 #include "wx/utils.h"
18 #include "wx/palette.h"
19 #include "wx/bitmap.h"
20 #include "wx/icon.h"
21 #include "wx/log.h"
22 #include "wx/control.h"
23 #include "wx/dcmemory.h"
24 #include "wx/image.h"
25 #include "wx/app.h"
26
27 #ifdef __VMS__
28 #pragma message disable nosimpint
29 #endif
30 #ifdef __VMS__
31 #pragma message enable nosimpint
32 #endif
33
34 #include "wx/x11/private.h"
35
36 #if wxHAVE_LIB_XPM
37 #include <X11/xpm.h>
38 #endif
39 #include <math.h>
40
41
42 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
43 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
44
45 wxBitmapRefData::wxBitmapRefData()
46 {
47 m_ok = FALSE;
48 m_width = 0;
49 m_height = 0;
50 m_depth = 0;
51 m_quality = 0;
52 m_numColors = 0;
53 m_bitmapMask = NULL;
54
55 m_pixmap = (WXPixmap) 0;
56 m_display = (WXDisplay*) 0;
57
58 m_freePixmap = TRUE; //TODO: necessary?
59 m_freeColors = (unsigned long*) 0;
60 m_freeColorsCount = 0;
61 }
62
63 wxBitmapRefData::~wxBitmapRefData()
64 {
65 if (m_pixmap && m_freePixmap)
66 XFreePixmap ((Display*) m_display, (Pixmap) m_pixmap);
67
68 if (m_freeColors)
69 {
70 int screen = DefaultScreen((Display*) m_display);
71 Colormap cmp = DefaultColormap((Display*) m_display,screen);
72 long llp;
73 for(llp = 0;llp < m_freeColorsCount;llp++)
74 XFreeColors((Display*) m_display, cmp, &m_freeColors[llp], 1, 0L);
75 delete m_freeColors;
76 };
77
78 if (m_bitmapMask)
79 delete m_bitmapMask;
80 m_bitmapMask = NULL;
81 }
82
83 wxList wxBitmap::sm_handlers;
84
85 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
86
87 wxBitmap::wxBitmap()
88 {
89 m_refData = NULL;
90 }
91
92 wxBitmap::~wxBitmap()
93 {
94 }
95
96 wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
97 {
98 m_refData = new wxBitmapRefData;
99
100 (void) Create((void*) bits, wxBITMAP_TYPE_XBM_DATA, width, height, depth);
101 }
102
103 wxBitmap::wxBitmap(int w, int h, int d)
104 {
105 (void)Create(w, h, d);
106 }
107
108 wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth)
109 {
110 (void) Create(data, type, width, height, depth);
111 }
112
113 wxBitmap::wxBitmap(const wxString& filename, long type)
114 {
115 LoadFile(filename, (int)type);
116 }
117
118 bool wxBitmap::Create(int w, int h, int d)
119 {
120 UnRef();
121
122 m_refData = new wxBitmapRefData;
123
124 if (d < 1)
125 d = wxDisplayDepth();
126
127 M_BITMAPDATA->m_width = w;
128 M_BITMAPDATA->m_height = h;
129 M_BITMAPDATA->m_depth = d;
130 M_BITMAPDATA->m_freePixmap = TRUE;
131
132 Display *dpy = (Display*) wxGetDisplay();
133
134 M_BITMAPDATA->m_display = dpy; /* MATTHEW: [4] Remember the display */
135
136 M_BITMAPDATA->m_pixmap = (WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
137 w, h, d);
138
139 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_pixmap != (WXPixmap) 0) ;
140 return M_BITMAPDATA->m_ok;
141 }
142
143 bool wxBitmap::LoadFile(const wxString& filename, long type)
144 {
145 UnRef();
146
147 m_refData = new wxBitmapRefData;
148
149 wxBitmapHandler *handler = FindHandler(type);
150
151 if ( handler == NULL ) {
152 wxImage image;
153 if (!image.LoadFile( filename, type )) return FALSE;
154 if (image.Ok())
155 {
156 *this = image.ConvertToBitmap();
157 return TRUE;
158 }
159 else return FALSE;
160 }
161
162 return handler->LoadFile(this, filename, type, -1, -1);
163 }
164
165 bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
166 {
167 UnRef();
168
169 m_refData = new wxBitmapRefData;
170
171 wxBitmapHandler *handler = FindHandler(type);
172
173 if ( handler == NULL ) {
174 wxLogWarning("no data bitmap handler for type %d defined.", type);
175
176 return FALSE;
177 }
178
179 return handler->Create(this, data, type, width, height, depth);
180 }
181
182 bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette)
183 {
184 wxBitmapHandler *handler = FindHandler(type);
185
186 if ( handler == NULL ) { // try wxImage
187 wxImage image( *this );
188 if (image.Ok()) return image.SaveFile( filename, type );
189 else return FALSE;
190 }
191
192 return handler->SaveFile(this, filename, type, palette);
193 }
194
195 void wxBitmap::SetWidth(int w)
196 {
197 if (!M_BITMAPDATA)
198 m_refData = new wxBitmapRefData;
199
200 M_BITMAPDATA->m_width = w;
201 }
202
203 void wxBitmap::SetHeight(int h)
204 {
205 if (!M_BITMAPDATA)
206 m_refData = new wxBitmapRefData;
207
208 M_BITMAPDATA->m_height = h;
209 }
210
211 void wxBitmap::SetDepth(int d)
212 {
213 if (!M_BITMAPDATA)
214 m_refData = new wxBitmapRefData;
215
216 M_BITMAPDATA->m_depth = d;
217 }
218
219 void wxBitmap::SetQuality(int q)
220 {
221 if (!M_BITMAPDATA)
222 m_refData = new wxBitmapRefData;
223
224 M_BITMAPDATA->m_quality = q;
225 }
226
227 void wxBitmap::SetOk(bool isOk)
228 {
229 if (!M_BITMAPDATA)
230 m_refData = new wxBitmapRefData;
231
232 M_BITMAPDATA->m_ok = isOk;
233 }
234
235 void wxBitmap::SetPalette(const wxPalette& palette)
236 {
237 if (!M_BITMAPDATA)
238 m_refData = new wxBitmapRefData;
239
240 M_BITMAPDATA->m_bitmapPalette = palette ;
241 }
242
243 void wxBitmap::SetMask(wxMask *mask)
244 {
245 if (!M_BITMAPDATA)
246 m_refData = new wxBitmapRefData;
247
248 M_BITMAPDATA->m_bitmapMask = mask ;
249 }
250
251 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
252 {
253 wxCHECK_MSG( Ok() &&
254 (rect.x >= 0) && (rect.y >= 0) &&
255 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
256 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
257
258 wxBitmap ret( rect.width, rect.height, 0 );
259 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
260
261 // The remaining still TODO
262 return ret;
263 }
264
265 void wxBitmap::AddHandler(wxBitmapHandler *handler)
266 {
267 sm_handlers.Append(handler);
268 }
269
270 void wxBitmap::InsertHandler(wxBitmapHandler *handler)
271 {
272 sm_handlers.Insert(handler);
273 }
274
275 bool wxBitmap::RemoveHandler(const wxString& name)
276 {
277 wxBitmapHandler *handler = FindHandler(name);
278 if ( handler )
279 {
280 sm_handlers.DeleteObject(handler);
281 return TRUE;
282 }
283 else
284 return FALSE;
285 }
286
287 wxBitmapHandler *wxBitmap::FindHandler(const wxString& name)
288 {
289 wxNode *node = sm_handlers.First();
290 while ( node )
291 {
292 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
293 if ( handler->GetName() == name )
294 return handler;
295 node = node->Next();
296 }
297 return NULL;
298 }
299
300 wxBitmapHandler *wxBitmap::FindHandler(const wxString& extension, long bitmapType)
301 {
302 wxNode *node = sm_handlers.First();
303 while ( node )
304 {
305 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
306 if ( handler->GetExtension() == extension &&
307 (bitmapType == -1 || handler->GetType() == bitmapType) )
308 return handler;
309 node = node->Next();
310 }
311 return NULL;
312 }
313
314 wxBitmapHandler *wxBitmap::FindHandler(long bitmapType)
315 {
316 wxNode *node = sm_handlers.First();
317 while ( node )
318 {
319 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
320 if (handler->GetType() == bitmapType)
321 return handler;
322 node = node->Next();
323 }
324 return NULL;
325 }
326
327 /*
328 * wxMask
329 */
330
331 wxMask::wxMask()
332 {
333 m_pixmap = (WXPixmap) 0;
334 }
335
336 // Construct a mask from a bitmap and a colour indicating
337 // the transparent area
338 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
339 {
340 m_pixmap = (WXPixmap) 0;
341
342 Create(bitmap, colour);
343 }
344
345 // Construct a mask from a bitmap and a palette index indicating
346 // the transparent area
347 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
348 {
349 m_pixmap = (WXPixmap) 0;
350
351 Create(bitmap, paletteIndex);
352 }
353
354 // Construct a mask from a mono bitmap (copies the bitmap).
355 wxMask::wxMask(const wxBitmap& bitmap)
356 {
357 m_pixmap = (WXPixmap) 0;
358
359 Create(bitmap);
360 }
361
362 wxMask::~wxMask()
363 {
364 // TODO: this may be the wrong display
365 if ( m_pixmap )
366 XFreePixmap ((Display*) wxGetDisplay(), (Pixmap) m_pixmap);
367 }
368
369 // Create a mask from a mono bitmap (copies the bitmap).
370 bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap))
371 {
372 // TODO
373 return FALSE;
374 }
375
376 // Create a mask from a bitmap and a palette index indicating
377 // the transparent area
378 bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap), int WXUNUSED(paletteIndex))
379 {
380 // TODO
381 return FALSE;
382 }
383
384 // Create a mask from a bitmap and a colour indicating
385 // the transparent area
386 bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap), const wxColour& WXUNUSED(colour))
387 {
388 // TODO
389 return FALSE;
390 }
391
392 /*
393 * wxBitmapHandler
394 */
395
396 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
397
398 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap), void *WXUNUSED(data), long WXUNUSED(type),
399 int WXUNUSED(width), int WXUNUSED(height), int WXUNUSED(depth))
400 {
401 return FALSE;
402 }
403
404 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), long WXUNUSED(type),
405 int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight))
406 {
407 return FALSE;
408 }
409
410 bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), int WXUNUSED(type),
411 const wxPalette *WXUNUSED(palette))
412 {
413 return FALSE;
414 }
415
416 /*
417 * Standard handlers
418 */
419
420 class WXDLLEXPORT wxXBMFileHandler: public wxBitmapHandler
421 {
422 DECLARE_DYNAMIC_CLASS(wxXBMFileHandler)
423 public:
424 inline wxXBMFileHandler()
425 {
426 m_name = "XBM file";
427 m_extension = "xbm";
428 m_type = wxBITMAP_TYPE_XBM;
429 };
430
431 virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
432 int desiredWidth, int desiredHeight);
433 };
434 IMPLEMENT_DYNAMIC_CLASS(wxXBMFileHandler, wxBitmapHandler)
435
436 bool wxXBMFileHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long WXUNUSED(flags),
437 int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight))
438 {
439 M_BITMAPHANDLERDATA->m_freePixmap = TRUE;
440
441 int hotX, hotY;
442 unsigned int w, h;
443 Pixmap pixmap;
444
445 Display *dpy = (Display*) wxGetDisplay();
446 M_BITMAPDATA->m_display = (WXDisplay*) dpy;
447
448 int value = XReadBitmapFile (dpy, RootWindow (dpy, DefaultScreen (dpy)),
449 (char*) (const char*) name, &w, &h, &pixmap, &hotX, &hotY);
450 M_BITMAPHANDLERDATA->m_width = w;
451 M_BITMAPHANDLERDATA->m_height = h;
452 M_BITMAPHANDLERDATA->m_depth = 1;
453 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) pixmap;
454
455 if ((value == BitmapFileInvalid) ||
456 (value == BitmapOpenFailed) ||
457 (value == BitmapNoMemory))
458 {
459 M_BITMAPHANDLERDATA->m_ok = FALSE;
460 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) 0;
461 }
462 else
463 M_BITMAPHANDLERDATA->m_ok = TRUE;
464
465 return M_BITMAPHANDLERDATA->m_ok ;
466 }
467
468 class WXDLLEXPORT wxXBMDataHandler: public wxBitmapHandler
469 {
470 DECLARE_DYNAMIC_CLASS(wxXBMDataHandler)
471 public:
472 inline wxXBMDataHandler()
473 {
474 m_name = "XBM data";
475 m_extension = "xbm";
476 m_type = wxBITMAP_TYPE_XBM_DATA;
477 };
478
479 virtual bool Create(wxBitmap *bitmap, void *data, long flags, int width, int height, int depth = 1);
480 };
481 IMPLEMENT_DYNAMIC_CLASS(wxXBMDataHandler, wxBitmapHandler)
482
483 bool wxXBMDataHandler::Create( wxBitmap *bitmap, void *data, long WXUNUSED(flags),
484 int width, int height, int WXUNUSED(depth))
485 {
486 M_BITMAPHANDLERDATA->m_width = width;
487 M_BITMAPHANDLERDATA->m_height = height;
488 M_BITMAPHANDLERDATA->m_depth = 1;
489 M_BITMAPHANDLERDATA->m_freePixmap = TRUE;
490
491 Display *dpy = (Display*) wxGetDisplay();
492 M_BITMAPHANDLERDATA->m_display = (WXDisplay*) dpy;
493
494 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) XCreateBitmapFromData (dpy, RootWindow (dpy, DefaultScreen (dpy)), (char*) data, width, height);
495 M_BITMAPHANDLERDATA->m_ok = (M_BITMAPHANDLERDATA->m_pixmap != (WXPixmap) 0) ;
496
497 return TRUE;
498 }
499
500 void wxBitmap::CleanUpHandlers()
501 {
502 wxNode *node = sm_handlers.First();
503 while ( node )
504 {
505 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
506 wxNode *next = node->Next();
507 delete handler;
508 delete node;
509 node = next;
510 }
511 }
512
513 void wxBitmap::InitStandardHandlers()
514 {
515 // Initialize all standard bitmap or derived class handlers here.
516 AddHandler(new wxXBMFileHandler);
517 AddHandler(new wxXBMDataHandler);
518
519 // XPM will be handled by wxImage
520 }
521
522 // Creates a bitmap with transparent areas drawn in
523 // the given colour.
524 wxBitmap wxCreateMaskedBitmap(const wxBitmap& bitmap, wxColour& colour)
525 {
526 wxBitmap newBitmap(bitmap.GetWidth(),
527 bitmap.GetHeight(),
528 bitmap.GetDepth());
529 wxMemoryDC destDC;
530 wxMemoryDC srcDC;
531 srcDC.SelectObject(bitmap);
532 destDC.SelectObject(newBitmap);
533
534 #if 0
535 wxBrush brush(colour, wxSOLID);
536 destDC.SetOptimization(FALSE);
537 destDC.SetBackground(brush);
538 destDC.Clear();
539 destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE);
540 #endif
541
542 return newBitmap;
543 }
544
545 //-----------------------------------------------------------------------------
546 // wxImage conversion routines
547 //-----------------------------------------------------------------------------
548
549 /*
550
551 Date: Wed, 05 Jan 2000 11:45:40 +0100
552 From: Frits Boel <boel@niob.knaw.nl>
553 To: julian.smart@ukonline.co.uk
554 Subject: Patch for Motif ConvertToBitmap
555
556 Hi Julian,
557
558 I've been working on a wxWin application for image processing. From the
559 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
560 till I looked in the source code of image.cpp. I saw that converting a
561 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
562 to the 256 colors of the palet. A very time-consuming piece of code!
563
564 Because I wanted a faster application, I've made a 'patch' for this. In
565 short: every pixel of the image is compared to a sorted list with
566 colors. If the color is found in the list, the palette entry is
567 returned; if the color is not found, the color palette is searched and
568 then the palette entry is returned and the color added to the sorted
569 list.
570
571 Maybe there is another method for this, namely changing the palette
572 itself (if the colors are known, as is the case with tiffs with a
573 colormap). I did not look at this, maybe someone else did?
574
575 The code of the patch is attached, have a look on it, and maybe you will
576 ship it with the next release of wxMotif?
577
578 Regards,
579
580 Frits Boel
581 Software engineer at Hubrecht Laboratory, The Netherlands.
582
583 */
584
585 class wxSearchColor
586 {
587 public:
588 wxSearchColor( void );
589 wxSearchColor( int size, XColor *colors );
590 ~wxSearchColor( void );
591
592 int SearchColor( int r, int g, int b );
593 private:
594 int AddColor( unsigned int value, int pos );
595
596 int size;
597 XColor *colors;
598 unsigned int *color;
599 int *entry;
600
601 int bottom;
602 int top;
603 };
604
605 wxSearchColor::wxSearchColor( void )
606 {
607 size = 0;
608 colors = (XColor*) NULL;
609 color = (unsigned int *) NULL;
610 entry = (int*) NULL;
611
612 bottom = 0;
613 top = 0;
614 }
615
616 wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
617 {
618 int i;
619 size = size_;
620 colors = colors_;
621 color = new unsigned int[size];
622 entry = new int [size];
623
624 for (i = 0; i < size; i++ ) {
625 entry[i] = -1;
626 }
627
628 bottom = top = ( size >> 1 );
629 }
630
631 wxSearchColor::~wxSearchColor( void )
632 {
633 if ( color ) delete color;
634 if ( entry ) delete entry;
635 }
636
637 int wxSearchColor::SearchColor( int r, int g, int b )
638 {
639 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
640 int begin = bottom;
641 int end = top;
642 int middle = 0;
643
644 while ( begin <= end ) {
645
646 middle = ( begin + end ) >> 1;
647
648 if ( value == color[middle] ) {
649 return( entry[middle] );
650 } else if ( value < color[middle] ) {
651 end = middle - 1;
652 } else {
653 begin = middle + 1;
654 }
655
656 }
657
658 return AddColor( value, middle );
659 }
660
661 int wxSearchColor::AddColor( unsigned int value, int pos )
662 {
663 int i;
664 int pixel = -1;
665 int max = 3 * (65536);
666 for ( i = 0; i < 256; i++ ) {
667 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
668 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
669 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
670 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
671 if (sum < max) { pixel = i; max = sum; }
672 }
673
674 if ( entry[pos] < 0 ) {
675 color[pos] = value;
676 entry[pos] = pixel;
677 } else if ( value < color[pos] ) {
678
679 if ( bottom > 0 ) {
680 for ( i = bottom; i < pos; i++ ) {
681 color[i-1] = color[i];
682 entry[i-1] = entry[i];
683 }
684 bottom--;
685 color[pos-1] = value;
686 entry[pos-1] = pixel;
687 } else if ( top < size-1 ) {
688 for ( i = top; i >= pos; i-- ) {
689 color[i+1] = color[i];
690 entry[i+1] = entry[i];
691 }
692 top++;
693 color[pos] = value;
694 entry[pos] = pixel;
695 }
696
697 } else {
698
699 if ( top < size-1 ) {
700 for ( i = top; i > pos; i-- ) {
701 color[i+1] = color[i];
702 entry[i+1] = entry[i];
703 }
704 top++;
705 color[pos+1] = value;
706 entry[pos+1] = pixel;
707 } else if ( bottom > 0 ) {
708 for ( i = bottom; i < pos; i++ ) {
709 color[i-1] = color[i];
710 entry[i-1] = entry[i];
711 }
712 bottom--;
713 color[pos] = value;
714 entry[pos] = pixel;
715 }
716
717 }
718
719 return( pixel );
720 }
721
722
723 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
724 {
725 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
726 wxCHECK_MSG( depth == -1, FALSE, wxT("invalid bitmap depth") )
727
728 m_refData = new wxBitmapRefData();
729
730 int width = image.GetWidth();
731 int height = image.GetHeight();
732
733 SetHeight( height );
734 SetWidth( width );
735
736 Display *dpy = (Display*) wxGetDisplay();
737 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
738 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
739
740 // Create image
741
742 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
743 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
744
745 Create( width, height, bpp );
746
747 // Create mask
748
749 XImage *mask_image = (XImage*) NULL;
750 if (image.HasMask())
751 {
752 mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 );
753 mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height );
754 }
755
756 // Retrieve depth info
757
758 XVisualInfo vinfo_template;
759 XVisualInfo *vi;
760
761 vinfo_template.visual = vis;
762 vinfo_template.visualid = XVisualIDFromVisual( vis );
763 vinfo_template.depth = bpp;
764 int nitem = 0;
765
766 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
767
768 wxCHECK_MSG( vi, FALSE, wxT("no visual") );
769
770 XFree( vi );
771
772 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
773 if (bpp < 8) bpp = 8;
774
775 // Render
776
777 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
778 byte_order b_o = RGB;
779
780 if (bpp >= 24)
781 {
782 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
783 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
784 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
785 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
786 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
787 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
788 }
789
790 int r_mask = image.GetMaskRed();
791 int g_mask = image.GetMaskGreen();
792 int b_mask = image.GetMaskBlue();
793
794 XColor colors[256];
795 if (bpp == 8)
796 {
797 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
798
799 for (int i = 0; i < 256; i++) colors[i].pixel = i;
800 XQueryColors( dpy, cmap, colors, 256 );
801 }
802
803 wxSearchColor scolor( 256, colors );
804 unsigned char* data = image.GetData();
805
806 bool hasMask = image.HasMask();
807
808 int index = 0;
809 for (int y = 0; y < height; y++)
810 {
811 for (int x = 0; x < width; x++)
812 {
813 int r = data[index];
814 index++;
815 int g = data[index];
816 index++;
817 int b = data[index];
818 index++;
819
820 if (hasMask)
821 {
822 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
823 XPutPixel( mask_image, x, y, 0 );
824 else
825 XPutPixel( mask_image, x, y, 1 );
826 }
827
828 switch (bpp)
829 {
830 case 8:
831 {
832 #if 0 // Old, slower code
833 int pixel = -1;
834 /*
835 if (wxTheApp->m_colorCube)
836 {
837 pixel = wxTheApp->m_colorCube
838 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
839 }
840 else
841 {
842 */
843 int max = 3 * (65536);
844 for (int i = 0; i < 256; i++)
845 {
846 int rdiff = (r << 8) - colors[i].red;
847 int gdiff = (g << 8) - colors[i].green;
848 int bdiff = (b << 8) - colors[i].blue;
849 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
850 if (sum < max) { pixel = i; max = sum; }
851 }
852 /*
853 }
854 */
855 #endif
856
857 // And this is all to get the 'right' color...
858 int pixel = scolor.SearchColor( r, g, b );
859 XPutPixel( data_image, x, y, pixel );
860 break;
861 }
862 case 15:
863 {
864 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
865 XPutPixel( data_image, x, y, pixel );
866 break;
867 }
868 case 16:
869 {
870 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
871 XPutPixel( data_image, x, y, pixel );
872 break;
873 }
874 case 32:
875 case 24:
876 {
877 int pixel = 0;
878 switch (b_o)
879 {
880 case RGB: pixel = (r << 16) | (g << 8) | b; break;
881 case RBG: pixel = (r << 16) | (b << 8) | g; break;
882 case BRG: pixel = (b << 16) | (r << 8) | g; break;
883 case BGR: pixel = (b << 16) | (g << 8) | r; break;
884 case GRB: pixel = (g << 16) | (r << 8) | b; break;
885 case GBR: pixel = (g << 16) | (b << 8) | r; break;
886 }
887 XPutPixel( data_image, x, y, pixel );
888 }
889 default: break;
890 }
891 } // for
892 } // for
893
894 // Blit picture
895
896 XGCValues gcvalues;
897 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
898 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
899 XPutImage( dpy, (Drawable)GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
900
901 XDestroyImage( data_image );
902 XFreeGC( dpy, gc );
903
904 // Blit mask
905 if (image.HasMask())
906 {
907 wxBitmap maskBitmap(width, height, 1);
908
909 GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), 0, (XGCValues*)NULL );
910 XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height );
911
912 XDestroyImage( mask_image );
913 XFreeGC( dpy, gcMask );
914
915 wxMask* mask = new wxMask;
916 mask->SetPixmap(maskBitmap.GetPixmap());
917
918 SetMask(mask);
919
920 maskBitmap.SetPixmapNull();
921 }
922
923
924 return TRUE;
925 }
926
927 wxImage wxBitmap::ConvertToImage() const
928 {
929 wxImage image;
930
931 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
932
933 Display *dpy = (Display*) wxGetDisplay();
934 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
935 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
936
937 XImage *ximage = XGetImage( dpy,
938 (Drawable)GetPixmap(),
939 0, 0,
940 GetWidth(), GetHeight(),
941 AllPlanes, ZPixmap );
942
943 wxCHECK_MSG( ximage, wxNullImage, wxT("couldn't create image") );
944
945 image.Create( GetWidth(), GetHeight() );
946 char unsigned *data = image.GetData();
947
948 if (!data)
949 {
950 XDestroyImage( ximage );
951 wxFAIL_MSG( wxT("couldn't create image") );
952 return wxNullImage;
953 }
954
955 /*
956 GdkImage *gdk_image_mask = (GdkImage*) NULL;
957 if (GetMask())
958 {
959 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
960 0, 0,
961 GetWidth(), GetHeight() );
962
963 image.SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
964 }
965 */
966
967 // Retrieve depth info
968
969 XVisualInfo vinfo_template;
970 XVisualInfo *vi;
971
972 vinfo_template.visual = vis;
973 vinfo_template.visualid = XVisualIDFromVisual( vis );
974 vinfo_template.depth = bpp;
975 int nitem = 0;
976
977 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
978
979 wxCHECK_MSG( vi, wxNullImage, wxT("no visual") );
980
981 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
982
983 XFree( vi );
984
985 XColor colors[256];
986 if (bpp == 8)
987 {
988 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
989
990 for (int i = 0; i < 256; i++) colors[i].pixel = i;
991 XQueryColors( dpy, cmap, colors, 256 );
992 }
993
994 long pos = 0;
995 for (int j = 0; j < GetHeight(); j++)
996 {
997 for (int i = 0; i < GetWidth(); i++)
998 {
999 int pixel = XGetPixel( ximage, i, j );
1000 if (bpp <= 8)
1001 {
1002 data[pos] = colors[pixel].red >> 8;
1003 data[pos+1] = colors[pixel].green >> 8;
1004 data[pos+2] = colors[pixel].blue >> 8;
1005 } else if (bpp == 15)
1006 {
1007 data[pos] = (pixel >> 7) & 0xf8;
1008 data[pos+1] = (pixel >> 2) & 0xf8;
1009 data[pos+2] = (pixel << 3) & 0xf8;
1010 } else if (bpp == 16)
1011 {
1012 data[pos] = (pixel >> 8) & 0xf8;
1013 data[pos+1] = (pixel >> 3) & 0xfc;
1014 data[pos+2] = (pixel << 3) & 0xf8;
1015 } else
1016 {
1017 data[pos] = (pixel >> 16) & 0xff;
1018 data[pos+1] = (pixel >> 8) & 0xff;
1019 data[pos+2] = pixel & 0xff;
1020 }
1021
1022 /*
1023 if (gdk_image_mask)
1024 {
1025 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1026 if (mask_pixel == 0)
1027 {
1028 data[pos] = 16;
1029 data[pos+1] = 16;
1030 data[pos+2] = 16;
1031 }
1032 }
1033 */
1034
1035 pos += 3;
1036 }
1037 }
1038
1039 XDestroyImage( ximage );
1040 /*
1041 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1042 */
1043
1044 return image;
1045 }
1046
1047 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
1048 {
1049 wxBitmap* bitmap = (wxBitmap*) & icon;
1050
1051 *this = *bitmap;
1052
1053 return TRUE;
1054 }