]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
Oops, I didn't see Robert had already corrected 16bit BMP typo
[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.") );
634 return FALSE;
635 }
636 if (height > 32767)
637 {
638 wxLogError( _T("Image height > 32767 pixels for file.") );
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.") );
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.") );
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.") );
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.") );
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.") );
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.") );
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 #if (GTK_MINOR_VERSION > 0)
1281 #include "gdk/gdkrgb.h"
1282 #endif
1283
1284 wxBitmap wxImage::ConvertToBitmap() const
1285 {
1286 wxBitmap bitmap;
1287
1288 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
1289
1290 int width = GetWidth();
1291 int height = GetHeight();
1292
1293 bitmap.SetHeight( height );
1294 bitmap.SetWidth( width );
1295
1296 bitmap.SetPixmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, -1 ) );
1297
1298 // Retrieve depth
1299
1300 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1301 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1302 int bpp = visual->depth;
1303
1304 bitmap.SetDepth( bpp );
1305
1306 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1307 if (bpp < 8) bpp = 8;
1308
1309 #if (GTK_MINOR_VERSION > 0)
1310
1311 if (!HasMask() && (bpp > 8))
1312 {
1313 static bool s_hasInitialized = FALSE;
1314
1315 if (!s_hasInitialized)
1316 {
1317 gdk_rgb_init();
1318 s_hasInitialized = TRUE;
1319 }
1320
1321 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
1322
1323 gdk_draw_rgb_image( bitmap.GetPixmap(),
1324 gc,
1325 0, 0,
1326 width, height,
1327 GDK_RGB_DITHER_NONE,
1328 GetData(),
1329 width*3 );
1330
1331 gdk_gc_unref( gc );
1332
1333 return bitmap;
1334 }
1335
1336 #endif
1337
1338 // Create picture image
1339
1340 GdkImage *data_image =
1341 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
1342
1343 // Create mask image
1344
1345 GdkImage *mask_image = (GdkImage*) NULL;
1346
1347 if (HasMask())
1348 {
1349 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1350
1351 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1352
1353 wxMask *mask = new wxMask();
1354 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1355
1356 bitmap.SetMask( mask );
1357 }
1358
1359 // Render
1360
1361 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1362 byte_order b_o = RGB;
1363
1364 if (bpp >= 24)
1365 {
1366 GdkVisual *visual = gdk_visual_get_system();
1367 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1368 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1369 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1370 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1371 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1372 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1373 }
1374
1375 int r_mask = GetMaskRed();
1376 int g_mask = GetMaskGreen();
1377 int b_mask = GetMaskBlue();
1378
1379 unsigned char* data = GetData();
1380
1381 int index = 0;
1382 for (int y = 0; y < height; y++)
1383 {
1384 for (int x = 0; x < width; x++)
1385 {
1386 int r = data[index];
1387 index++;
1388 int g = data[index];
1389 index++;
1390 int b = data[index];
1391 index++;
1392
1393 if (HasMask())
1394 {
1395 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1396 gdk_image_put_pixel( mask_image, x, y, 1 );
1397 else
1398 gdk_image_put_pixel( mask_image, x, y, 0 );
1399 }
1400
1401 if (HasMask())
1402 {
1403 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1404 gdk_image_put_pixel( mask_image, x, y, 1 );
1405 else
1406 gdk_image_put_pixel( mask_image, x, y, 0 );
1407 }
1408
1409 switch (bpp)
1410 {
1411 case 8:
1412 {
1413 int pixel = -1;
1414 if (wxTheApp->m_colorCube)
1415 {
1416 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1417 }
1418 else
1419 {
1420 GdkColormap *cmap = gtk_widget_get_default_colormap();
1421 GdkColor *colors = cmap->colors;
1422 int max = 3 * (65536);
1423
1424 for (int i = 0; i < cmap->size; i++)
1425 {
1426 int rdiff = (r << 8) - colors[i].red;
1427 int gdiff = (g << 8) - colors[i].green;
1428 int bdiff = (b << 8) - colors[i].blue;
1429 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1430 if (sum < max) { pixel = i; max = sum; }
1431 }
1432 }
1433
1434 gdk_image_put_pixel( data_image, x, y, pixel );
1435
1436 break;
1437 }
1438 case 15:
1439 {
1440 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1441 gdk_image_put_pixel( data_image, x, y, pixel );
1442 break;
1443 }
1444 case 16:
1445 {
1446 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1447 gdk_image_put_pixel( data_image, x, y, pixel );
1448 break;
1449 }
1450 case 32:
1451 case 24:
1452 {
1453 guint32 pixel = 0;
1454 switch (b_o)
1455 {
1456 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1457 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1458 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1459 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1460 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1461 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1462 }
1463 gdk_image_put_pixel( data_image, x, y, pixel );
1464 }
1465 default: break;
1466 }
1467 } // for
1468 } // for
1469
1470 // Blit picture
1471
1472 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1473
1474 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1475
1476 gdk_image_destroy( data_image );
1477 gdk_gc_unref( data_gc );
1478
1479 // Blit mask
1480
1481 if (HasMask())
1482 {
1483 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1484
1485 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1486
1487 gdk_image_destroy( mask_image );
1488 gdk_gc_unref( mask_gc );
1489 }
1490
1491 return bitmap;
1492 }
1493
1494 wxImage::wxImage( const wxBitmap &bitmap )
1495 {
1496 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
1497
1498 GdkImage *gdk_image = gdk_image_get( bitmap.GetPixmap(),
1499 0, 0,
1500 bitmap.GetWidth(), bitmap.GetHeight() );
1501
1502 wxCHECK_RET( gdk_image, _T("couldn't create image") );
1503
1504 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1505 char unsigned *data = GetData();
1506
1507 if (!data)
1508 {
1509 gdk_image_destroy( gdk_image );
1510 wxFAIL_MSG( _T("couldn't create image") );
1511 return;
1512 }
1513
1514 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1515 if (bitmap.GetMask())
1516 {
1517 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1518 0, 0,
1519 bitmap.GetWidth(), bitmap.GetHeight() );
1520
1521 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1522 }
1523
1524 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1525 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1526 int bpp = visual->depth;
1527 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1528
1529 GdkColormap *cmap = gtk_widget_get_default_colormap();
1530
1531 long pos = 0;
1532 for (int j = 0; j < bitmap.GetHeight(); j++)
1533 {
1534 for (int i = 0; i < bitmap.GetWidth(); i++)
1535 {
1536 int pixel = gdk_image_get_pixel( gdk_image, i, j );
1537 if (bpp <= 8)
1538 {
1539 data[pos] = cmap->colors[pixel].red >> 8;
1540 data[pos+1] = cmap->colors[pixel].green >> 8;
1541 data[pos+2] = cmap->colors[pixel].blue >> 8;
1542 } else if (bpp == 15)
1543 {
1544 data[pos] = (pixel >> 7) & 0xf8;
1545 data[pos+1] = (pixel >> 2) & 0xf8;
1546 data[pos+2] = (pixel << 3) & 0xf8;
1547 } else if (bpp == 16)
1548 {
1549 data[pos] = (pixel >> 8) & 0xf8;
1550 data[pos+1] = (pixel >> 3) & 0xfc;
1551 data[pos+2] = (pixel << 3) & 0xf8;
1552 } else
1553 {
1554 data[pos] = (pixel >> 16) & 0xff;
1555 data[pos+1] = (pixel >> 8) & 0xff;
1556 data[pos+2] = pixel & 0xff;
1557 }
1558
1559 if (gdk_image_mask)
1560 {
1561 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1562 if (mask_pixel == 0)
1563 {
1564 data[pos] = 16;
1565 data[pos+1] = 16;
1566 data[pos+2] = 16;
1567 }
1568 }
1569
1570 pos += 3;
1571 }
1572 }
1573
1574 gdk_image_destroy( gdk_image );
1575 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1576 }
1577
1578 #endif
1579
1580 #ifdef __WXMOTIF__
1581
1582 #include <Xm/Xm.h>
1583 #include "wx/utils.h"
1584 #include <math.h>
1585
1586 wxBitmap wxImage::ConvertToBitmap() const
1587 {
1588 wxBitmap bitmap;
1589
1590 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
1591
1592 int width = GetWidth();
1593 int height = GetHeight();
1594
1595 bitmap.SetHeight( height );
1596 bitmap.SetWidth( width );
1597
1598 Display *dpy = (Display*) wxGetDisplay();
1599 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1600 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1601
1602 // Create image
1603
1604 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
1605 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
1606
1607 bitmap.Create( width, height, bpp );
1608
1609 /*
1610 // Create mask
1611
1612 GdkImage *mask_image = (GdkImage*) NULL;
1613
1614 if (HasMask())
1615 {
1616 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1617
1618 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1619
1620 wxMask *mask = new wxMask();
1621 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1622
1623 bitmap.SetMask( mask );
1624 }
1625 */
1626
1627 // Retrieve depth info
1628
1629 XVisualInfo vinfo_template;
1630 XVisualInfo *vi;
1631
1632 vinfo_template.visual = vis;
1633 vinfo_template.visualid = XVisualIDFromVisual( vis );
1634 vinfo_template.depth = bpp;
1635 int nitem = 0;
1636
1637 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1638
1639 wxCHECK_MSG( vi, wxNullBitmap, _T("no visual") );
1640
1641 XFree( vi );
1642
1643 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1644 if (bpp < 8) bpp = 8;
1645
1646 // Render
1647
1648 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1649 byte_order b_o = RGB;
1650
1651 if (bpp >= 24)
1652 {
1653 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1654 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1655 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1656 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1657 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1658 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1659 }
1660
1661 /*
1662 int r_mask = GetMaskRed();
1663 int g_mask = GetMaskGreen();
1664 int b_mask = GetMaskBlue();
1665 */
1666
1667 XColor colors[256];
1668 if (bpp == 8)
1669 {
1670 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
1671
1672 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1673 XQueryColors( dpy, cmap, colors, 256 );
1674 }
1675
1676 unsigned char* data = GetData();
1677
1678 int index = 0;
1679 for (int y = 0; y < height; y++)
1680 {
1681 for (int x = 0; x < width; x++)
1682 {
1683 int r = data[index];
1684 index++;
1685 int g = data[index];
1686 index++;
1687 int b = data[index];
1688 index++;
1689
1690 /*
1691 if (HasMask())
1692 {
1693 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1694 gdk_image_put_pixel( mask_image, x, y, 1 );
1695 else
1696 gdk_image_put_pixel( mask_image, x, y, 0 );
1697 }
1698 */
1699
1700 switch (bpp)
1701 {
1702 case 8:
1703 {
1704 int pixel = -1;
1705 /*
1706 if (wxTheApp->m_colorCube)
1707 {
1708 pixel = wxTheApp->m_colorCube
1709 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1710 }
1711 else
1712 {
1713 */
1714 int max = 3 * (65536);
1715 for (int i = 0; i < 256; i++)
1716 {
1717 int rdiff = (r << 8) - colors[i].red;
1718 int gdiff = (g << 8) - colors[i].green;
1719 int bdiff = (b << 8) - colors[i].blue;
1720 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1721 if (sum < max) { pixel = i; max = sum; }
1722 }
1723 /*
1724 }
1725 */
1726 XPutPixel( data_image, x, y, pixel );
1727 break;
1728 }
1729 case 15:
1730 {
1731 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1732 XPutPixel( data_image, x, y, pixel );
1733 break;
1734 }
1735 case 16:
1736 {
1737 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1738 XPutPixel( data_image, x, y, pixel );
1739 break;
1740 }
1741 case 32:
1742 case 24:
1743 {
1744 int pixel = 0;
1745 switch (b_o)
1746 {
1747 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1748 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1749 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1750 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1751 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1752 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1753 }
1754 XPutPixel( data_image, x, y, pixel );
1755 }
1756 default: break;
1757 }
1758 } // for
1759 } // for
1760
1761 // Blit picture
1762
1763 XGCValues gcvalues;
1764 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
1765 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
1766 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
1767
1768 XDestroyImage( data_image );
1769 XFreeGC( dpy, gc );
1770
1771 /*
1772 // Blit mask
1773
1774 if (HasMask())
1775 {
1776 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1777
1778 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1779
1780 gdk_image_destroy( mask_image );
1781 gdk_gc_unref( mask_gc );
1782 }
1783 */
1784
1785 return bitmap;
1786 }
1787
1788 wxImage::wxImage( const wxBitmap &bitmap )
1789 {
1790 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
1791
1792 Display *dpy = (Display*) wxGetDisplay();
1793 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1794 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1795
1796 XImage *ximage = XGetImage( dpy,
1797 (Drawable)bitmap.GetPixmap(),
1798 0, 0,
1799 bitmap.GetWidth(), bitmap.GetHeight(),
1800 AllPlanes, ZPixmap );
1801
1802 wxCHECK_RET( ximage, _T("couldn't create image") );
1803
1804 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1805 char unsigned *data = GetData();
1806
1807 if (!data)
1808 {
1809 XDestroyImage( ximage );
1810 wxFAIL_MSG( _T("couldn't create image") );
1811 return;
1812 }
1813
1814 /*
1815 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1816 if (bitmap.GetMask())
1817 {
1818 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1819 0, 0,
1820 bitmap.GetWidth(), bitmap.GetHeight() );
1821
1822 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1823 }
1824 */
1825
1826 // Retrieve depth info
1827
1828 XVisualInfo vinfo_template;
1829 XVisualInfo *vi;
1830
1831 vinfo_template.visual = vis;
1832 vinfo_template.visualid = XVisualIDFromVisual( vis );
1833 vinfo_template.depth = bpp;
1834 int nitem = 0;
1835
1836 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1837
1838 wxCHECK_MSG( vi, wxNullBitmap, _T("no visual") );
1839
1840 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1841
1842 XFree( vi );
1843
1844 XColor colors[256];
1845 if (bpp == 8)
1846 {
1847 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
1848
1849 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1850 XQueryColors( dpy, cmap, colors, 256 );
1851 }
1852
1853 long pos = 0;
1854 for (int j = 0; j < bitmap.GetHeight(); j++)
1855 {
1856 for (int i = 0; i < bitmap.GetWidth(); i++)
1857 {
1858 int pixel = XGetPixel( ximage, i, j );
1859 if (bpp <= 8)
1860 {
1861 data[pos] = colors[pixel].red >> 8;
1862 data[pos+1] = colors[pixel].green >> 8;
1863 data[pos+2] = colors[pixel].blue >> 8;
1864 } else if (bpp == 15)
1865 {
1866 data[pos] = (pixel >> 7) & 0xf8;
1867 data[pos+1] = (pixel >> 2) & 0xf8;
1868 data[pos+2] = (pixel << 3) & 0xf8;
1869 } else if (bpp == 16)
1870 {
1871 data[pos] = (pixel >> 8) & 0xf8;
1872 data[pos+1] = (pixel >> 3) & 0xfc;
1873 data[pos+2] = (pixel << 3) & 0xf8;
1874 } else
1875 {
1876 data[pos] = (pixel >> 16) & 0xff;
1877 data[pos+1] = (pixel >> 8) & 0xff;
1878 data[pos+2] = pixel & 0xff;
1879 }
1880
1881 /*
1882 if (gdk_image_mask)
1883 {
1884 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1885 if (mask_pixel == 0)
1886 {
1887 data[pos] = 16;
1888 data[pos+1] = 16;
1889 data[pos+2] = 16;
1890 }
1891 }
1892 */
1893
1894 pos += 3;
1895 }
1896 }
1897
1898 XDestroyImage( ximage );
1899 /*
1900 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1901 */
1902 }
1903 #endif
1904
1905 // A module to allow wxImage initialization/cleanup
1906 // without calling these functions from app.cpp or from
1907 // the user's application.
1908
1909 class wxImageModule: public wxModule
1910 {
1911 DECLARE_DYNAMIC_CLASS(wxImageModule)
1912 public:
1913 wxImageModule() {}
1914 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
1915 void OnExit() { wxImage::CleanUpHandlers(); };
1916 };
1917
1918 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)