]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
Added wxEnableTopLevelWindows(bool enable) for use by wxSafeYield().
[wxWidgets.git] / src / common / image.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: image.cpp
3 // Purpose: wxImage
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "image.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/image.h"
22 #include "wx/bitmap.h"
23 #include "wx/debug.h"
24 #include "wx/log.h"
25 #include "wx/app.h"
26 #include "wx/filefn.h"
27 #include "wx/wfstream.h"
28 #include "wx/intl.h"
29 #include "wx/module.h"
30
31 // For memcpy
32 #include <string.h>
33
34 #ifdef __SALFORDC__
35 #ifdef FAR
36 #undef FAR
37 #endif
38 #endif
39
40 #ifdef __WXMSW__
41 #include <windows.h>
42 #endif
43
44 //-----------------------------------------------------------------------------
45 // wxImage
46 //-----------------------------------------------------------------------------
47
48 class wxImageRefData: public wxObjectRefData
49 {
50
51 public:
52 wxImageRefData(void);
53 ~wxImageRefData(void);
54
55 int m_width;
56 int m_height;
57 unsigned char *m_data;
58 bool m_hasMask;
59 unsigned char m_maskRed,m_maskGreen,m_maskBlue;
60 bool m_ok;
61 };
62
63 wxImageRefData::wxImageRefData(void)
64 {
65 m_width = 0;
66 m_height = 0;
67 m_data = (unsigned char*) NULL;
68 m_ok = FALSE;
69 m_maskRed = 0;
70 m_maskGreen = 0;
71 m_maskBlue = 0;
72 m_hasMask = FALSE;
73 }
74
75 wxImageRefData::~wxImageRefData(void)
76 {
77 if (m_data) free( m_data );
78 }
79
80 wxList wxImage::sm_handlers;
81
82 //-----------------------------------------------------------------------------
83
84 #define M_IMGDATA ((wxImageRefData *)m_refData)
85
86 #if !USE_SHARED_LIBRARIES
87 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
88 #endif
89
90 wxImage::wxImage()
91 {
92 }
93
94 wxImage::wxImage( int width, int height )
95 {
96 Create( width, height );
97 }
98
99 wxImage::wxImage( const wxString& name, long type )
100 {
101 LoadFile( name, type );
102 }
103
104 wxImage::wxImage( const wxString& name, const wxString& mimetype )
105 {
106 LoadFile( name, mimetype );
107 }
108
109 #if wxUSE_STREAMS
110 wxImage::wxImage( wxInputStream& stream, long type )
111 {
112 LoadFile( stream, type );
113 }
114
115 wxImage::wxImage( wxInputStream& stream, const wxString& mimetype )
116 {
117 LoadFile( stream, mimetype );
118 }
119 #endif // wxUSE_STREAMS
120
121 wxImage::wxImage( const wxImage& image )
122 {
123 Ref(image);
124 }
125
126 wxImage::wxImage( const wxImage* image )
127 {
128 if (image) Ref(*image);
129 }
130
131 void wxImage::Create( int width, int height )
132 {
133 m_refData = new wxImageRefData();
134
135 M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
136 if (M_IMGDATA->m_data)
137 {
138 for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
139
140 M_IMGDATA->m_width = width;
141 M_IMGDATA->m_height = height;
142 M_IMGDATA->m_ok = TRUE;
143 }
144 else
145 {
146 UnRef();
147 }
148 }
149
150 void wxImage::Destroy()
151 {
152 UnRef();
153 }
154
155 wxImage wxImage::Scale( int width, int height )
156 {
157 wxImage image;
158
159 wxCHECK_MSG( Ok(), image, _T("invalid image") );
160
161 wxCHECK_MSG( (width > 0) && (height > 0), image, _T("invalid image size") );
162
163 image.Create( width, height );
164
165 char unsigned *data = image.GetData();
166
167 wxCHECK_MSG( data, image, _T("unable to create image") );
168
169 if (M_IMGDATA->m_hasMask)
170 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
171
172 long old_height = M_IMGDATA->m_height;
173 long old_width = M_IMGDATA->m_width;
174
175 char unsigned *source_data = M_IMGDATA->m_data;
176 char unsigned *target_data = data;
177
178 for (long j = 0; j < height; j++)
179 {
180 long y_offset = (j * old_height / height) * old_width;
181
182 for (long i = 0; i < width; i++)
183 {
184 memcpy( target_data,
185 source_data + 3*(y_offset + ((i * old_width )/ width)),
186 3 );
187 target_data += 3;
188 }
189 }
190
191 return image;
192 }
193
194 void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
195 {
196 wxCHECK_RET( Ok(), _T("invalid image") );
197
198 int w = M_IMGDATA->m_width;
199 int h = M_IMGDATA->m_height;
200
201 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), _T("invalid image index") );
202
203 long pos = (y * w + x) * 3;
204
205 M_IMGDATA->m_data[ pos ] = r;
206 M_IMGDATA->m_data[ pos+1 ] = g;
207 M_IMGDATA->m_data[ pos+2 ] = b;
208 }
209
210 unsigned char wxImage::GetRed( int x, int y )
211 {
212 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
213
214 int w = M_IMGDATA->m_width;
215 int h = M_IMGDATA->m_height;
216
217 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, _T("invalid image index") );
218
219 long pos = (y * w + x) * 3;
220
221 return M_IMGDATA->m_data[pos];
222 }
223
224 unsigned char wxImage::GetGreen( int x, int y )
225 {
226 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
227
228 int w = M_IMGDATA->m_width;
229 int h = M_IMGDATA->m_height;
230
231 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, _T("invalid image index") );
232
233 long pos = (y * w + x) * 3;
234
235 return M_IMGDATA->m_data[pos+1];
236 }
237
238 unsigned char wxImage::GetBlue( int x, int y )
239 {
240 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
241
242 int w = M_IMGDATA->m_width;
243 int h = M_IMGDATA->m_height;
244
245 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, _T("invalid image index") );
246
247 long pos = (y * w + x) * 3;
248
249 return M_IMGDATA->m_data[pos+2];
250 }
251
252 bool wxImage::Ok() const
253 {
254 return (M_IMGDATA && M_IMGDATA->m_ok);
255 }
256
257 char unsigned *wxImage::GetData() const
258 {
259 wxCHECK_MSG( Ok(), (char unsigned *)NULL, _T("invalid image") );
260
261 return M_IMGDATA->m_data;
262 }
263
264 void wxImage::SetData( char unsigned *data )
265 {
266 wxCHECK_RET( Ok(), _T("invalid image") );
267
268 memcpy(M_IMGDATA->m_data, data, M_IMGDATA->m_width * M_IMGDATA->m_height * 3);
269 }
270
271 void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
272 {
273 wxCHECK_RET( Ok(), _T("invalid image") );
274
275 M_IMGDATA->m_maskRed = r;
276 M_IMGDATA->m_maskGreen = g;
277 M_IMGDATA->m_maskBlue = b;
278 M_IMGDATA->m_hasMask = TRUE;
279 }
280
281 unsigned char wxImage::GetMaskRed() const
282 {
283 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
284
285 return M_IMGDATA->m_maskRed;
286 }
287
288 unsigned char wxImage::GetMaskGreen() const
289 {
290 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
291
292 return M_IMGDATA->m_maskGreen;
293 }
294
295 unsigned char wxImage::GetMaskBlue() const
296 {
297 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
298
299 return M_IMGDATA->m_maskBlue;
300 }
301
302 void wxImage::SetMask( bool mask )
303 {
304 wxCHECK_RET( Ok(), _T("invalid image") );
305
306 M_IMGDATA->m_hasMask = mask;
307 }
308
309 bool wxImage::HasMask() const
310 {
311 wxCHECK_MSG( Ok(), FALSE, _T("invalid image") );
312
313 return M_IMGDATA->m_hasMask;
314 }
315
316 int wxImage::GetWidth() const
317 {
318 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
319
320 return M_IMGDATA->m_width;
321 }
322
323 int wxImage::GetHeight() const
324 {
325 wxCHECK_MSG( Ok(), 0, _T("invalid image") );
326
327 return M_IMGDATA->m_height;
328 }
329
330 bool wxImage::LoadFile( const wxString& filename, long type )
331 {
332 #if wxUSE_STREAMS
333 if (wxFileExists(filename))
334 {
335 wxFileInputStream stream(filename);
336 return LoadFile(stream, type);
337 }
338
339 else {
340 wxLogError( _T("Can't load image from file '%s': file does not exist."), filename.c_str() );
341
342 return FALSE;
343 }
344 #else // !wxUSE_STREAMS
345 return FALSE;
346 #endif // wxUSE_STREAMS
347 }
348
349 bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype )
350 {
351 #if wxUSE_STREAMS
352 if (wxFileExists(filename))
353 {
354 wxFileInputStream stream(filename);
355 return LoadFile(stream, mimetype);
356 }
357
358 else {
359 wxLogError( _T("Can't load image from file '%s': file does not exist."), filename.c_str() );
360
361 return FALSE;
362 }
363 #else // !wxUSE_STREAMS
364 return FALSE;
365 #endif // wxUSE_STREAMS
366 }
367
368 bool wxImage::SaveFile( const wxString& filename, int type )
369 {
370 #if wxUSE_STREAMS
371 wxFileOutputStream stream(filename);
372
373 if ( stream.LastError() == wxStream_NOERROR )
374 return SaveFile(stream, type);
375 else
376 #endif // wxUSE_STREAMS
377 return FALSE;
378 }
379
380 bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype )
381 {
382 #if wxUSE_STREAMS
383 wxFileOutputStream stream(filename);
384
385 if ( stream.LastError() == wxStream_NOERROR )
386 return SaveFile(stream, mimetype);
387 else
388 #endif // wxUSE_STREAMS
389 return FALSE;
390 }
391
392 #if wxUSE_STREAMS
393 bool wxImage::LoadFile( wxInputStream& stream, long type )
394 {
395 UnRef();
396
397 m_refData = new wxImageRefData;
398
399 wxImageHandler *handler = FindHandler(type);
400
401 if (handler == NULL)
402 {
403 wxLogWarning( _T("No image handler for type %d defined."), type );
404
405 return FALSE;
406 }
407
408 return handler->LoadFile( this, stream );
409 }
410
411 bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype )
412 {
413 UnRef();
414
415 m_refData = new wxImageRefData;
416
417 wxImageHandler *handler = FindHandlerMime(mimetype);
418
419 if (handler == NULL)
420 {
421 wxLogWarning( _T("No image handler for type %s defined."), mimetype.GetData() );
422
423 return FALSE;
424 }
425
426 return handler->LoadFile( this, stream );
427 }
428
429 bool wxImage::SaveFile( wxOutputStream& stream, int type )
430 {
431 wxCHECK_MSG( Ok(), FALSE, _T("invalid image") );
432
433 wxImageHandler *handler = FindHandler(type);
434
435 if (handler == NULL)
436 {
437 wxLogWarning( _T("No image handler for type %d defined."), type );
438
439 return FALSE;
440 }
441
442 return handler->SaveFile( this, stream );
443 }
444
445 bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype )
446 {
447 wxCHECK_MSG( Ok(), FALSE, _T("invalid image") );
448
449 wxImageHandler *handler = FindHandlerMime(mimetype);
450
451 if (handler == NULL)
452 {
453 wxLogWarning( _T("No image handler for type %s defined."), mimetype.GetData() );
454
455 return FALSE;
456 }
457
458 return handler->SaveFile( this, stream );
459 }
460 #endif // wxUSE_STREAMS
461
462 void wxImage::AddHandler( wxImageHandler *handler )
463 {
464 // make sure that the memory will be freed at the program end
465 sm_handlers.DeleteContents(TRUE);
466
467 sm_handlers.Append( handler );
468 }
469
470 void wxImage::InsertHandler( wxImageHandler *handler )
471 {
472 // make sure that the memory will be freed at the program end
473 sm_handlers.DeleteContents(TRUE);
474
475 sm_handlers.Insert( handler );
476 }
477
478 bool wxImage::RemoveHandler( const wxString& name )
479 {
480 wxImageHandler *handler = FindHandler(name);
481 if (handler)
482 {
483 sm_handlers.DeleteObject(handler);
484 return TRUE;
485 }
486 else
487 return FALSE;
488 }
489
490 wxImageHandler *wxImage::FindHandler( const wxString& name )
491 {
492 wxNode *node = sm_handlers.First();
493 while (node)
494 {
495 wxImageHandler *handler = (wxImageHandler*)node->Data();
496 if (handler->GetName().Cmp(name) == 0) return handler;
497
498 node = node->Next();
499 }
500 return (wxImageHandler *)NULL;
501 }
502
503 wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
504 {
505 wxNode *node = sm_handlers.First();
506 while (node)
507 {
508 wxImageHandler *handler = (wxImageHandler*)node->Data();
509 if ( (handler->GetExtension().Cmp(extension) == 0) &&
510 (bitmapType == -1 || handler->GetType() == bitmapType) )
511 return handler;
512 node = node->Next();
513 }
514 return (wxImageHandler*)NULL;
515 }
516
517 wxImageHandler *wxImage::FindHandler( long bitmapType )
518 {
519 wxNode *node = sm_handlers.First();
520 while (node)
521 {
522 wxImageHandler *handler = (wxImageHandler *)node->Data();
523 if (handler->GetType() == bitmapType) return handler;
524 node = node->Next();
525 }
526 return NULL;
527 }
528
529 wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
530 {
531 wxNode *node = sm_handlers.First();
532 while (node)
533 {
534 wxImageHandler *handler = (wxImageHandler *)node->Data();
535 if (handler->GetMimeType().IsSameAs(mimetype, FALSE)) return handler;
536 node = node->Next();
537 }
538 return NULL;
539 }
540
541 void wxImage::InitStandardHandlers()
542 {
543 AddHandler( new wxBMPHandler );
544 }
545
546 void wxImage::CleanUpHandlers()
547 {
548 wxNode *node = sm_handlers.First();
549 while (node)
550 {
551 wxImageHandler *handler = (wxImageHandler *)node->Data();
552 wxNode *next = node->Next();
553 delete handler;
554 delete node;
555 node = next;
556 }
557 }
558
559 //-----------------------------------------------------------------------------
560 // wxImageHandler
561 //-----------------------------------------------------------------------------
562
563 #if !USE_SHARED_LIBRARIES
564 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler,wxObject)
565 #endif
566
567 #if wxUSE_STREAMS
568 bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream) )
569 {
570 return FALSE;
571 }
572
573 bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream) )
574 {
575 return FALSE;
576 }
577 #endif // wxUSE_STREAMS
578
579 //-----------------------------------------------------------------------------
580 // wxBMPHandler
581 //-----------------------------------------------------------------------------
582
583 #if !USE_SHARED_LIBRARIES
584 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
585 #endif
586
587 #if wxUSE_STREAMS
588 bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
589 {
590 unsigned char *data, *ptr;
591 int done, i, bpp, planes, comp, ncolors, line, column,
592 linesize, linepos, rshift = 0, gshift = 0, bshift = 0;
593 unsigned char aByte;
594 short int word;
595 long int dbuf[4], dword, rmask = 0, gmask = 0, bmask = 0, offset,
596 size;
597 off_t start_offset = stream.TellI();
598 signed char bbuf[4];
599 struct _cmap
600 {
601 unsigned char r, g, b;
602 }
603 *cmap = NULL;
604 #ifndef BI_RGB
605 #define BI_RGB 0
606 #define BI_RLE8 1
607 #define BI_RLE4 2
608 #endif
609
610 #ifndef BI_BITFIELDS
611 #define BI_BITFIELDS 3
612 #endif
613
614 image->Destroy();
615
616 done = 0;
617 /*
618 * Reading the bmp header
619 */
620
621 stream.Read(&bbuf, 2);
622
623 stream.Read(dbuf, 4 * 4);
624
625 size = dbuf[0];
626 offset = dbuf[2];
627
628 stream.Read(dbuf, 4 * 2);
629 int width = (int)dbuf[0];
630 int height = (int)dbuf[1];
631 if (width > 32767)
632 {
633 wxLogError( _T("Image width > 32767 pixels for file\n") );
634 return FALSE;
635 }
636 if (height > 32767)
637 {
638 wxLogError( _T("Image height > 32767 pixels for file\n") );
639 return FALSE;
640 }
641 stream.Read(&word, 2);
642 planes = (int)word;
643 stream.Read(&word, 2);
644 bpp = (int)word;
645 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp && 16 && bpp != 24 && bpp != 32)
646 {
647 wxLogError( _T("unknown bitdepth in file\n") );
648 return FALSE;
649 }
650 stream.Read(dbuf, 4 * 4);
651 comp = (int)dbuf[0];
652 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
653 {
654 wxLogError( _T("unknown encoding in Windows BMP file\n") );
655 return FALSE;
656 }
657 stream.Read(dbuf, 4 * 2);
658 ncolors = (int)dbuf[0];
659 if (ncolors == 0)
660 ncolors = 1 << bpp;
661 /* some more sanity checks */
662 if (((comp == BI_RLE4) && (bpp != 4)) || ((comp == BI_RLE8) && (bpp != 8)) || ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
663 {
664 wxLogError( _T("encoding of BMP doesn't match bitdepth\n") );
665 return FALSE;
666 }
667 if (bpp < 16)
668 {
669 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
670
671 if (!cmap)
672 {
673 wxLogError( _T("Cannot allocate RAM for color map in BMP file\n") );
674 return FALSE;
675 }
676 }
677 else
678 cmap = NULL;
679
680 image->Create( width, height );
681 ptr = image->GetData();
682 if (!ptr)
683 {
684 wxLogError( _T("Cannot allocate RAM for RGB data in file\n") );
685 if (cmap)
686 free(cmap);
687 return FALSE;
688 }
689
690 /*
691 * Reading the palette, if it exists.
692 */
693 if (bpp < 16 && ncolors != 0)
694 {
695 for (i = 0; i < ncolors; i++)
696 {
697 stream.Read(bbuf, 4);
698 cmap[i].b = bbuf[0];
699 cmap[i].g = bbuf[1];
700 cmap[i].r = bbuf[2];
701 }
702 }
703 else if (bpp == 16 || bpp == 32)
704 {
705 if (comp == BI_BITFIELDS)
706 {
707 int bit = 0;
708
709 stream.Read(dbuf, 4 * 3);
710 bmask = dbuf[0];
711 gmask = dbuf[1];
712 rmask = dbuf[2];
713 /* find shift amount.. ugly, but i can't think of a better way */
714 for (bit = 0; bit < bpp; bit++)
715 {
716 if (bmask & (1 << bit))
717 bshift = bit;
718 if (gmask & (1 << bit))
719 gshift = bit;
720 if (rmask & (1 << bit))
721 rshift = bit;
722 }
723 }
724 else if (bpp == 16)
725 {
726 rmask = 0x7C00;
727 gmask = 0x03E0;
728 bmask = 0x001F;
729 rshift = 10;
730 gshift = 5;
731 bshift = 0;
732 }
733 else if (bpp == 32)
734 {
735 rmask = 0x00FF0000;
736 gmask = 0x0000FF00;
737 bmask = 0x000000FF;
738 rshift = 16;
739 gshift = 8;
740 bshift = 0;
741 }
742 }
743
744 /*
745 * Reading the image data
746 */
747 stream.SeekI(start_offset + offset);
748 data = ptr;
749
750 /* set the whole image to the background color */
751 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
752 {
753 for (i = 0; i < width * height; i++)
754 {
755 *ptr++ = cmap[0].r;
756 *ptr++ = cmap[0].g;
757 *ptr++ = cmap[0].b;
758 }
759 ptr = data;
760 }
761 line = 0;
762 column = 0;
763 #define poffset (line * width * 3 + column * 3)
764
765 /*
766 * BMPs are stored upside down... hmmmmmmmmmm....
767 */
768
769 linesize = ((width * bpp + 31) / 32) * 4;
770 for (line = (height - 1); line >= 0; line--)
771 {
772 linepos = 0;
773 for (column = 0; column < width;)
774 {
775 if (bpp < 16)
776 {
777 int index;
778
779 linepos++;
780 aByte = stream.GetC();
781 if (bpp == 1)
782 {
783 int bit = 0;
784
785 for (bit = 0; bit < 8; bit++)
786 {
787 index = ((aByte & (0x80 >> bit)) ? 1 : 0);
788 ptr[poffset] = cmap[index].r;
789 ptr[poffset + 1] = cmap[index].g;
790 ptr[poffset + 2] = cmap[index].b;
791 column++;
792 }
793 }
794 else if (bpp == 4)
795 {
796 if (comp == BI_RLE4)
797 {
798 wxLogError( _T("can't deal with 4bit encoded yet.\n") );
799 image->Destroy();
800 free(cmap);
801 return FALSE;
802 }
803 else
804 {
805 int nibble = 0;
806
807 for (nibble = 0; nibble < 2; nibble++)
808 {
809 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
810 if (index >= 16)
811 index = 15;
812 ptr[poffset] = cmap[index].r;
813 ptr[poffset + 1] = cmap[index].g;
814 ptr[poffset + 2] = cmap[index].b;
815 column++;
816 }
817 }
818 }
819 else if (bpp == 8)
820 {
821 if (comp == BI_RLE8)
822 {
823 unsigned char first;
824
825 first = aByte;
826 aByte = stream.GetC();
827 if (first == 0)
828 {
829 if (aByte == 0)
830 {
831 /* column = width; */
832 }
833 else if (aByte == 1)
834 {
835 column = width;
836 line = -1;
837 }
838 else if (aByte == 2)
839 {
840 aByte = stream.GetC();
841 column += aByte;
842 linepos = column * bpp / 8;
843 aByte = stream.GetC();
844 line += aByte;
845 }
846 else
847 {
848 int absolute = aByte;
849
850 for (i = 0; i < absolute; i++)
851 {
852 linepos++;
853 aByte = stream.GetC();
854 ptr[poffset] = cmap[aByte].r;
855 ptr[poffset + 1] = cmap[aByte].g;
856 ptr[poffset + 2] = cmap[aByte].b;
857 column++;
858 }
859 if (absolute & 0x01)
860 aByte = stream.GetC();
861 }
862 }
863 else
864 {
865 for (i = 0; i < first; i++)
866 {
867 ptr[poffset] = cmap[aByte].r;
868 ptr[poffset + 1] = cmap[aByte].g;
869 ptr[poffset + 2] = cmap[aByte].b;
870 column++;
871 linepos++;
872 }
873 }
874 }
875 else
876 {
877 ptr[poffset] = cmap[aByte].r;
878 ptr[poffset + 1] = cmap[aByte].g;
879 ptr[poffset + 2] = cmap[aByte].b;
880 column++;
881 linepos += size;
882 }
883 }
884 }
885 else if (bpp == 24)
886 {
887 stream.Read(&bbuf, 3);
888 linepos += 3;
889 ptr[poffset] = (unsigned char)bbuf[2];
890 ptr[poffset + 1] = (unsigned char)bbuf[1];
891 ptr[poffset + 2] = (unsigned char)bbuf[0];
892 column++;
893 }
894 else if (bpp == 16)
895 {
896 unsigned char temp;
897
898 stream.Read(&word, 2);
899 linepos += 2;
900 temp = (word & rmask) >> rshift;
901 ptr[poffset] = temp;
902 temp = (word & gmask) >> gshift;
903 ptr[poffset + 1] = temp;
904 temp = (word & bmask) >> gshift;
905 ptr[poffset + 2] = temp;
906 column++;
907 }
908 else
909 {
910 unsigned char temp;
911
912 stream.Read(&dword, 4);
913 linepos += 4;
914 temp = (dword & rmask) >> rshift;
915 ptr[poffset] = temp;
916 temp = (dword & gmask) >> gshift;
917 ptr[poffset + 1] = temp;
918 temp = (dword & bmask) >> bshift;
919 ptr[poffset + 2] = temp;
920 column++;
921 }
922 }
923 while ((linepos < linesize) && (comp != 1) && (comp != 2))
924 {
925 stream.Read(&aByte, 1);
926 linepos += 1;
927 if (stream.LastError() != wxStream_NOERROR)
928 break;
929 }
930 }
931 if (cmap) free(cmap);
932
933 image->SetMask( FALSE );
934
935 return TRUE;
936 }
937 #endif // wxUSE_STREAMS
938
939 #ifdef __WXMSW__
940
941 wxBitmap wxImage::ConvertToBitmap() const
942 {
943 // sizeLimit is the MS upper limit for the DIB size
944 int sizeLimit = 1024*768*3;
945
946 // width and height of the device-dependent bitmap
947 int width = GetWidth();
948 int bmpHeight = GetHeight();
949
950 // calc the number of bytes per scanline and padding
951 int bytePerLine = width*3;
952 int sizeDWORD = sizeof( DWORD );
953 div_t lineBoundary = div( bytePerLine, sizeDWORD );
954 int padding = 0;
955 if( lineBoundary.rem > 0 )
956 {
957 padding = sizeDWORD - lineBoundary.rem;
958 bytePerLine += padding;
959 }
960 // calc the number of DIBs and heights of DIBs
961 int numDIB = 1;
962 int hRemain = 0;
963 int height = sizeLimit/bytePerLine;
964 if( height >= bmpHeight )
965 height = bmpHeight;
966 else
967 {
968 div_t result = div( bmpHeight, height );
969 numDIB = result.quot;
970 hRemain = result.rem;
971 if( hRemain >0 ) numDIB++;
972 }
973
974 // set bitmap parameters
975 wxBitmap bitmap;
976 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
977 bitmap.SetWidth( width );
978 bitmap.SetHeight( bmpHeight );
979 bitmap.SetDepth( wxDisplayDepth() );
980
981 // create a DIB header
982 int headersize = sizeof(BITMAPINFOHEADER);
983 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
984 wxCHECK_MSG( lpDIBh, bitmap, _T("could not allocate memory for DIB header") );
985 // Fill in the DIB header
986 lpDIBh->bmiHeader.biSize = headersize;
987 lpDIBh->bmiHeader.biWidth = (DWORD)width;
988 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
989 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
990 // the general formula for biSizeImage:
991 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
992 lpDIBh->bmiHeader.biPlanes = 1;
993 lpDIBh->bmiHeader.biBitCount = 24;
994 lpDIBh->bmiHeader.biCompression = BI_RGB;
995 lpDIBh->bmiHeader.biClrUsed = 0;
996 // These seem not really needed for our purpose here.
997 lpDIBh->bmiHeader.biClrImportant = 0;
998 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
999 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1000 // memory for DIB data
1001 unsigned char *lpBits;
1002 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
1003 if( !lpBits )
1004 {
1005 wxFAIL_MSG( _T("could not allocate memory for DIB") );
1006 free( lpDIBh );
1007 return bitmap;
1008 }
1009
1010 // create and set the device-dependent bitmap
1011 HDC hdc = ::GetDC(NULL);
1012 HDC memdc = ::CreateCompatibleDC( hdc );
1013 HBITMAP hbitmap;
1014 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
1015 ::SelectObject( memdc, hbitmap);
1016
1017 // copy image data into DIB data and then into DDB (in a loop)
1018 unsigned char *data = GetData();
1019 int i, j, n;
1020 int origin = 0;
1021 unsigned char *ptdata = data;
1022 unsigned char *ptbits;
1023
1024 for( n=0; n<numDIB; n++ )
1025 {
1026 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
1027 {
1028 // redefine height and size of the (possibly) last smaller DIB
1029 // memory is not reallocated
1030 height = hRemain;
1031 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1032 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1033 }
1034 ptbits = lpBits;
1035
1036 for( j=0; j<height; j++ )
1037 {
1038 for( i=0; i<width; i++ )
1039 {
1040 *(ptbits++) = *(ptdata+2);
1041 *(ptbits++) = *(ptdata+1);
1042 *(ptbits++) = *(ptdata );
1043 ptdata += 3;
1044 }
1045 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
1046 }
1047 ::StretchDIBits( memdc, 0, origin, width, height,\
1048 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1049 origin += height;
1050 // if numDIB = 1, lines below can also be used
1051 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1052 // The above line is equivalent to the following two lines.
1053 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1054 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1055 // or the following lines
1056 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1057 // HDC memdc = ::CreateCompatibleDC( hdc );
1058 // ::SelectObject( memdc, hbitmap);
1059 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1060 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1061 // ::SelectObject( memdc, 0 );
1062 // ::DeleteDC( memdc );
1063 }
1064 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
1065
1066 // similarly, created an mono-bitmap for the possible mask
1067 if( HasMask() )
1068 {
1069 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
1070 ::SelectObject( memdc, hbitmap);
1071 if( numDIB == 1 ) height = bmpHeight;
1072 else height = sizeLimit/bytePerLine;
1073 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1074 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1075 origin = 0;
1076 unsigned char r = GetMaskRed();
1077 unsigned char g = GetMaskGreen();
1078 unsigned char b = GetMaskBlue();
1079 unsigned char zero = 0, one = 255;
1080 ptdata = data;
1081 for( n=0; n<numDIB; n++ )
1082 {
1083 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
1084 {
1085 // redefine height and size of the (possibly) last smaller DIB
1086 // memory is not reallocated
1087 height = hRemain;
1088 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1089 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1090 }
1091 ptbits = lpBits;
1092 for( int j=0; j<height; j++ )
1093 {
1094 for(i=0; i<width; i++ )
1095 {
1096 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
1097 {
1098 *(ptbits++) = one;
1099 *(ptbits++) = one;
1100 *(ptbits++) = one;
1101 }
1102 else
1103 {
1104 *(ptbits++) = zero;
1105 *(ptbits++) = zero;
1106 *(ptbits++) = zero;
1107 }
1108 }
1109 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
1110 }
1111 ::StretchDIBits( memdc, 0, origin, width, height,\
1112 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1113 origin += height;
1114 }
1115 // create a wxMask object
1116 wxMask *mask = new wxMask();
1117 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
1118 bitmap.SetMask( mask );
1119 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1120 /* The following can also be used but is slow to run
1121 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1122 wxMask *mask = new wxMask( bitmap, colour );
1123 bitmap.SetMask( mask );
1124 */
1125 }
1126
1127 // free allocated resources
1128 ::SelectObject( memdc, 0 );
1129 ::DeleteDC( memdc );
1130 ::ReleaseDC(NULL, hdc);
1131 free(lpDIBh);
1132 free(lpBits);
1133
1134 // check the wxBitmap object
1135 if( bitmap.GetHBITMAP() )
1136 bitmap.SetOk( TRUE );
1137 else
1138 bitmap.SetOk( FALSE );
1139
1140 return bitmap;
1141 }
1142
1143 wxImage::wxImage( const wxBitmap &bitmap )
1144 {
1145 // check the bitmap
1146 if( !bitmap.Ok() )
1147 {
1148 wxFAIL_MSG( _T("invalid bitmap") );
1149 return;
1150 }
1151
1152 // create an wxImage object
1153 int width = bitmap.GetWidth();
1154 int height = bitmap.GetHeight();
1155 Create( width, height );
1156 unsigned char *data = GetData();
1157 if( !data )
1158 {
1159 wxFAIL_MSG( _T("could not allocate data for image") );
1160 return;
1161 }
1162
1163 // calc the number of bytes per scanline and padding in the DIB
1164 int bytePerLine = width*3;
1165 int sizeDWORD = sizeof( DWORD );
1166 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1167 int padding = 0;
1168 if( lineBoundary.rem > 0 )
1169 {
1170 padding = sizeDWORD - lineBoundary.rem;
1171 bytePerLine += padding;
1172 }
1173
1174 // create a DIB header
1175 int headersize = sizeof(BITMAPINFOHEADER);
1176 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1177 if( !lpDIBh )
1178 {
1179 wxFAIL_MSG( _T("could not allocate data for DIB header") );
1180 free( data );
1181 return;
1182 }
1183 // Fill in the DIB header
1184 lpDIBh->bmiHeader.biSize = headersize;
1185 lpDIBh->bmiHeader.biWidth = width;
1186 lpDIBh->bmiHeader.biHeight = -height;
1187 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1188 lpDIBh->bmiHeader.biPlanes = 1;
1189 lpDIBh->bmiHeader.biBitCount = 24;
1190 lpDIBh->bmiHeader.biCompression = BI_RGB;
1191 lpDIBh->bmiHeader.biClrUsed = 0;
1192 // These seem not really needed for our purpose here.
1193 lpDIBh->bmiHeader.biClrImportant = 0;
1194 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1195 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1196 // memory for DIB data
1197 unsigned char *lpBits;
1198 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1199 if( !lpBits )
1200 {
1201 wxFAIL_MSG( _T("could not allocate data for DIB") );
1202 free( data );
1203 free( lpDIBh );
1204 return;
1205 }
1206
1207 // copy data from the device-dependent bitmap to the DIB
1208 HDC hdc = ::GetDC(NULL);
1209 HBITMAP hbitmap;
1210 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1211 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1212
1213 // copy DIB data into the wxImage object
1214 int i, j;
1215 unsigned char *ptdata = data;
1216 unsigned char *ptbits = lpBits;
1217 for( i=0; i<height; i++ )
1218 {
1219 for( j=0; j<width; j++ )
1220 {
1221 *(ptdata++) = *(ptbits+2);
1222 *(ptdata++) = *(ptbits+1);
1223 *(ptdata++) = *(ptbits );
1224 ptbits += 3;
1225 }
1226 ptbits += padding;
1227 }
1228
1229 // similarly, set data according to the possible mask bitmap
1230 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1231 {
1232 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1233 // memory DC created, color set, data copied, and memory DC deleted
1234 HDC memdc = ::CreateCompatibleDC( hdc );
1235 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1236 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1237 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1238 ::DeleteDC( memdc );
1239 // background color set to RGB(16,16,16) in consistent with wxGTK
1240 unsigned char r=16, g=16, b=16;
1241 ptdata = data;
1242 ptbits = lpBits;
1243 for( i=0; i<height; i++ )
1244 {
1245 for( j=0; j<width; j++ )
1246 {
1247 if( *ptbits != 0 )
1248 ptdata += 3;
1249 else
1250 {
1251 *(ptdata++) = r;
1252 *(ptdata++) = g;
1253 *(ptdata++) = b;
1254 }
1255 ptbits += 3;
1256 }
1257 ptbits += padding;
1258 }
1259 SetMaskColour( r, g, b );
1260 SetMask( TRUE );
1261 }
1262 else
1263 {
1264 SetMask( FALSE );
1265 }
1266 // free allocated resources
1267 ::ReleaseDC(NULL, hdc);
1268 free(lpDIBh);
1269 free(lpBits);
1270 }
1271
1272 #endif
1273
1274 #ifdef __WXGTK__
1275
1276 #include "gtk/gtk.h"
1277 #include "gdk/gdk.h"
1278 #include "gdk/gdkx.h"
1279
1280 wxBitmap wxImage::ConvertToBitmap() const
1281 {
1282 wxBitmap bitmap;
1283
1284 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
1285
1286 int width = GetWidth();
1287 int height = GetHeight();
1288
1289 bitmap.SetHeight( height );
1290 bitmap.SetWidth( width );
1291
1292 // Create picture
1293
1294 GdkImage *data_image =
1295 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
1296
1297 bitmap.SetPixmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, -1 ) );
1298
1299 // Create mask
1300
1301 GdkImage *mask_image = (GdkImage*) NULL;
1302
1303 if (HasMask())
1304 {
1305 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1306
1307 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1308
1309 wxMask *mask = new wxMask();
1310 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1311
1312 bitmap.SetMask( mask );
1313 }
1314
1315 // Retrieve depth
1316
1317 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1318 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1319 int bpp = visual->depth;
1320
1321 bitmap.SetDepth( bpp );
1322
1323 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1324 if (bpp < 8) bpp = 8;
1325
1326 // Render
1327
1328 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1329 byte_order b_o = RGB;
1330
1331 if (bpp >= 24)
1332 {
1333 GdkVisual *visual = gdk_visual_get_system();
1334 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1335 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1336 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1337 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1338 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1339 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1340 }
1341
1342 int r_mask = GetMaskRed();
1343 int g_mask = GetMaskGreen();
1344 int b_mask = GetMaskBlue();
1345
1346 unsigned char* data = GetData();
1347
1348 int index = 0;
1349 for (int y = 0; y < height; y++)
1350 {
1351 for (int x = 0; x < width; x++)
1352 {
1353 int r = data[index];
1354 index++;
1355 int g = data[index];
1356 index++;
1357 int b = data[index];
1358 index++;
1359
1360 if (HasMask())
1361 {
1362 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1363 gdk_image_put_pixel( mask_image, x, y, 1 );
1364 else
1365 gdk_image_put_pixel( mask_image, x, y, 0 );
1366 }
1367
1368 if (HasMask())
1369 {
1370 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1371 gdk_image_put_pixel( mask_image, x, y, 1 );
1372 else
1373 gdk_image_put_pixel( mask_image, x, y, 0 );
1374 }
1375
1376 switch (bpp)
1377 {
1378 case 8:
1379 {
1380 int pixel = -1;
1381 if (wxTheApp->m_colorCube)
1382 {
1383 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1384 }
1385 else
1386 {
1387 GdkColormap *cmap = gtk_widget_get_default_colormap();
1388 GdkColor *colors = cmap->colors;
1389 int max = 3 * (65536);
1390
1391 for (int i = 0; i < cmap->size; i++)
1392 {
1393 int rdiff = (r << 8) - colors[i].red;
1394 int gdiff = (g << 8) - colors[i].green;
1395 int bdiff = (b << 8) - colors[i].blue;
1396 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1397 if (sum < max) { pixel = i; max = sum; }
1398 }
1399 }
1400
1401 gdk_image_put_pixel( data_image, x, y, pixel );
1402
1403 break;
1404 }
1405 case 15:
1406 {
1407 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1408 gdk_image_put_pixel( data_image, x, y, pixel );
1409 break;
1410 }
1411 case 16:
1412 {
1413 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1414 gdk_image_put_pixel( data_image, x, y, pixel );
1415 break;
1416 }
1417 case 32:
1418 case 24:
1419 {
1420 guint32 pixel = 0;
1421 switch (b_o)
1422 {
1423 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1424 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1425 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1426 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1427 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1428 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1429 }
1430 gdk_image_put_pixel( data_image, x, y, pixel );
1431 }
1432 default: break;
1433 }
1434 } // for
1435 } // for
1436
1437 // Blit picture
1438
1439 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1440
1441 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1442
1443 gdk_image_destroy( data_image );
1444 gdk_gc_unref( data_gc );
1445
1446 // Blit mask
1447
1448 if (HasMask())
1449 {
1450 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1451
1452 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1453
1454 gdk_image_destroy( mask_image );
1455 gdk_gc_unref( mask_gc );
1456 }
1457
1458 return bitmap;
1459 }
1460
1461 wxImage::wxImage( const wxBitmap &bitmap )
1462 {
1463 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
1464
1465 GdkImage *gdk_image = gdk_image_get( bitmap.GetPixmap(),
1466 0, 0,
1467 bitmap.GetWidth(), bitmap.GetHeight() );
1468
1469 wxCHECK_RET( gdk_image, _T("couldn't create image") );
1470
1471 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1472 char unsigned *data = GetData();
1473
1474 if (!data)
1475 {
1476 gdk_image_destroy( gdk_image );
1477 wxFAIL_MSG( _T("couldn't create image") );
1478 return;
1479 }
1480
1481 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1482 if (bitmap.GetMask())
1483 {
1484 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1485 0, 0,
1486 bitmap.GetWidth(), bitmap.GetHeight() );
1487
1488 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1489 }
1490
1491 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1492 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1493 int bpp = visual->depth;
1494 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1495
1496 GdkColormap *cmap = gtk_widget_get_default_colormap();
1497
1498 long pos = 0;
1499 for (int j = 0; j < bitmap.GetHeight(); j++)
1500 {
1501 for (int i = 0; i < bitmap.GetWidth(); i++)
1502 {
1503 int pixel = gdk_image_get_pixel( gdk_image, i, j );
1504 if (bpp <= 8)
1505 {
1506 data[pos] = cmap->colors[pixel].red >> 8;
1507 data[pos+1] = cmap->colors[pixel].green >> 8;
1508 data[pos+2] = cmap->colors[pixel].blue >> 8;
1509 } else if (bpp == 15)
1510 {
1511 data[pos] = (pixel >> 7) & 0xf8;
1512 data[pos+1] = (pixel >> 2) & 0xf8;
1513 data[pos+2] = (pixel << 3) & 0xf8;
1514 } else if (bpp == 16)
1515 {
1516 data[pos] = (pixel >> 8) & 0xf8;
1517 data[pos+1] = (pixel >> 3) & 0xfc;
1518 data[pos+2] = (pixel << 3) & 0xf8;
1519 } else
1520 {
1521 data[pos] = (pixel >> 16) & 0xff;
1522 data[pos+1] = (pixel >> 8) & 0xff;
1523 data[pos+2] = pixel & 0xff;
1524 }
1525
1526 if (gdk_image_mask)
1527 {
1528 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1529 if (mask_pixel == 0)
1530 {
1531 data[pos] = 16;
1532 data[pos+1] = 16;
1533 data[pos+2] = 16;
1534 }
1535 }
1536
1537 pos += 3;
1538 }
1539 }
1540
1541 gdk_image_destroy( gdk_image );
1542 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1543 }
1544
1545 #endif
1546
1547 #ifdef __WXMOTIF__
1548
1549 #include <Xm/Xm.h>
1550 #include "wx/utils.h"
1551 #include <math.h>
1552
1553 wxBitmap wxImage::ConvertToBitmap() const
1554 {
1555 wxBitmap bitmap;
1556
1557 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
1558
1559 int width = GetWidth();
1560 int height = GetHeight();
1561
1562 bitmap.SetHeight( height );
1563 bitmap.SetWidth( width );
1564
1565 Display *dpy = (Display*) wxGetDisplay();
1566 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1567 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1568
1569 // Create image
1570
1571 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
1572 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
1573
1574 bitmap.Create( width, height, bpp );
1575
1576 /*
1577 // Create mask
1578
1579 GdkImage *mask_image = (GdkImage*) NULL;
1580
1581 if (HasMask())
1582 {
1583 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1584
1585 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1586
1587 wxMask *mask = new wxMask();
1588 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1589
1590 bitmap.SetMask( mask );
1591 }
1592 */
1593
1594 // Retrieve depth info
1595
1596 XVisualInfo vinfo_template;
1597 XVisualInfo *vi;
1598
1599 vinfo_template.visual = vis;
1600 vinfo_template.visualid = XVisualIDFromVisual( vis );
1601 vinfo_template.depth = bpp;
1602 int nitem = 0;
1603
1604 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1605
1606 if (!vi)
1607 {
1608 printf("no visual.\n" );
1609 return wxNullBitmap;
1610 }
1611
1612 XFree( vi );
1613
1614 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1615 if (bpp < 8) bpp = 8;
1616
1617 // Render
1618
1619 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1620 byte_order b_o = RGB;
1621
1622 if (bpp >= 24)
1623 {
1624 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1625 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1626 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1627 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1628 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1629 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1630 }
1631
1632 /*
1633 int r_mask = GetMaskRed();
1634 int g_mask = GetMaskGreen();
1635 int b_mask = GetMaskBlue();
1636 */
1637
1638 XColor colors[256];
1639 if (bpp == 8)
1640 {
1641 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
1642
1643 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1644 XQueryColors( dpy, cmap, colors, 256 );
1645 }
1646
1647 unsigned char* data = GetData();
1648
1649 int index = 0;
1650 for (int y = 0; y < height; y++)
1651 {
1652 for (int x = 0; x < width; x++)
1653 {
1654 int r = data[index];
1655 index++;
1656 int g = data[index];
1657 index++;
1658 int b = data[index];
1659 index++;
1660
1661 /*
1662 if (HasMask())
1663 {
1664 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1665 gdk_image_put_pixel( mask_image, x, y, 1 );
1666 else
1667 gdk_image_put_pixel( mask_image, x, y, 0 );
1668 }
1669 */
1670
1671 switch (bpp)
1672 {
1673 case 8:
1674 {
1675 int pixel = -1;
1676 /*
1677 if (wxTheApp->m_colorCube)
1678 {
1679 pixel = wxTheApp->m_colorCube
1680 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1681 }
1682 else
1683 {
1684 */
1685 int max = 3 * (65536);
1686 for (int i = 0; i < 256; i++)
1687 {
1688 int rdiff = (r << 8) - colors[i].red;
1689 int gdiff = (g << 8) - colors[i].green;
1690 int bdiff = (b << 8) - colors[i].blue;
1691 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1692 if (sum < max) { pixel = i; max = sum; }
1693 }
1694 /*
1695 }
1696 */
1697 XPutPixel( data_image, x, y, pixel );
1698 break;
1699 }
1700 case 15:
1701 {
1702 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1703 XPutPixel( data_image, x, y, pixel );
1704 break;
1705 }
1706 case 16:
1707 {
1708 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1709 XPutPixel( data_image, x, y, pixel );
1710 break;
1711 }
1712 case 32:
1713 case 24:
1714 {
1715 int pixel = 0;
1716 switch (b_o)
1717 {
1718 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1719 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1720 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1721 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1722 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1723 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1724 }
1725 XPutPixel( data_image, x, y, pixel );
1726 }
1727 default: break;
1728 }
1729 } // for
1730 } // for
1731
1732 // Blit picture
1733
1734 XGCValues gcvalues;
1735 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
1736 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
1737 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
1738
1739 XDestroyImage( data_image );
1740 XFreeGC( dpy, gc );
1741
1742 /*
1743 // Blit mask
1744
1745 if (HasMask())
1746 {
1747 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1748
1749 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1750
1751 gdk_image_destroy( mask_image );
1752 gdk_gc_unref( mask_gc );
1753 }
1754 */
1755
1756 return bitmap;
1757 }
1758
1759 wxImage::wxImage( const wxBitmap &bitmap )
1760 {
1761 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
1762
1763 Display *dpy = (Display*) wxGetDisplay();
1764 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1765 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1766
1767 XImage *ximage = XGetImage( dpy,
1768 (Drawable)bitmap.GetPixmap(),
1769 0, 0,
1770 bitmap.GetWidth(), bitmap.GetHeight(),
1771 AllPlanes, ZPixmap );
1772
1773 wxCHECK_RET( ximage, _T("couldn't create image") );
1774
1775 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1776 char unsigned *data = GetData();
1777
1778 if (!data)
1779 {
1780 XDestroyImage( ximage );
1781 wxFAIL_MSG( _T("couldn't create image") );
1782 return;
1783 }
1784
1785 /*
1786 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1787 if (bitmap.GetMask())
1788 {
1789 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1790 0, 0,
1791 bitmap.GetWidth(), bitmap.GetHeight() );
1792
1793 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1794 }
1795 */
1796
1797 // Retrieve depth info
1798
1799 XVisualInfo vinfo_template;
1800 XVisualInfo *vi;
1801
1802 vinfo_template.visual = vis;
1803 vinfo_template.visualid = XVisualIDFromVisual( vis );
1804 vinfo_template.depth = bpp;
1805 int nitem = 0;
1806
1807 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1808
1809 if (!vi)
1810 {
1811 printf("no visual.\n" );
1812 return;
1813 }
1814
1815 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1816
1817 XFree( vi );
1818
1819 XColor colors[256];
1820 if (bpp == 8)
1821 {
1822 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
1823
1824 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1825 XQueryColors( dpy, cmap, colors, 256 );
1826 }
1827
1828 long pos = 0;
1829 for (int j = 0; j < bitmap.GetHeight(); j++)
1830 {
1831 for (int i = 0; i < bitmap.GetWidth(); i++)
1832 {
1833 int pixel = XGetPixel( ximage, i, j );
1834 if (bpp <= 8)
1835 {
1836 data[pos] = colors[pixel].red >> 8;
1837 data[pos+1] = colors[pixel].green >> 8;
1838 data[pos+2] = colors[pixel].blue >> 8;
1839 } else if (bpp == 15)
1840 {
1841 data[pos] = (pixel >> 7) & 0xf8;
1842 data[pos+1] = (pixel >> 2) & 0xf8;
1843 data[pos+2] = (pixel << 3) & 0xf8;
1844 } else if (bpp == 16)
1845 {
1846 data[pos] = (pixel >> 8) & 0xf8;
1847 data[pos+1] = (pixel >> 3) & 0xfc;
1848 data[pos+2] = (pixel << 3) & 0xf8;
1849 } else
1850 {
1851 data[pos] = (pixel >> 16) & 0xff;
1852 data[pos+1] = (pixel >> 8) & 0xff;
1853 data[pos+2] = pixel & 0xff;
1854 }
1855
1856 /*
1857 if (gdk_image_mask)
1858 {
1859 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1860 if (mask_pixel == 0)
1861 {
1862 data[pos] = 16;
1863 data[pos+1] = 16;
1864 data[pos+2] = 16;
1865 }
1866 }
1867 */
1868
1869 pos += 3;
1870 }
1871 }
1872
1873 XDestroyImage( ximage );
1874 /*
1875 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1876 */
1877 }
1878 #endif
1879
1880 // A module to allow wxImage initialization/cleanup
1881 // without calling these functions from app.cpp or from
1882 // the user's application.
1883
1884 class wxImageModule: public wxModule
1885 {
1886 DECLARE_DYNAMIC_CLASS(wxImageModule)
1887 public:
1888 wxImageModule() {}
1889 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
1890 void OnExit() { wxImage::CleanUpHandlers(); };
1891 };
1892
1893 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)