]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
Chianti, Pinot noir, WINE..
[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
589 #ifndef BI_RGB
590 #define BI_RGB 0
591 #define BI_RLE8 1
592 #define BI_RLE4 2
593 #endif
594
595 #ifndef BI_BITFIELDS
596 #define BI_BITFIELDS 3
597 #endif
598
599 #define poffset (line * width * 3 + column * 3)
600
601 bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
602 {
603 int rshift = 0, gshift = 0, bshift = 0;
604 wxUint8 aByte;
605 wxUint16 aWord;
606 wxInt32 dbuf[4], aDword,
607 rmask = 0, gmask = 0, bmask = 0;
608 wxInt8 bbuf[4];
609 struct _cmap {
610 unsigned char r, g, b;
611 } *cmap = NULL;
612
613 off_t start_offset = stream.TellI();
614
615 image->Destroy();
616
617 /*
618 * Read the BMP header
619 */
620
621 stream.Read( &bbuf, 2 );
622 stream.Read( dbuf, 4 * 4 );
623
624 wxInt32 size = wxINT32_SWAP_FROM_LE( dbuf[0] );
625 wxInt32 offset = wxINT32_SWAP_FROM_LE( dbuf[2] );
626
627 stream.Read(dbuf, 4 * 2);
628 int width = (int)wxINT32_SWAP_FROM_LE( dbuf[0] );
629 int height = (int)wxINT32_SWAP_FROM_LE( dbuf[1] );
630 if (width > 32767)
631 {
632 wxLogError( _T("Image width > 32767 pixels for file.") );
633 return FALSE;
634 }
635 if (height > 32767)
636 {
637 wxLogError( _T("Image height > 32767 pixels for file.") );
638 return FALSE;
639 }
640
641 stream.Read( &aWord, 2 );
642 /*
643 TODO
644 int planes = (int)wxUINT16_SWAP_FROM_LE( aWord );
645 */
646 stream.Read( &aWord, 2 );
647 int bpp = (int)wxUINT16_SWAP_FROM_LE( aWord );
648 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
649 {
650 wxLogError( _T("unknown bitdepth in file.") );
651 return FALSE;
652 }
653
654 stream.Read( dbuf, 4 * 4 );
655 int comp = (int)wxINT32_SWAP_FROM_LE( dbuf[0] );
656 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
657 {
658 wxLogError( _T("unknown encoding in Windows BMP file.") );
659 return FALSE;
660 }
661
662 stream.Read( dbuf, 4 * 2 );
663 int ncolors = (int)wxINT32_SWAP_FROM_LE( dbuf[0] );
664 if (ncolors == 0)
665 ncolors = 1 << bpp;
666 /* some more sanity checks */
667 if (((comp == BI_RLE4) && (bpp != 4)) ||
668 ((comp == BI_RLE8) && (bpp != 8)) ||
669 ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
670 {
671 wxLogError( _T("encoding of BMP doesn't match bitdepth.") );
672 return FALSE;
673 }
674 if (bpp < 16)
675 {
676 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
677 if (!cmap)
678 {
679 wxLogError( _T("Cannot allocate RAM for color map in BMP file.") );
680 return FALSE;
681 }
682 }
683 else
684 cmap = NULL;
685
686 image->Create( width, height );
687 unsigned char *ptr = image->GetData();
688 if (!ptr)
689 {
690 wxLogError( _T("Cannot allocate RAM for RGB data in file.") );
691 if (cmap)
692 free(cmap);
693 return FALSE;
694 }
695
696 /*
697 * Reading the palette, if it exists.
698 */
699 if (bpp < 16 && ncolors != 0)
700 {
701 for (int j = 0; j < ncolors; j++)
702 {
703 stream.Read( bbuf, 4 );
704 cmap[j].b = bbuf[0];
705 cmap[j].g = bbuf[1];
706 cmap[j].r = bbuf[2];
707 }
708 }
709 else if (bpp == 16 || bpp == 32)
710 {
711 if (comp == BI_BITFIELDS)
712 {
713 int bit = 0;
714 stream.Read( dbuf, 4 * 3 );
715 bmask = wxINT32_SWAP_FROM_LE( dbuf[0] );
716 gmask = wxINT32_SWAP_FROM_LE( dbuf[1] );
717 rmask = wxINT32_SWAP_FROM_LE( dbuf[2] );
718 /* find shift amount.. ugly, but i can't think of a better way */
719 for (bit = 0; bit < bpp; bit++)
720 {
721 if (bmask & (1 << bit))
722 bshift = bit;
723 if (gmask & (1 << bit))
724 gshift = bit;
725 if (rmask & (1 << bit))
726 rshift = bit;
727 }
728 }
729 else if (bpp == 16)
730 {
731 rmask = 0x7C00;
732 gmask = 0x03E0;
733 bmask = 0x001F;
734 rshift = 10;
735 gshift = 5;
736 bshift = 0;
737 }
738 else if (bpp == 32)
739 {
740 rmask = 0x00FF0000;
741 gmask = 0x0000FF00;
742 bmask = 0x000000FF;
743 rshift = 16;
744 gshift = 8;
745 bshift = 0;
746 }
747 }
748
749 /*
750 * Reading the image data
751 */
752 stream.SeekI( start_offset + offset );
753 unsigned char *data = ptr;
754
755 /* set the whole image to the background color */
756 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
757 {
758 for (int i = 0; i < width * height; i++)
759 {
760 *ptr++ = cmap[0].r;
761 *ptr++ = cmap[0].g;
762 *ptr++ = cmap[0].b;
763 }
764 ptr = data;
765 }
766
767 int line = 0;
768 int column = 0;
769 int linesize = ((width * bpp + 31) / 32) * 4;
770
771 /* BMPs are stored upside down */
772 for (line = (height - 1); line >= 0; line--)
773 {
774 int linepos = 0;
775 for (column = 0; column < width;)
776 {
777 if (bpp < 16)
778 {
779 int index = 0;
780 linepos++;
781 aByte = stream.GetC();
782 if (bpp == 1)
783 {
784 int bit = 0;
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 for (nibble = 0; nibble < 2; nibble++)
807 {
808 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
809 if (index >= 16)
810 index = 15;
811 ptr[poffset] = cmap[index].r;
812 ptr[poffset + 1] = cmap[index].g;
813 ptr[poffset + 2] = cmap[index].b;
814 column++;
815 }
816 }
817 }
818 else if (bpp == 8)
819 {
820 if (comp == BI_RLE8)
821 {
822 unsigned char first;
823 first = aByte;
824 aByte = stream.GetC();
825 if (first == 0)
826 {
827 if (aByte == 0)
828 {
829 /* column = width; */
830 }
831 else if (aByte == 1)
832 {
833 column = width;
834 line = -1;
835 }
836 else if (aByte == 2)
837 {
838 aByte = stream.GetC();
839 column += aByte;
840 linepos = column * bpp / 8;
841 aByte = stream.GetC();
842 line += aByte;
843 }
844 else
845 {
846 int absolute = aByte;
847 for (int k = 0; k < absolute; k++)
848 {
849 linepos++;
850 aByte = stream.GetC();
851 ptr[poffset ] = cmap[aByte].r;
852 ptr[poffset + 1] = cmap[aByte].g;
853 ptr[poffset + 2] = cmap[aByte].b;
854 column++;
855 }
856 if (absolute & 0x01)
857 aByte = stream.GetC();
858 }
859 }
860 else
861 {
862 for (int l = 0; l < first; l++)
863 {
864 ptr[poffset ] = cmap[aByte].r;
865 ptr[poffset + 1] = cmap[aByte].g;
866 ptr[poffset + 2] = cmap[aByte].b;
867 column++;
868 linepos++;
869 }
870 }
871 }
872 else
873 {
874 ptr[poffset ] = cmap[aByte].r;
875 ptr[poffset + 1] = cmap[aByte].g;
876 ptr[poffset + 2] = cmap[aByte].b;
877 column++;
878 linepos += size;
879 }
880 }
881 }
882 else if (bpp == 24)
883 {
884 stream.Read( &bbuf, 3 );
885 linepos += 3;
886 ptr[poffset ] = (unsigned char)bbuf[2];
887 ptr[poffset + 1] = (unsigned char)bbuf[1];
888 ptr[poffset + 2] = (unsigned char)bbuf[0];
889 column++;
890 }
891 else if (bpp == 16)
892 {
893 unsigned char temp;
894 stream.Read( &aWord, 2 );
895 aWord = wxUINT16_SWAP_FROM_LE( aWord );
896 linepos += 2;
897 temp = (aWord & rmask) >> rshift;
898 ptr[poffset] = temp;
899 temp = (aWord & gmask) >> gshift;
900 ptr[poffset + 1] = temp;
901 temp = (aWord & bmask) >> gshift;
902 ptr[poffset + 2] = temp;
903 column++;
904 }
905 else
906 {
907 unsigned char temp;
908 stream.Read( &aDword, 4 );
909 aDword = wxINT32_SWAP_FROM_LE( aDword );
910 linepos += 4;
911 temp = (aDword & rmask) >> rshift;
912 ptr[poffset] = temp;
913 temp = (aDword & gmask) >> gshift;
914 ptr[poffset + 1] = temp;
915 temp = (aDword & bmask) >> bshift;
916 ptr[poffset + 2] = temp;
917 column++;
918 }
919 }
920 while ((linepos < linesize) && (comp != 1) && (comp != 2))
921 {
922 stream.Read( &aByte, 1 );
923 linepos += 1;
924 if (stream.LastError() != wxStream_NOERROR)
925 break;
926 }
927 }
928 if (cmap)
929 free(cmap);
930
931 image->SetMask( FALSE );
932
933 return TRUE;
934 }
935 #endif // wxUSE_STREAMS
936
937 #ifdef __WXMSW__
938
939 wxBitmap wxImage::ConvertToBitmap() const
940 {
941 // sizeLimit is the MS upper limit for the DIB size
942 int sizeLimit = 1024*768*3;
943
944 // width and height of the device-dependent bitmap
945 int width = GetWidth();
946 int bmpHeight = GetHeight();
947
948 // calc the number of bytes per scanline and padding
949 int bytePerLine = width*3;
950 int sizeDWORD = sizeof( DWORD );
951 div_t lineBoundary = div( bytePerLine, sizeDWORD );
952 int padding = 0;
953 if( lineBoundary.rem > 0 )
954 {
955 padding = sizeDWORD - lineBoundary.rem;
956 bytePerLine += padding;
957 }
958 // calc the number of DIBs and heights of DIBs
959 int numDIB = 1;
960 int hRemain = 0;
961 int height = sizeLimit/bytePerLine;
962 if( height >= bmpHeight )
963 height = bmpHeight;
964 else
965 {
966 div_t result = div( bmpHeight, height );
967 numDIB = result.quot;
968 hRemain = result.rem;
969 if( hRemain >0 ) numDIB++;
970 }
971
972 // set bitmap parameters
973 wxBitmap bitmap;
974 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
975 bitmap.SetWidth( width );
976 bitmap.SetHeight( bmpHeight );
977 bitmap.SetDepth( wxDisplayDepth() );
978
979 // create a DIB header
980 int headersize = sizeof(BITMAPINFOHEADER);
981 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
982 wxCHECK_MSG( lpDIBh, bitmap, _T("could not allocate memory for DIB header") );
983 // Fill in the DIB header
984 lpDIBh->bmiHeader.biSize = headersize;
985 lpDIBh->bmiHeader.biWidth = (DWORD)width;
986 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
987 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
988 // the general formula for biSizeImage:
989 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
990 lpDIBh->bmiHeader.biPlanes = 1;
991 lpDIBh->bmiHeader.biBitCount = 24;
992 lpDIBh->bmiHeader.biCompression = BI_RGB;
993 lpDIBh->bmiHeader.biClrUsed = 0;
994 // These seem not really needed for our purpose here.
995 lpDIBh->bmiHeader.biClrImportant = 0;
996 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
997 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
998 // memory for DIB data
999 unsigned char *lpBits;
1000 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
1001 if( !lpBits )
1002 {
1003 wxFAIL_MSG( _T("could not allocate memory for DIB") );
1004 free( lpDIBh );
1005 return bitmap;
1006 }
1007
1008 // create and set the device-dependent bitmap
1009 HDC hdc = ::GetDC(NULL);
1010 HDC memdc = ::CreateCompatibleDC( hdc );
1011 HBITMAP hbitmap;
1012 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
1013 ::SelectObject( memdc, hbitmap);
1014
1015 // copy image data into DIB data and then into DDB (in a loop)
1016 unsigned char *data = GetData();
1017 int i, j, n;
1018 int origin = 0;
1019 unsigned char *ptdata = data;
1020 unsigned char *ptbits;
1021
1022 for( n=0; n<numDIB; n++ )
1023 {
1024 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
1025 {
1026 // redefine height and size of the (possibly) last smaller DIB
1027 // memory is not reallocated
1028 height = hRemain;
1029 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1030 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1031 }
1032 ptbits = lpBits;
1033
1034 for( j=0; j<height; j++ )
1035 {
1036 for( i=0; i<width; i++ )
1037 {
1038 *(ptbits++) = *(ptdata+2);
1039 *(ptbits++) = *(ptdata+1);
1040 *(ptbits++) = *(ptdata );
1041 ptdata += 3;
1042 }
1043 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
1044 }
1045 ::StretchDIBits( memdc, 0, origin, width, height,\
1046 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1047 origin += height;
1048 // if numDIB = 1, lines below can also be used
1049 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1050 // The above line is equivalent to the following two lines.
1051 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1052 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1053 // or the following lines
1054 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1055 // HDC memdc = ::CreateCompatibleDC( hdc );
1056 // ::SelectObject( memdc, hbitmap);
1057 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1058 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1059 // ::SelectObject( memdc, 0 );
1060 // ::DeleteDC( memdc );
1061 }
1062 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
1063
1064 // similarly, created an mono-bitmap for the possible mask
1065 if( HasMask() )
1066 {
1067 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
1068 ::SelectObject( memdc, hbitmap);
1069 if( numDIB == 1 ) height = bmpHeight;
1070 else height = sizeLimit/bytePerLine;
1071 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1072 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1073 origin = 0;
1074 unsigned char r = GetMaskRed();
1075 unsigned char g = GetMaskGreen();
1076 unsigned char b = GetMaskBlue();
1077 unsigned char zero = 0, one = 255;
1078 ptdata = data;
1079 for( n=0; n<numDIB; n++ )
1080 {
1081 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
1082 {
1083 // redefine height and size of the (possibly) last smaller DIB
1084 // memory is not reallocated
1085 height = hRemain;
1086 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1087 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1088 }
1089 ptbits = lpBits;
1090 for( int j=0; j<height; j++ )
1091 {
1092 for(i=0; i<width; i++ )
1093 {
1094 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
1095 {
1096 *(ptbits++) = one;
1097 *(ptbits++) = one;
1098 *(ptbits++) = one;
1099 }
1100 else
1101 {
1102 *(ptbits++) = zero;
1103 *(ptbits++) = zero;
1104 *(ptbits++) = zero;
1105 }
1106 }
1107 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
1108 }
1109 ::StretchDIBits( memdc, 0, origin, width, height,\
1110 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1111 origin += height;
1112 }
1113 // create a wxMask object
1114 wxMask *mask = new wxMask();
1115 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
1116 bitmap.SetMask( mask );
1117 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1118 /* The following can also be used but is slow to run
1119 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1120 wxMask *mask = new wxMask( bitmap, colour );
1121 bitmap.SetMask( mask );
1122 */
1123 }
1124
1125 // free allocated resources
1126 ::SelectObject( memdc, 0 );
1127 ::DeleteDC( memdc );
1128 ::ReleaseDC(NULL, hdc);
1129 free(lpDIBh);
1130 free(lpBits);
1131
1132 // check the wxBitmap object
1133 if( bitmap.GetHBITMAP() )
1134 bitmap.SetOk( TRUE );
1135 else
1136 bitmap.SetOk( FALSE );
1137
1138 return bitmap;
1139 }
1140
1141 wxImage::wxImage( const wxBitmap &bitmap )
1142 {
1143 // check the bitmap
1144 if( !bitmap.Ok() )
1145 {
1146 wxFAIL_MSG( _T("invalid bitmap") );
1147 return;
1148 }
1149
1150 // create an wxImage object
1151 int width = bitmap.GetWidth();
1152 int height = bitmap.GetHeight();
1153 Create( width, height );
1154 unsigned char *data = GetData();
1155 if( !data )
1156 {
1157 wxFAIL_MSG( _T("could not allocate data for image") );
1158 return;
1159 }
1160
1161 // calc the number of bytes per scanline and padding in the DIB
1162 int bytePerLine = width*3;
1163 int sizeDWORD = sizeof( DWORD );
1164 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1165 int padding = 0;
1166 if( lineBoundary.rem > 0 )
1167 {
1168 padding = sizeDWORD - lineBoundary.rem;
1169 bytePerLine += padding;
1170 }
1171
1172 // create a DIB header
1173 int headersize = sizeof(BITMAPINFOHEADER);
1174 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1175 if( !lpDIBh )
1176 {
1177 wxFAIL_MSG( _T("could not allocate data for DIB header") );
1178 free( data );
1179 return;
1180 }
1181 // Fill in the DIB header
1182 lpDIBh->bmiHeader.biSize = headersize;
1183 lpDIBh->bmiHeader.biWidth = width;
1184 lpDIBh->bmiHeader.biHeight = -height;
1185 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1186 lpDIBh->bmiHeader.biPlanes = 1;
1187 lpDIBh->bmiHeader.biBitCount = 24;
1188 lpDIBh->bmiHeader.biCompression = BI_RGB;
1189 lpDIBh->bmiHeader.biClrUsed = 0;
1190 // These seem not really needed for our purpose here.
1191 lpDIBh->bmiHeader.biClrImportant = 0;
1192 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1193 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1194 // memory for DIB data
1195 unsigned char *lpBits;
1196 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1197 if( !lpBits )
1198 {
1199 wxFAIL_MSG( _T("could not allocate data for DIB") );
1200 free( data );
1201 free( lpDIBh );
1202 return;
1203 }
1204
1205 // copy data from the device-dependent bitmap to the DIB
1206 HDC hdc = ::GetDC(NULL);
1207 HBITMAP hbitmap;
1208 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1209 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1210
1211 // copy DIB data into the wxImage object
1212 int i, j;
1213 unsigned char *ptdata = data;
1214 unsigned char *ptbits = lpBits;
1215 for( i=0; i<height; i++ )
1216 {
1217 for( j=0; j<width; j++ )
1218 {
1219 *(ptdata++) = *(ptbits+2);
1220 *(ptdata++) = *(ptbits+1);
1221 *(ptdata++) = *(ptbits );
1222 ptbits += 3;
1223 }
1224 ptbits += padding;
1225 }
1226
1227 // similarly, set data according to the possible mask bitmap
1228 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1229 {
1230 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1231 // memory DC created, color set, data copied, and memory DC deleted
1232 HDC memdc = ::CreateCompatibleDC( hdc );
1233 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1234 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1235 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1236 ::DeleteDC( memdc );
1237 // background color set to RGB(16,16,16) in consistent with wxGTK
1238 unsigned char r=16, g=16, b=16;
1239 ptdata = data;
1240 ptbits = lpBits;
1241 for( i=0; i<height; i++ )
1242 {
1243 for( j=0; j<width; j++ )
1244 {
1245 if( *ptbits != 0 )
1246 ptdata += 3;
1247 else
1248 {
1249 *(ptdata++) = r;
1250 *(ptdata++) = g;
1251 *(ptdata++) = b;
1252 }
1253 ptbits += 3;
1254 }
1255 ptbits += padding;
1256 }
1257 SetMaskColour( r, g, b );
1258 SetMask( TRUE );
1259 }
1260 else
1261 {
1262 SetMask( FALSE );
1263 }
1264 // free allocated resources
1265 ::ReleaseDC(NULL, hdc);
1266 free(lpDIBh);
1267 free(lpBits);
1268 }
1269
1270 #endif
1271
1272 #ifdef __WXGTK__
1273
1274 #include "gtk/gtk.h"
1275 #include "gdk/gdk.h"
1276 #include "gdk/gdkx.h"
1277
1278 #if (GTK_MINOR_VERSION > 0)
1279 #include "gdk/gdkrgb.h"
1280 #endif
1281
1282 wxBitmap wxImage::ConvertToBitmap() const
1283 {
1284 wxBitmap bitmap;
1285
1286 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
1287
1288 int width = GetWidth();
1289 int height = GetHeight();
1290
1291 bitmap.SetHeight( height );
1292 bitmap.SetWidth( width );
1293
1294 bitmap.SetPixmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, -1 ) );
1295
1296 // Retrieve depth
1297
1298 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1299 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1300 int bpp = visual->depth;
1301
1302 bitmap.SetDepth( bpp );
1303
1304 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1305 if (bpp < 8) bpp = 8;
1306
1307 #if (GTK_MINOR_VERSION > 0)
1308
1309 if (!HasMask() && (bpp > 8))
1310 {
1311 static bool s_hasInitialized = FALSE;
1312
1313 if (!s_hasInitialized)
1314 {
1315 gdk_rgb_init();
1316 s_hasInitialized = TRUE;
1317 }
1318
1319 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
1320
1321 gdk_draw_rgb_image( bitmap.GetPixmap(),
1322 gc,
1323 0, 0,
1324 width, height,
1325 GDK_RGB_DITHER_NONE,
1326 GetData(),
1327 width*3 );
1328
1329 gdk_gc_unref( gc );
1330
1331 return bitmap;
1332 }
1333
1334 #endif
1335
1336 // Create picture image
1337
1338 GdkImage *data_image =
1339 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
1340
1341 // Create mask image
1342
1343 GdkImage *mask_image = (GdkImage*) NULL;
1344
1345 if (HasMask())
1346 {
1347 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1348
1349 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1350
1351 wxMask *mask = new wxMask();
1352 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1353
1354 bitmap.SetMask( mask );
1355 }
1356
1357 // Render
1358
1359 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1360 byte_order b_o = RGB;
1361
1362 if (bpp >= 24)
1363 {
1364 GdkVisual *visual = gdk_visual_get_system();
1365 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1366 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1367 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1368 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1369 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1370 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1371 }
1372
1373 int r_mask = GetMaskRed();
1374 int g_mask = GetMaskGreen();
1375 int b_mask = GetMaskBlue();
1376
1377 unsigned char* data = GetData();
1378
1379 int index = 0;
1380 for (int y = 0; y < height; y++)
1381 {
1382 for (int x = 0; x < width; x++)
1383 {
1384 int r = data[index];
1385 index++;
1386 int g = data[index];
1387 index++;
1388 int b = data[index];
1389 index++;
1390
1391 if (HasMask())
1392 {
1393 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1394 gdk_image_put_pixel( mask_image, x, y, 1 );
1395 else
1396 gdk_image_put_pixel( mask_image, x, y, 0 );
1397 }
1398
1399 if (HasMask())
1400 {
1401 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1402 gdk_image_put_pixel( mask_image, x, y, 1 );
1403 else
1404 gdk_image_put_pixel( mask_image, x, y, 0 );
1405 }
1406
1407 switch (bpp)
1408 {
1409 case 8:
1410 {
1411 int pixel = -1;
1412 if (wxTheApp->m_colorCube)
1413 {
1414 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1415 }
1416 else
1417 {
1418 GdkColormap *cmap = gtk_widget_get_default_colormap();
1419 GdkColor *colors = cmap->colors;
1420 int max = 3 * (65536);
1421
1422 for (int i = 0; i < cmap->size; i++)
1423 {
1424 int rdiff = (r << 8) - colors[i].red;
1425 int gdiff = (g << 8) - colors[i].green;
1426 int bdiff = (b << 8) - colors[i].blue;
1427 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1428 if (sum < max) { pixel = i; max = sum; }
1429 }
1430 }
1431
1432 gdk_image_put_pixel( data_image, x, y, pixel );
1433
1434 break;
1435 }
1436 case 15:
1437 {
1438 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1439 gdk_image_put_pixel( data_image, x, y, pixel );
1440 break;
1441 }
1442 case 16:
1443 {
1444 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1445 gdk_image_put_pixel( data_image, x, y, pixel );
1446 break;
1447 }
1448 case 32:
1449 case 24:
1450 {
1451 guint32 pixel = 0;
1452 switch (b_o)
1453 {
1454 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1455 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1456 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1457 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1458 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1459 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1460 }
1461 gdk_image_put_pixel( data_image, x, y, pixel );
1462 }
1463 default: break;
1464 }
1465 } // for
1466 } // for
1467
1468 // Blit picture
1469
1470 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1471
1472 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1473
1474 gdk_image_destroy( data_image );
1475 gdk_gc_unref( data_gc );
1476
1477 // Blit mask
1478
1479 if (HasMask())
1480 {
1481 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1482
1483 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1484
1485 gdk_image_destroy( mask_image );
1486 gdk_gc_unref( mask_gc );
1487 }
1488
1489 return bitmap;
1490 }
1491
1492 wxImage::wxImage( const wxBitmap &bitmap )
1493 {
1494 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
1495
1496 GdkImage *gdk_image = gdk_image_get( bitmap.GetPixmap(),
1497 0, 0,
1498 bitmap.GetWidth(), bitmap.GetHeight() );
1499
1500 wxCHECK_RET( gdk_image, _T("couldn't create image") );
1501
1502 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1503 char unsigned *data = GetData();
1504
1505 if (!data)
1506 {
1507 gdk_image_destroy( gdk_image );
1508 wxFAIL_MSG( _T("couldn't create image") );
1509 return;
1510 }
1511
1512 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1513 if (bitmap.GetMask())
1514 {
1515 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1516 0, 0,
1517 bitmap.GetWidth(), bitmap.GetHeight() );
1518
1519 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1520 }
1521
1522 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1523 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1524 int bpp = visual->depth;
1525 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1526
1527 GdkColormap *cmap = gtk_widget_get_default_colormap();
1528
1529 long pos = 0;
1530 for (int j = 0; j < bitmap.GetHeight(); j++)
1531 {
1532 for (int i = 0; i < bitmap.GetWidth(); i++)
1533 {
1534 int pixel = gdk_image_get_pixel( gdk_image, i, j );
1535 if (bpp <= 8)
1536 {
1537 data[pos] = cmap->colors[pixel].red >> 8;
1538 data[pos+1] = cmap->colors[pixel].green >> 8;
1539 data[pos+2] = cmap->colors[pixel].blue >> 8;
1540 } else if (bpp == 15)
1541 {
1542 data[pos] = (pixel >> 7) & 0xf8;
1543 data[pos+1] = (pixel >> 2) & 0xf8;
1544 data[pos+2] = (pixel << 3) & 0xf8;
1545 } else if (bpp == 16)
1546 {
1547 data[pos] = (pixel >> 8) & 0xf8;
1548 data[pos+1] = (pixel >> 3) & 0xfc;
1549 data[pos+2] = (pixel << 3) & 0xf8;
1550 } else
1551 {
1552 data[pos] = (pixel >> 16) & 0xff;
1553 data[pos+1] = (pixel >> 8) & 0xff;
1554 data[pos+2] = pixel & 0xff;
1555 }
1556
1557 if (gdk_image_mask)
1558 {
1559 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1560 if (mask_pixel == 0)
1561 {
1562 data[pos] = 16;
1563 data[pos+1] = 16;
1564 data[pos+2] = 16;
1565 }
1566 }
1567
1568 pos += 3;
1569 }
1570 }
1571
1572 gdk_image_destroy( gdk_image );
1573 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1574 }
1575
1576 #endif
1577
1578 #ifdef __WXMOTIF__
1579
1580 #include <Xm/Xm.h>
1581 #include "wx/utils.h"
1582 #include <math.h>
1583
1584 wxBitmap wxImage::ConvertToBitmap() const
1585 {
1586 wxBitmap bitmap;
1587
1588 wxCHECK_MSG( Ok(), bitmap, _T("invalid image") );
1589
1590 int width = GetWidth();
1591 int height = GetHeight();
1592
1593 bitmap.SetHeight( height );
1594 bitmap.SetWidth( width );
1595
1596 Display *dpy = (Display*) wxGetDisplay();
1597 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1598 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1599
1600 // Create image
1601
1602 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
1603 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
1604
1605 bitmap.Create( width, height, bpp );
1606
1607 /*
1608 // Create mask
1609
1610 GdkImage *mask_image = (GdkImage*) NULL;
1611
1612 if (HasMask())
1613 {
1614 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1615
1616 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1617
1618 wxMask *mask = new wxMask();
1619 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1620
1621 bitmap.SetMask( mask );
1622 }
1623 */
1624
1625 // Retrieve depth info
1626
1627 XVisualInfo vinfo_template;
1628 XVisualInfo *vi;
1629
1630 vinfo_template.visual = vis;
1631 vinfo_template.visualid = XVisualIDFromVisual( vis );
1632 vinfo_template.depth = bpp;
1633 int nitem = 0;
1634
1635 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1636
1637 wxCHECK_MSG( vi, wxNullBitmap, _T("no visual") );
1638
1639 XFree( vi );
1640
1641 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1642 if (bpp < 8) bpp = 8;
1643
1644 // Render
1645
1646 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1647 byte_order b_o = RGB;
1648
1649 if (bpp >= 24)
1650 {
1651 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1652 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1653 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1654 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1655 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1656 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1657 }
1658
1659 /*
1660 int r_mask = GetMaskRed();
1661 int g_mask = GetMaskGreen();
1662 int b_mask = GetMaskBlue();
1663 */
1664
1665 XColor colors[256];
1666 if (bpp == 8)
1667 {
1668 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
1669
1670 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1671 XQueryColors( dpy, cmap, colors, 256 );
1672 }
1673
1674 unsigned char* data = GetData();
1675
1676 int index = 0;
1677 for (int y = 0; y < height; y++)
1678 {
1679 for (int x = 0; x < width; x++)
1680 {
1681 int r = data[index];
1682 index++;
1683 int g = data[index];
1684 index++;
1685 int b = data[index];
1686 index++;
1687
1688 /*
1689 if (HasMask())
1690 {
1691 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1692 gdk_image_put_pixel( mask_image, x, y, 1 );
1693 else
1694 gdk_image_put_pixel( mask_image, x, y, 0 );
1695 }
1696 */
1697
1698 switch (bpp)
1699 {
1700 case 8:
1701 {
1702 int pixel = -1;
1703 /*
1704 if (wxTheApp->m_colorCube)
1705 {
1706 pixel = wxTheApp->m_colorCube
1707 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1708 }
1709 else
1710 {
1711 */
1712 int max = 3 * (65536);
1713 for (int i = 0; i < 256; i++)
1714 {
1715 int rdiff = (r << 8) - colors[i].red;
1716 int gdiff = (g << 8) - colors[i].green;
1717 int bdiff = (b << 8) - colors[i].blue;
1718 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1719 if (sum < max) { pixel = i; max = sum; }
1720 }
1721 /*
1722 }
1723 */
1724 XPutPixel( data_image, x, y, pixel );
1725 break;
1726 }
1727 case 15:
1728 {
1729 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1730 XPutPixel( data_image, x, y, pixel );
1731 break;
1732 }
1733 case 16:
1734 {
1735 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1736 XPutPixel( data_image, x, y, pixel );
1737 break;
1738 }
1739 case 32:
1740 case 24:
1741 {
1742 int pixel = 0;
1743 switch (b_o)
1744 {
1745 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1746 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1747 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1748 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1749 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1750 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1751 }
1752 XPutPixel( data_image, x, y, pixel );
1753 }
1754 default: break;
1755 }
1756 } // for
1757 } // for
1758
1759 // Blit picture
1760
1761 XGCValues gcvalues;
1762 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
1763 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
1764 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
1765
1766 XDestroyImage( data_image );
1767 XFreeGC( dpy, gc );
1768
1769 /*
1770 // Blit mask
1771
1772 if (HasMask())
1773 {
1774 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1775
1776 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1777
1778 gdk_image_destroy( mask_image );
1779 gdk_gc_unref( mask_gc );
1780 }
1781 */
1782
1783 return bitmap;
1784 }
1785
1786 wxImage::wxImage( const wxBitmap &bitmap )
1787 {
1788 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
1789
1790 Display *dpy = (Display*) wxGetDisplay();
1791 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1792 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1793
1794 XImage *ximage = XGetImage( dpy,
1795 (Drawable)bitmap.GetPixmap(),
1796 0, 0,
1797 bitmap.GetWidth(), bitmap.GetHeight(),
1798 AllPlanes, ZPixmap );
1799
1800 wxCHECK_RET( ximage, _T("couldn't create image") );
1801
1802 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1803 char unsigned *data = GetData();
1804
1805 if (!data)
1806 {
1807 XDestroyImage( ximage );
1808 wxFAIL_MSG( _T("couldn't create image") );
1809 return;
1810 }
1811
1812 /*
1813 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1814 if (bitmap.GetMask())
1815 {
1816 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1817 0, 0,
1818 bitmap.GetWidth(), bitmap.GetHeight() );
1819
1820 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1821 }
1822 */
1823
1824 // Retrieve depth info
1825
1826 XVisualInfo vinfo_template;
1827 XVisualInfo *vi;
1828
1829 vinfo_template.visual = vis;
1830 vinfo_template.visualid = XVisualIDFromVisual( vis );
1831 vinfo_template.depth = bpp;
1832 int nitem = 0;
1833
1834 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1835
1836 wxCHECK_MSG( vi, wxNullBitmap, _T("no visual") );
1837
1838 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1839
1840 XFree( vi );
1841
1842 XColor colors[256];
1843 if (bpp == 8)
1844 {
1845 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
1846
1847 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1848 XQueryColors( dpy, cmap, colors, 256 );
1849 }
1850
1851 long pos = 0;
1852 for (int j = 0; j < bitmap.GetHeight(); j++)
1853 {
1854 for (int i = 0; i < bitmap.GetWidth(); i++)
1855 {
1856 int pixel = XGetPixel( ximage, i, j );
1857 if (bpp <= 8)
1858 {
1859 data[pos] = colors[pixel].red >> 8;
1860 data[pos+1] = colors[pixel].green >> 8;
1861 data[pos+2] = colors[pixel].blue >> 8;
1862 } else if (bpp == 15)
1863 {
1864 data[pos] = (pixel >> 7) & 0xf8;
1865 data[pos+1] = (pixel >> 2) & 0xf8;
1866 data[pos+2] = (pixel << 3) & 0xf8;
1867 } else if (bpp == 16)
1868 {
1869 data[pos] = (pixel >> 8) & 0xf8;
1870 data[pos+1] = (pixel >> 3) & 0xfc;
1871 data[pos+2] = (pixel << 3) & 0xf8;
1872 } else
1873 {
1874 data[pos] = (pixel >> 16) & 0xff;
1875 data[pos+1] = (pixel >> 8) & 0xff;
1876 data[pos+2] = pixel & 0xff;
1877 }
1878
1879 /*
1880 if (gdk_image_mask)
1881 {
1882 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1883 if (mask_pixel == 0)
1884 {
1885 data[pos] = 16;
1886 data[pos+1] = 16;
1887 data[pos+2] = 16;
1888 }
1889 }
1890 */
1891
1892 pos += 3;
1893 }
1894 }
1895
1896 XDestroyImage( ximage );
1897 /*
1898 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1899 */
1900 }
1901 #endif
1902
1903 // A module to allow wxImage initialization/cleanup
1904 // without calling these functions from app.cpp or from
1905 // the user's application.
1906
1907 class wxImageModule: public wxModule
1908 {
1909 DECLARE_DYNAMIC_CLASS(wxImageModule)
1910 public:
1911 wxImageModule() {}
1912 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
1913 void OnExit() { wxImage::CleanUpHandlers(); };
1914 };
1915
1916 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)