Now compiling
[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 wxBrush brush(colour, wxSOLID);
535 destDC.SetOptimization(FALSE);
536 destDC.SetBackground(brush);
537 destDC.Clear();
538 destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE);
539
540 return newBitmap;
541 }
542
543 //-----------------------------------------------------------------------------
544 // wxImage conversion routines
545 //-----------------------------------------------------------------------------
546
547 /*
548
549 Date: Wed, 05 Jan 2000 11:45:40 +0100
550 From: Frits Boel <boel@niob.knaw.nl>
551 To: julian.smart@ukonline.co.uk
552 Subject: Patch for Motif ConvertToBitmap
553
554 Hi Julian,
555
556 I've been working on a wxWin application for image processing. From the
557 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
558 till I looked in the source code of image.cpp. I saw that converting a
559 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
560 to the 256 colors of the palet. A very time-consuming piece of code!
561
562 Because I wanted a faster application, I've made a 'patch' for this. In
563 short: every pixel of the image is compared to a sorted list with
564 colors. If the color is found in the list, the palette entry is
565 returned; if the color is not found, the color palette is searched and
566 then the palette entry is returned and the color added to the sorted
567 list.
568
569 Maybe there is another method for this, namely changing the palette
570 itself (if the colors are known, as is the case with tiffs with a
571 colormap). I did not look at this, maybe someone else did?
572
573 The code of the patch is attached, have a look on it, and maybe you will
574 ship it with the next release of wxMotif?
575
576 Regards,
577
578 Frits Boel
579 Software engineer at Hubrecht Laboratory, The Netherlands.
580
581 */
582
583 class wxSearchColor
584 {
585 public:
586 wxSearchColor( void );
587 wxSearchColor( int size, XColor *colors );
588 ~wxSearchColor( void );
589
590 int SearchColor( int r, int g, int b );
591 private:
592 int AddColor( unsigned int value, int pos );
593
594 int size;
595 XColor *colors;
596 unsigned int *color;
597 int *entry;
598
599 int bottom;
600 int top;
601 };
602
603 wxSearchColor::wxSearchColor( void )
604 {
605 size = 0;
606 colors = (XColor*) NULL;
607 color = (unsigned int *) NULL;
608 entry = (int*) NULL;
609
610 bottom = 0;
611 top = 0;
612 }
613
614 wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
615 {
616 int i;
617 size = size_;
618 colors = colors_;
619 color = new unsigned int[size];
620 entry = new int [size];
621
622 for (i = 0; i < size; i++ ) {
623 entry[i] = -1;
624 }
625
626 bottom = top = ( size >> 1 );
627 }
628
629 wxSearchColor::~wxSearchColor( void )
630 {
631 if ( color ) delete color;
632 if ( entry ) delete entry;
633 }
634
635 int wxSearchColor::SearchColor( int r, int g, int b )
636 {
637 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
638 int begin = bottom;
639 int end = top;
640 int middle = 0;
641
642 while ( begin <= end ) {
643
644 middle = ( begin + end ) >> 1;
645
646 if ( value == color[middle] ) {
647 return( entry[middle] );
648 } else if ( value < color[middle] ) {
649 end = middle - 1;
650 } else {
651 begin = middle + 1;
652 }
653
654 }
655
656 return AddColor( value, middle );
657 }
658
659 int wxSearchColor::AddColor( unsigned int value, int pos )
660 {
661 int i;
662 int pixel = -1;
663 int max = 3 * (65536);
664 for ( i = 0; i < 256; i++ ) {
665 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
666 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
667 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
668 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
669 if (sum < max) { pixel = i; max = sum; }
670 }
671
672 if ( entry[pos] < 0 ) {
673 color[pos] = value;
674 entry[pos] = pixel;
675 } else if ( value < color[pos] ) {
676
677 if ( bottom > 0 ) {
678 for ( i = bottom; i < pos; i++ ) {
679 color[i-1] = color[i];
680 entry[i-1] = entry[i];
681 }
682 bottom--;
683 color[pos-1] = value;
684 entry[pos-1] = pixel;
685 } else if ( top < size-1 ) {
686 for ( i = top; i >= pos; i-- ) {
687 color[i+1] = color[i];
688 entry[i+1] = entry[i];
689 }
690 top++;
691 color[pos] = value;
692 entry[pos] = pixel;
693 }
694
695 } else {
696
697 if ( top < size-1 ) {
698 for ( i = top; i > pos; i-- ) {
699 color[i+1] = color[i];
700 entry[i+1] = entry[i];
701 }
702 top++;
703 color[pos+1] = value;
704 entry[pos+1] = pixel;
705 } else if ( bottom > 0 ) {
706 for ( i = bottom; i < pos; i++ ) {
707 color[i-1] = color[i];
708 entry[i-1] = entry[i];
709 }
710 bottom--;
711 color[pos] = value;
712 entry[pos] = pixel;
713 }
714
715 }
716
717 return( pixel );
718 }
719
720
721 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
722 {
723 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
724 wxCHECK_MSG( depth == -1, FALSE, wxT("invalid bitmap depth") )
725
726 m_refData = new wxBitmapRefData();
727
728 int width = image.GetWidth();
729 int height = image.GetHeight();
730
731 SetHeight( height );
732 SetWidth( width );
733
734 Display *dpy = (Display*) wxGetDisplay();
735 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
736 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
737
738 // Create image
739
740 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
741 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
742
743 Create( width, height, bpp );
744
745 // Create mask
746
747 XImage *mask_image = (XImage*) NULL;
748 if (image.HasMask())
749 {
750 mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 );
751 mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height );
752 }
753
754 // Retrieve depth info
755
756 XVisualInfo vinfo_template;
757 XVisualInfo *vi;
758
759 vinfo_template.visual = vis;
760 vinfo_template.visualid = XVisualIDFromVisual( vis );
761 vinfo_template.depth = bpp;
762 int nitem = 0;
763
764 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
765
766 wxCHECK_MSG( vi, FALSE, wxT("no visual") );
767
768 XFree( vi );
769
770 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
771 if (bpp < 8) bpp = 8;
772
773 // Render
774
775 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
776 byte_order b_o = RGB;
777
778 if (bpp >= 24)
779 {
780 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
781 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
782 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
783 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
784 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
785 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
786 }
787
788 int r_mask = image.GetMaskRed();
789 int g_mask = image.GetMaskGreen();
790 int b_mask = image.GetMaskBlue();
791
792 XColor colors[256];
793 if (bpp == 8)
794 {
795 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
796
797 for (int i = 0; i < 256; i++) colors[i].pixel = i;
798 XQueryColors( dpy, cmap, colors, 256 );
799 }
800
801 wxSearchColor scolor( 256, colors );
802 unsigned char* data = image.GetData();
803
804 bool hasMask = image.HasMask();
805
806 int index = 0;
807 for (int y = 0; y < height; y++)
808 {
809 for (int x = 0; x < width; x++)
810 {
811 int r = data[index];
812 index++;
813 int g = data[index];
814 index++;
815 int b = data[index];
816 index++;
817
818 if (hasMask)
819 {
820 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
821 XPutPixel( mask_image, x, y, 0 );
822 else
823 XPutPixel( mask_image, x, y, 1 );
824 }
825
826 switch (bpp)
827 {
828 case 8:
829 {
830 #if 0 // Old, slower code
831 int pixel = -1;
832 /*
833 if (wxTheApp->m_colorCube)
834 {
835 pixel = wxTheApp->m_colorCube
836 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
837 }
838 else
839 {
840 */
841 int max = 3 * (65536);
842 for (int i = 0; i < 256; i++)
843 {
844 int rdiff = (r << 8) - colors[i].red;
845 int gdiff = (g << 8) - colors[i].green;
846 int bdiff = (b << 8) - colors[i].blue;
847 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
848 if (sum < max) { pixel = i; max = sum; }
849 }
850 /*
851 }
852 */
853 #endif
854
855 // And this is all to get the 'right' color...
856 int pixel = scolor.SearchColor( r, g, b );
857 XPutPixel( data_image, x, y, pixel );
858 break;
859 }
860 case 15:
861 {
862 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
863 XPutPixel( data_image, x, y, pixel );
864 break;
865 }
866 case 16:
867 {
868 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
869 XPutPixel( data_image, x, y, pixel );
870 break;
871 }
872 case 32:
873 case 24:
874 {
875 int pixel = 0;
876 switch (b_o)
877 {
878 case RGB: pixel = (r << 16) | (g << 8) | b; break;
879 case RBG: pixel = (r << 16) | (b << 8) | g; break;
880 case BRG: pixel = (b << 16) | (r << 8) | g; break;
881 case BGR: pixel = (b << 16) | (g << 8) | r; break;
882 case GRB: pixel = (g << 16) | (r << 8) | b; break;
883 case GBR: pixel = (g << 16) | (b << 8) | r; break;
884 }
885 XPutPixel( data_image, x, y, pixel );
886 }
887 default: break;
888 }
889 } // for
890 } // for
891
892 // Blit picture
893
894 XGCValues gcvalues;
895 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
896 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
897 XPutImage( dpy, (Drawable)GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
898
899 XDestroyImage( data_image );
900 XFreeGC( dpy, gc );
901
902 // Blit mask
903 if (image.HasMask())
904 {
905 wxBitmap maskBitmap(width, height, 1);
906
907 GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), 0, (XGCValues*)NULL );
908 XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height );
909
910 XDestroyImage( mask_image );
911 XFreeGC( dpy, gcMask );
912
913 wxMask* mask = new wxMask;
914 mask->SetPixmap(maskBitmap.GetPixmap());
915
916 SetMask(mask);
917
918 maskBitmap.SetPixmapNull();
919 }
920
921
922 return TRUE;
923 }
924
925 wxImage wxBitmap::ConvertToImage() const
926 {
927 wxImage image;
928
929 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
930
931 Display *dpy = (Display*) wxGetDisplay();
932 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
933 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
934
935 XImage *ximage = XGetImage( dpy,
936 (Drawable)GetPixmap(),
937 0, 0,
938 GetWidth(), GetHeight(),
939 AllPlanes, ZPixmap );
940
941 wxCHECK_MSG( ximage, wxNullImage, wxT("couldn't create image") );
942
943 image.Create( GetWidth(), GetHeight() );
944 char unsigned *data = image.GetData();
945
946 if (!data)
947 {
948 XDestroyImage( ximage );
949 wxFAIL_MSG( wxT("couldn't create image") );
950 return wxNullImage;
951 }
952
953 /*
954 GdkImage *gdk_image_mask = (GdkImage*) NULL;
955 if (GetMask())
956 {
957 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
958 0, 0,
959 GetWidth(), GetHeight() );
960
961 image.SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
962 }
963 */
964
965 // Retrieve depth info
966
967 XVisualInfo vinfo_template;
968 XVisualInfo *vi;
969
970 vinfo_template.visual = vis;
971 vinfo_template.visualid = XVisualIDFromVisual( vis );
972 vinfo_template.depth = bpp;
973 int nitem = 0;
974
975 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
976
977 wxCHECK_MSG( vi, wxNullImage, wxT("no visual") );
978
979 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
980
981 XFree( vi );
982
983 XColor colors[256];
984 if (bpp == 8)
985 {
986 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
987
988 for (int i = 0; i < 256; i++) colors[i].pixel = i;
989 XQueryColors( dpy, cmap, colors, 256 );
990 }
991
992 long pos = 0;
993 for (int j = 0; j < GetHeight(); j++)
994 {
995 for (int i = 0; i < GetWidth(); i++)
996 {
997 int pixel = XGetPixel( ximage, i, j );
998 if (bpp <= 8)
999 {
1000 data[pos] = colors[pixel].red >> 8;
1001 data[pos+1] = colors[pixel].green >> 8;
1002 data[pos+2] = colors[pixel].blue >> 8;
1003 } else if (bpp == 15)
1004 {
1005 data[pos] = (pixel >> 7) & 0xf8;
1006 data[pos+1] = (pixel >> 2) & 0xf8;
1007 data[pos+2] = (pixel << 3) & 0xf8;
1008 } else if (bpp == 16)
1009 {
1010 data[pos] = (pixel >> 8) & 0xf8;
1011 data[pos+1] = (pixel >> 3) & 0xfc;
1012 data[pos+2] = (pixel << 3) & 0xf8;
1013 } else
1014 {
1015 data[pos] = (pixel >> 16) & 0xff;
1016 data[pos+1] = (pixel >> 8) & 0xff;
1017 data[pos+2] = pixel & 0xff;
1018 }
1019
1020 /*
1021 if (gdk_image_mask)
1022 {
1023 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1024 if (mask_pixel == 0)
1025 {
1026 data[pos] = 16;
1027 data[pos+1] = 16;
1028 data[pos+2] = 16;
1029 }
1030 }
1031 */
1032
1033 pos += 3;
1034 }
1035 }
1036
1037 XDestroyImage( ximage );
1038 /*
1039 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1040 */
1041
1042 return image;
1043 }
1044
1045 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
1046 {
1047 // TODO
1048 return FALSE;
1049 }