]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
ee8a4a1ec8ac1cba54e9285fe69ee99417400c08
[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 #ifdef wxUSE_LIBPNG
27 #include "../png/png.h"
28 #endif
29 #include "wx/filefn.h"
30 #include "wx/wfstream.h"
31
32 #ifdef __WXMSW__
33 #include <windows.h>
34 #endif
35
36 //-----------------------------------------------------------------------------
37 // wxImage
38 //-----------------------------------------------------------------------------
39
40 class wxImageRefData: public wxObjectRefData
41 {
42
43 public:
44 wxImageRefData(void);
45 ~wxImageRefData(void);
46
47 int m_width;
48 int m_height;
49 unsigned char *m_data;
50 bool m_hasMask;
51 unsigned char m_maskRed,m_maskGreen,m_maskBlue;
52 bool m_ok;
53 };
54
55 wxImageRefData::wxImageRefData(void)
56 {
57 m_width = 0;
58 m_height = 0;
59 m_data = (unsigned char*) NULL;
60 m_ok = FALSE;
61 m_maskRed = 0;
62 m_maskGreen = 0;
63 m_maskBlue = 0;
64 m_hasMask = FALSE;
65 }
66
67 wxImageRefData::~wxImageRefData(void)
68 {
69 if (m_data) free( m_data );
70 }
71
72 wxList wxImage::sm_handlers;
73
74 //-----------------------------------------------------------------------------
75
76 #define M_IMGDATA ((wxImageRefData *)m_refData)
77
78 #if !USE_SHARED_LIBRARIES
79 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
80 #endif
81
82 wxImage::wxImage()
83 {
84 }
85
86 wxImage::wxImage( int width, int height )
87 {
88 Create( width, height );
89 }
90
91 wxImage::wxImage( const wxString& name, long type )
92 {
93 LoadFile( name, type );
94 }
95
96 wxImage::wxImage( wxInputStream& stream, long type )
97 {
98 LoadFile( stream, type );
99 }
100
101 wxImage::wxImage( const wxImage& image )
102 {
103 Ref(image);
104 }
105
106 wxImage::wxImage( const wxImage* image )
107 {
108 if (image) Ref(*image);
109 }
110
111 void wxImage::Create( int width, int height )
112 {
113 m_refData = new wxImageRefData();
114
115 M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
116 if (M_IMGDATA->m_data)
117 {
118 for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
119
120 M_IMGDATA->m_width = width;
121 M_IMGDATA->m_height = height;
122 M_IMGDATA->m_ok = TRUE;
123 }
124 else
125 {
126 UnRef();
127 }
128 }
129
130 void wxImage::Destroy()
131 {
132 UnRef();
133 }
134
135 wxImage wxImage::Scale( int width, int height )
136 {
137 wxImage image;
138
139 wxCHECK_MSG( Ok(), image, "invlaid image" );
140
141 wxCHECK_MSG( (width > 0) && (height > 0), image, "invalid image size" );
142
143 image.Create( width, height );
144
145 char unsigned *data = image.GetData();
146
147 wxCHECK_MSG( data, image, "unable to create image" );
148
149 if (M_IMGDATA->m_hasMask)
150 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
151
152 double xscale = (double)width / (double)M_IMGDATA->m_width;
153 double yscale = (double)height / (double)M_IMGDATA->m_height;
154
155 for (int j = 0; j < height; j++)
156 {
157 for (int i = 0; i < width; i++)
158 {
159 int new_pos = 3*(j*width + i);
160 int old_pos = 3*((long)(j/yscale)*M_IMGDATA->m_width + (long)(i/xscale));
161 data[ new_pos ] = M_IMGDATA->m_data[ old_pos ];
162 data[ new_pos+1 ] = M_IMGDATA->m_data[ old_pos+1 ];
163 data[ new_pos+2 ] = M_IMGDATA->m_data[ old_pos+2 ];
164 }
165 }
166
167 return image;
168 }
169
170 void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
171 {
172 wxCHECK_RET( Ok(), "invalid image" );
173
174 int w = M_IMGDATA->m_width;
175 int h = M_IMGDATA->m_height;
176
177 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), "invalid image index" );
178
179 long pos = (y * w + x) * 3;
180
181 M_IMGDATA->m_data[ pos ] = r;
182 M_IMGDATA->m_data[ pos+1 ] = g;
183 M_IMGDATA->m_data[ pos+2 ] = b;
184 }
185
186 unsigned char wxImage::GetRed( int x, int y )
187 {
188 wxCHECK_MSG( Ok(), 0, "invalid image" );
189
190 int w = M_IMGDATA->m_width;
191 int h = M_IMGDATA->m_height;
192
193 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
194
195 long pos = (y * w + x) * 3;
196
197 return M_IMGDATA->m_data[pos];
198 }
199
200 unsigned char wxImage::GetGreen( int x, int y )
201 {
202 wxCHECK_MSG( Ok(), 0, "invalid image" );
203
204 int w = M_IMGDATA->m_width;
205 int h = M_IMGDATA->m_height;
206
207 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
208
209 long pos = (y * w + x) * 3;
210
211 return M_IMGDATA->m_data[pos+1];
212 }
213
214 unsigned char wxImage::GetBlue( int x, int y )
215 {
216 wxCHECK_MSG( Ok(), 0, "invalid image" );
217
218 int w = M_IMGDATA->m_width;
219 int h = M_IMGDATA->m_height;
220
221 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
222
223 long pos = (y * w + x) * 3;
224
225 return M_IMGDATA->m_data[pos+2];
226 }
227
228 bool wxImage::Ok() const
229 {
230 return (M_IMGDATA && M_IMGDATA->m_ok);
231 }
232
233 char unsigned *wxImage::GetData() const
234 {
235 wxCHECK_MSG( Ok(), (char unsigned *)NULL, "invalid image" );
236
237 return M_IMGDATA->m_data;
238 }
239
240 void wxImage::SetData( char unsigned *WXUNUSED(data) )
241 {
242 wxCHECK_RET( Ok(), "invalid image" );
243 }
244
245 void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
246 {
247 wxCHECK_RET( Ok(), "invalid image" );
248
249 M_IMGDATA->m_maskRed = r;
250 M_IMGDATA->m_maskGreen = g;
251 M_IMGDATA->m_maskBlue = b;
252 M_IMGDATA->m_hasMask = TRUE;
253 }
254
255 unsigned char wxImage::GetMaskRed() const
256 {
257 wxCHECK_MSG( Ok(), 0, "invalid image" );
258
259 return M_IMGDATA->m_maskRed;
260 }
261
262 unsigned char wxImage::GetMaskGreen() const
263 {
264 wxCHECK_MSG( Ok(), 0, "invalid image" );
265
266 return M_IMGDATA->m_maskGreen;
267 }
268
269 unsigned char wxImage::GetMaskBlue() const
270 {
271 wxCHECK_MSG( Ok(), 0, "invalid image" );
272
273 return M_IMGDATA->m_maskBlue;
274 }
275
276 void wxImage::SetMask( bool mask )
277 {
278 wxCHECK_RET( Ok(), "invalid image" );
279
280 M_IMGDATA->m_hasMask = mask;
281 }
282
283 bool wxImage::HasMask() const
284 {
285 wxCHECK_MSG( Ok(), FALSE, "invalid image" );
286
287 return M_IMGDATA->m_hasMask;
288 }
289
290 int wxImage::GetWidth() const
291 {
292 wxCHECK_MSG( Ok(), 0, "invalid image" );
293
294 return M_IMGDATA->m_width;
295 }
296
297 int wxImage::GetHeight() const
298 {
299 wxCHECK_MSG( Ok(), 0, "invalid image" );
300
301 return M_IMGDATA->m_height;
302 }
303
304 bool wxImage::LoadFile( const wxString& filename, long type )
305 {
306 if (wxFileExists(filename))
307 {
308 wxFileInputStream stream(filename);
309 return LoadFile(stream, type);
310 }
311
312 else {
313 wxLogWarning( "Image file does not exist." );
314
315 return FALSE;
316 }
317 }
318
319 bool wxImage::LoadFile( wxInputStream& stream, long type )
320 {
321 UnRef();
322
323 m_refData = new wxImageRefData;
324
325 wxImageHandler *handler = FindHandler(type);
326
327 if (handler == NULL)
328 {
329 wxLogWarning( "No image handler for type %d defined.", type );
330
331 return FALSE;
332 }
333
334 return handler->LoadFile( this, stream );
335 }
336
337 bool wxImage::SaveFile( const wxString& filename, int type )
338 {
339 wxFileOutputStream stream(filename);
340
341 if ( stream.LastError() == wxStream_NOERROR )
342 return SaveFile(stream, type);
343 else
344 return FALSE;
345 }
346
347 bool wxImage::SaveFile( wxOutputStream& stream, int type )
348 {
349 wxCHECK_MSG( Ok(), FALSE, "invalid image" );
350
351 wxImageHandler *handler = FindHandler(type);
352
353 if (handler == NULL)
354 {
355 wxLogWarning( "No image handler for type %d defined.", type );
356
357 return FALSE;
358 }
359
360 return handler->SaveFile( this, stream );
361 }
362
363 void wxImage::AddHandler( wxImageHandler *handler )
364 {
365 sm_handlers.Append( handler );
366 }
367
368 void wxImage::InsertHandler( wxImageHandler *handler )
369 {
370 sm_handlers.Insert( handler );
371 }
372
373 bool wxImage::RemoveHandler( const wxString& name )
374 {
375 wxImageHandler *handler = FindHandler(name);
376 if (handler)
377 {
378 sm_handlers.DeleteObject(handler);
379 return TRUE;
380 }
381 else
382 return FALSE;
383 }
384
385 wxImageHandler *wxImage::FindHandler( const wxString& name )
386 {
387 wxNode *node = sm_handlers.First();
388 while (node)
389 {
390 wxImageHandler *handler = (wxImageHandler*)node->Data();
391 if (handler->GetName() == name) return handler;
392 node = node->Next();
393 }
394 return (wxImageHandler *)NULL;
395 }
396
397 wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
398 {
399 wxNode *node = sm_handlers.First();
400 while (node)
401 {
402 wxImageHandler *handler = (wxImageHandler*)node->Data();
403 if ( handler->GetExtension() == extension &&
404 (bitmapType == -1 || handler->GetType() == bitmapType) )
405 return handler;
406 node = node->Next();
407 }
408 return (wxImageHandler*)NULL;
409 }
410
411 wxImageHandler *wxImage::FindHandler( long bitmapType )
412 {
413 wxNode *node = sm_handlers.First();
414 while (node)
415 {
416 wxImageHandler *handler = (wxImageHandler *)node->Data();
417 if (handler->GetType() == bitmapType) return handler;
418 node = node->Next();
419 }
420 return NULL;
421 }
422
423 void wxImage::InitStandardHandlers()
424 {
425 AddHandler( new wxBMPHandler );
426 #ifdef wxUSE_LIBPNG
427 AddHandler( new wxPNGHandler );
428 #endif
429 }
430
431 void wxImage::CleanUpHandlers()
432 {
433 wxNode *node = sm_handlers.First();
434 while (node)
435 {
436 wxImageHandler *handler = (wxImageHandler *)node->Data();
437 wxNode *next = node->Next();
438 delete handler;
439 delete node;
440 node = next;
441 }
442 }
443
444 //-----------------------------------------------------------------------------
445 // wxImageHandler
446 //-----------------------------------------------------------------------------
447
448 #if !USE_SHARED_LIBRARIES
449 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler,wxObject)
450 #endif
451
452 bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream) )
453 {
454 return FALSE;
455 }
456
457 bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream) )
458 {
459 return FALSE;
460 }
461
462 //-----------------------------------------------------------------------------
463 // wxPNGHandler
464 //-----------------------------------------------------------------------------
465
466 #ifdef wxUSE_LIBPNG
467
468 #if !USE_SHARED_LIBRARIES
469 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
470 #endif
471
472
473 static void _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
474 {
475 ((wxInputStream*) png_get_io_ptr( png_ptr )) -> Read(data, length);
476 }
477
478 static void _PNG_stream_writer( png_structp png_ptr, png_bytep data, png_size_t length )
479 {
480 ((wxOutputStream*) png_get_io_ptr( png_ptr )) -> Write(data, length);
481 }
482
483 bool wxPNGHandler::LoadFile( wxImage *image, wxInputStream& stream )
484 {
485 // png_structp png_ptr;
486 // png_infop info_ptr;
487 // unsigned char *ptr, **lines, *ptr2;
488 // int transp,bit_depth,color_type,interlace_type;
489 //png_uint_32 width, height;
490 //unsigned int i;
491
492 image->Destroy();
493
494 png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
495 (voidp) NULL, (png_error_ptr) NULL, (png_error_ptr) NULL );
496 if (!png_ptr) return FALSE;
497
498 png_infop info_ptr = png_create_info_struct( png_ptr );
499 if (!info_ptr)
500 {
501 png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
502 return FALSE;
503 }
504
505 if (setjmp(png_ptr->jmpbuf))
506 {
507 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
508 return FALSE;
509 }
510
511 if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
512 {
513 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
514 return FALSE;
515 }
516 png_set_read_fn( png_ptr, &stream, _PNG_stream_reader);
517
518 png_uint_32 width,height;
519 int bit_depth,color_type,interlace_type;
520
521 png_read_info( png_ptr, info_ptr );
522 png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL );
523
524 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand( png_ptr );
525
526 png_set_strip_16( png_ptr );
527 png_set_packing( png_ptr );
528 if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand( png_ptr );
529 png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
530
531 image->Create( width, height );
532
533 if (!image->Ok())
534 {
535 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
536 return FALSE;
537 }
538
539 unsigned char **lines = (unsigned char **)malloc( height * sizeof(unsigned char *) );
540 if (lines == NULL)
541 {
542 image->Destroy();
543 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
544 return FALSE;
545 }
546
547 for (unsigned int i = 0; i < height; i++)
548 {
549 if ((lines[i] = (unsigned char *)malloc(width * (sizeof(unsigned char) * 4))) == NULL)
550 {
551 image->Destroy();
552 for (unsigned int n = 0; n < i; n++) free( lines[n] );
553 free( lines );
554 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
555 return FALSE;
556 }
557 }
558
559
560 int transp = 0;
561 png_read_image( png_ptr, lines );
562 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
563 unsigned char *ptr = image->GetData();
564 if ((color_type == PNG_COLOR_TYPE_GRAY) ||
565 (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
566 {
567 for (unsigned int y = 0; y < height; y++)
568 {
569 unsigned char *ptr2 = lines[y];
570 for (unsigned int x = 0; x < width; x++)
571 {
572 unsigned char r = *ptr2++;
573 unsigned char a = *ptr2++;
574 if (a < 128)
575 {
576 *ptr++ = 255;
577 *ptr++ = 0;
578 *ptr++ = 255;
579 transp = 1;
580 }
581 else
582 {
583 *ptr++ = r;
584 *ptr++ = r;
585 *ptr++ = r;
586 }
587 }
588 }
589 }
590 else
591 {
592 for (unsigned int y = 0; y < height; y++)
593 {
594 unsigned char *ptr2 = lines[y];
595 for (unsigned int x = 0; x < width; x++)
596 {
597 unsigned char r = *ptr2++;
598 unsigned char g = *ptr2++;
599 unsigned char b = *ptr2++;
600 unsigned char a = *ptr2++;
601 if (a < 128)
602 {
603 *ptr++ = 255;
604 *ptr++ = 0;
605 *ptr++ = 255;
606 transp = 1;
607 }
608 else
609 {
610 if ((r == 255) && (g == 0) && (b == 255)) r = 254;
611 *ptr++ = r;
612 *ptr++ = g;
613 *ptr++ = b;
614 }
615 }
616 }
617 }
618
619 for (unsigned int j = 0; j < height; j++) free( lines[j] );
620 free( lines );
621
622 if (transp)
623 {
624 image->SetMaskColour( 255, 0, 255 );
625 }
626 else
627 {
628 image->SetMask( FALSE );
629 }
630
631 return TRUE;
632 }
633
634
635 bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream )
636 {
637 {
638 png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
639 if (!png_ptr)
640 {
641 return FALSE;
642 }
643
644 png_infop info_ptr = png_create_info_struct(png_ptr);
645 if (info_ptr == NULL)
646 {
647 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
648 return FALSE;
649 }
650
651 if (setjmp(png_ptr->jmpbuf))
652 {
653 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
654 return FALSE;
655 }
656
657 png_set_write_fn( png_ptr, &stream, _PNG_stream_writer, NULL);
658
659 png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
660 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
661 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
662
663 png_color_8 sig_bit;
664 sig_bit.red = 8;
665 sig_bit.green = 8;
666 sig_bit.blue = 8;
667 sig_bit.alpha = 8;
668 png_set_sBIT( png_ptr, info_ptr, &sig_bit );
669 png_write_info( png_ptr, info_ptr );
670 png_set_shift( png_ptr, &sig_bit );
671 png_set_packing( png_ptr );
672
673 unsigned char *data = (unsigned char *)malloc( image->GetWidth()*4 );
674 if (!data)
675 {
676 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
677 return FALSE;
678 }
679
680 for (int y = 0; y < image->GetHeight(); y++)
681 {
682 unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
683 for (int x = 0; x < image->GetWidth(); x++)
684 {
685 data[(x << 2) + 0] = *ptr++;
686 data[(x << 2) + 1] = *ptr++;
687 data[(x << 2) + 2] = *ptr++;
688 if ((data[(x << 2) + 0] == image->GetMaskRed()) &&
689 (data[(x << 2) + 1] == image->GetMaskGreen()) &&
690 (data[(x << 2) + 2] == image->GetMaskBlue()))
691 {
692 data[(x << 2) + 3] = 0;
693 }
694 else
695 {
696 data[(x << 2) + 3] = 255;
697 }
698 }
699 png_bytep row_ptr = data;
700 png_write_rows( png_ptr, &row_ptr, 1 );
701 }
702
703 free(data);
704 png_write_end( png_ptr, info_ptr );
705 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
706 }
707 return TRUE;
708 }
709
710 #endif
711
712 // wxUSE_LIBPNG
713
714 //-----------------------------------------------------------------------------
715 // wxBMPHandler
716 //-----------------------------------------------------------------------------
717
718 #if !USE_SHARED_LIBRARIES
719 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
720 #endif
721
722 bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
723 {
724 unsigned char *data, *ptr;
725 int done, i, bpp, planes, comp, ncolors, line, column,
726 linesize, linepos, rshift = 0, gshift = 0, bshift = 0;
727 unsigned char aByte;
728 short int word;
729 long int dbuf[4], dword, rmask = 0, gmask = 0, bmask = 0, offset,
730 size;
731 off_t start_offset = stream.TellI();
732 signed char bbuf[4];
733 struct _cmap
734 {
735 unsigned char r, g, b;
736 }
737 *cmap = NULL;
738 #ifndef BI_RGB
739 #define BI_RGB 0
740 #define BI_RLE8 1
741 #define BI_RLE4 2
742 #endif
743
744 #ifndef BI_BITFIELDS
745 #define BI_BITFIELDS 3
746 #endif
747
748 image->Destroy();
749
750 done = 0;
751 /*
752 * Reading the bmp header
753 */
754
755 stream.Read(&bbuf, 2);
756
757 stream.Read(dbuf, 4 * 4);
758
759 size = dbuf[0];
760 offset = dbuf[2];
761
762 stream.Read(dbuf, 4 * 2);
763 int width = (int)dbuf[0];
764 int height = (int)dbuf[1];
765 if (width > 32767)
766 {
767 wxLogError( "Image width > 32767 pixels for file\n" );
768 return FALSE;
769 }
770 if (height > 32767)
771 {
772 wxLogError( "Image height > 32767 pixels for file\n" );
773 return FALSE;
774 }
775 stream.Read(&word, 2);
776 planes = (int)word;
777 stream.Read(&word, 2);
778 bpp = (int)word;
779 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp && 16 && bpp != 24 && bpp != 32)
780 {
781 wxLogError( "unknown bitdepth in file\n" );
782 return FALSE;
783 }
784 stream.Read(dbuf, 4 * 4);
785 comp = (int)dbuf[0];
786 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
787 {
788 wxLogError( "unknown encoding in Windows BMP file\n" );
789 return FALSE;
790 }
791 stream.Read(dbuf, 4 * 2);
792 ncolors = (int)dbuf[0];
793 if (ncolors == 0)
794 ncolors = 1 << bpp;
795 /* some more sanity checks */
796 if (((comp == BI_RLE4) && (bpp != 4)) || ((comp == BI_RLE8) && (bpp != 8)) || ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
797 {
798 wxLogError( "encoding of BMP doesn't match bitdepth\n" );
799 return FALSE;
800 }
801 if (bpp < 16)
802 {
803 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
804
805 if (!cmap)
806 {
807 wxLogError( "Cannot allocate RAM for color map in BMP file\n" );
808 return FALSE;
809 }
810 }
811 else
812 cmap = NULL;
813
814 image->Create( width, height );
815 ptr = image->GetData();
816 if (!ptr)
817 {
818 wxLogError( "Cannot allocate RAM for RGB data in file\n" );
819 if (cmap)
820 free(cmap);
821 return FALSE;
822 }
823
824 /*
825 * Reading the palette, if it exists.
826 */
827 if (bpp < 16 && ncolors != 0)
828 {
829 for (i = 0; i < ncolors; i++)
830 {
831 stream.Read(bbuf, 4);
832 cmap[i].b = bbuf[0];
833 cmap[i].g = bbuf[1];
834 cmap[i].r = bbuf[2];
835 }
836 }
837 else if (bpp == 16 || bpp == 32)
838 {
839 if (comp == BI_BITFIELDS)
840 {
841 int bit = 0;
842
843 stream.Read(dbuf, 4 * 3);
844 bmask = dbuf[0];
845 gmask = dbuf[1];
846 rmask = dbuf[2];
847 /* find shift amount.. ugly, but i can't think of a better way */
848 for (bit = 0; bit < bpp; bit++)
849 {
850 if (bmask & (1 << bit))
851 bshift = bit;
852 if (gmask & (1 << bit))
853 gshift = bit;
854 if (rmask & (1 << bit))
855 rshift = bit;
856 }
857 }
858 else if (bpp == 16)
859 {
860 rmask = 0x7C00;
861 gmask = 0x03E0;
862 bmask = 0x001F;
863 rshift = 10;
864 gshift = 5;
865 bshift = 0;
866 }
867 else if (bpp == 32)
868 {
869 rmask = 0x00FF0000;
870 gmask = 0x0000FF00;
871 bmask = 0x000000FF;
872 rshift = 16;
873 gshift = 8;
874 bshift = 0;
875 }
876 }
877
878 /*
879 * Reading the image data
880 */
881 stream.SeekI(start_offset + offset);
882 data = ptr;
883
884 /* set the whole image to the background color */
885 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
886 {
887 for (i = 0; i < width * height; i++)
888 {
889 *ptr++ = cmap[0].r;
890 *ptr++ = cmap[0].g;
891 *ptr++ = cmap[0].b;
892 }
893 ptr = data;
894 }
895 line = 0;
896 column = 0;
897 #define poffset (line * width * 3 + column * 3)
898
899 /*
900 * BMPs are stored upside down... hmmmmmmmmmm....
901 */
902
903 linesize = ((width * bpp + 31) / 32) * 4;
904 for (line = (height - 1); line >= 0; line--)
905 {
906 linepos = 0;
907 for (column = 0; column < width;)
908 {
909 if (bpp < 16)
910 {
911 int index;
912
913 linepos++;
914 aByte = stream.GetC();
915 if (bpp == 1)
916 {
917 int bit = 0;
918
919 for (bit = 0; bit < 8; bit++)
920 {
921 index = ((aByte & (0x80 >> bit)) ? 1 : 0);
922 ptr[poffset] = cmap[index].r;
923 ptr[poffset + 1] = cmap[index].g;
924 ptr[poffset + 2] = cmap[index].b;
925 column++;
926 }
927 }
928 else if (bpp == 4)
929 {
930 if (comp == BI_RLE4)
931 {
932 wxLogError( "can't deal with 4bit encoded yet.\n");
933 image->Destroy();
934 free(cmap);
935 return FALSE;
936 }
937 else
938 {
939 int nibble = 0;
940
941 for (nibble = 0; nibble < 2; nibble++)
942 {
943 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
944 if (index >= 16)
945 index = 15;
946 ptr[poffset] = cmap[index].r;
947 ptr[poffset + 1] = cmap[index].g;
948 ptr[poffset + 2] = cmap[index].b;
949 column++;
950 }
951 }
952 }
953 else if (bpp == 8)
954 {
955 if (comp == BI_RLE8)
956 {
957 unsigned char first;
958
959 first = aByte;
960 aByte = stream.GetC();
961 if (first == 0)
962 {
963 if (aByte == 0)
964 {
965 /* column = width; */
966 }
967 else if (aByte == 1)
968 {
969 column = width;
970 line = -1;
971 }
972 else if (aByte == 2)
973 {
974 aByte = stream.GetC();
975 column += aByte;
976 linepos = column * bpp / 8;
977 aByte = stream.GetC();
978 line += aByte;
979 }
980 else
981 {
982 int absolute = aByte;
983
984 for (i = 0; i < absolute; i++)
985 {
986 linepos++;
987 aByte = stream.GetC();
988 ptr[poffset] = cmap[aByte].r;
989 ptr[poffset + 1] = cmap[aByte].g;
990 ptr[poffset + 2] = cmap[aByte].b;
991 column++;
992 }
993 if (absolute & 0x01)
994 aByte = stream.GetC();
995 }
996 }
997 else
998 {
999 for (i = 0; i < first; i++)
1000 {
1001 ptr[poffset] = cmap[aByte].r;
1002 ptr[poffset + 1] = cmap[aByte].g;
1003 ptr[poffset + 2] = cmap[aByte].b;
1004 column++;
1005 linepos++;
1006 }
1007 }
1008 }
1009 else
1010 {
1011 ptr[poffset] = cmap[aByte].r;
1012 ptr[poffset + 1] = cmap[aByte].g;
1013 ptr[poffset + 2] = cmap[aByte].b;
1014 column++;
1015 linepos += size;
1016 }
1017 }
1018 }
1019 else if (bpp == 24)
1020 {
1021 stream.Read(&bbuf, 3);
1022 linepos += 3;
1023 ptr[poffset] = (unsigned char)bbuf[2];
1024 ptr[poffset + 1] = (unsigned char)bbuf[1];
1025 ptr[poffset + 2] = (unsigned char)bbuf[0];
1026 column++;
1027 }
1028 else if (bpp == 16)
1029 {
1030 unsigned char temp;
1031
1032 stream.Read(&word, 2);
1033 linepos += 2;
1034 temp = (word & rmask) >> rshift;
1035 ptr[poffset] = temp;
1036 temp = (word & gmask) >> gshift;
1037 ptr[poffset + 1] = temp;
1038 temp = (word & bmask) >> gshift;
1039 ptr[poffset + 2] = temp;
1040 column++;
1041 }
1042 else
1043 {
1044 unsigned char temp;
1045
1046 stream.Read(&dword, 4);
1047 linepos += 4;
1048 temp = (dword & rmask) >> rshift;
1049 ptr[poffset] = temp;
1050 temp = (dword & gmask) >> gshift;
1051 ptr[poffset + 1] = temp;
1052 temp = (dword & bmask) >> bshift;
1053 ptr[poffset + 2] = temp;
1054 column++;
1055 }
1056 }
1057 while ((linepos < linesize) && (comp != 1) && (comp != 2))
1058 {
1059 stream.Read(&aByte, 1);
1060 linepos += 1;
1061 if (stream.LastError() != wxStream_NOERROR)
1062 break;
1063 }
1064 }
1065 if (cmap) free(cmap);
1066
1067 image->SetMask( FALSE );
1068
1069 return TRUE;
1070 }
1071
1072 #ifdef __WXMSW__
1073
1074 wxBitmap wxImage::ConvertToBitmap() const
1075 {
1076
1077 wxBitmap bitmap;
1078 wxCHECK_MSG( Ok(), bitmap, "invalid image" );
1079 int width = GetWidth();
1080 int height = GetHeight();
1081 bitmap.SetWidth( width );
1082 bitmap.SetHeight( height );
1083 bitmap.SetDepth( wxDisplayDepth() );
1084
1085 int headersize = sizeof(BITMAPINFOHEADER);
1086 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1087 wxCHECK_MSG( lpDIBh, bitmap, "could not allocate memory for DIB header" );
1088
1089 // Fill in the DIB header
1090 lpDIBh->bmiHeader.biSize = headersize;
1091 lpDIBh->bmiHeader.biWidth = width;
1092 lpDIBh->bmiHeader.biHeight = -height;
1093 lpDIBh->bmiHeader.biSizeImage = width * height * 3;
1094
1095 lpDIBh->bmiHeader.biPlanes = 1;
1096 lpDIBh->bmiHeader.biBitCount = 24;
1097 lpDIBh->bmiHeader.biCompression = BI_RGB;
1098 lpDIBh->bmiHeader.biClrUsed = 0;
1099
1100 // These seem not needed for our purpose here.
1101 // lpDIBh->bmiHeader.biClrImportant = 0;
1102 // lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1103 // lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1104
1105 unsigned char *lpBits = (unsigned char *) malloc( width*height*3 );
1106 if( !lpBits )
1107 {
1108 wxFAIL_MSG( "could not allocate memory for DIB" );
1109 free( lpDIBh );
1110 return bitmap;
1111 }
1112
1113 unsigned char *data = GetData();
1114
1115 unsigned char *ptdata = data, *ptbits = lpBits;
1116 for( int i=0; i<width*height; i++ )
1117 {
1118 *(ptbits++) = *(ptdata+2);
1119 *(ptbits++) = *(ptdata+1);
1120 *(ptbits++) = *(ptdata );
1121 ptdata += 3;
1122 }
1123
1124 HDC hdc = ::GetDC(NULL);
1125
1126 HBITMAP hbitmap;
1127 hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1128
1129 // The above line is equivalent to the following two lines.
1130 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1131 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1132 // or the following lines
1133 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1134 // HDC memdc = ::CreateCompatibleDC( hdc );
1135 // ::SelectObject( memdc, hbitmap);
1136 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1137 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1138 // ::SelectObject( memdc, 0 );
1139 // ::DeleteDC( memdc );
1140
1141 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
1142
1143 if( HasMask() )
1144 {
1145 unsigned char r = GetMaskRed();
1146 unsigned char g = GetMaskGreen();
1147 unsigned char b = GetMaskBlue();
1148 unsigned char zero = 0, one = 255;
1149 ptdata = data;
1150 ptbits = lpBits;
1151 for( int i=0; i<width*height; i++ )
1152 {
1153 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
1154 {
1155 *(ptbits++) = one;
1156 *(ptbits++) = one;
1157 *(ptbits++) = one;
1158 }
1159 else
1160 {
1161 *(ptbits++) = zero;
1162 *(ptbits++) = zero;
1163 *(ptbits++) = zero;
1164 }
1165 }
1166 hbitmap = ::CreateBitmap( (WORD)width, (WORD)height, 1, 1, NULL );
1167 ::SetDIBits( hdc, hbitmap, 0, (WORD)height, lpBits, lpDIBh, DIB_RGB_COLORS);
1168 wxMask *mask = new wxMask();
1169 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
1170 bitmap.SetMask( mask );
1171
1172 /* The following can also be used but is slow to run
1173 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1174 wxMask *mask = new wxMask( bitmap, colour );
1175 bitmap.SetMask( mask );
1176 */
1177 }
1178
1179 ::ReleaseDC(NULL, hdc);
1180 free(lpDIBh);
1181 free(lpBits);
1182
1183 if( bitmap.GetHBITMAP() )
1184 bitmap.SetOk( TRUE );
1185 else
1186 bitmap.SetOk( FALSE );
1187
1188 return bitmap;
1189 }
1190
1191
1192 wxImage::wxImage( const wxBitmap &bitmap )
1193 {
1194 if( !bitmap.Ok() )
1195 {
1196 wxFAIL_MSG( "invalid bitmap" );
1197 return;
1198 }
1199
1200 int width = bitmap.GetWidth();
1201 int height = bitmap.GetHeight();
1202 Create( width, height );
1203 unsigned char *data = GetData();
1204 if( !data )
1205 {
1206 wxFAIL_MSG( "could not allocate data for image" );
1207 return;
1208 }
1209
1210 int headersize = sizeof(BITMAPINFOHEADER);
1211 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1212 if( !lpDIBh )
1213 {
1214 wxFAIL_MSG( "could not allocate data for DIB header" );
1215 free( data );
1216 return;
1217 }
1218
1219 // Fill in the DIB header
1220 lpDIBh->bmiHeader.biSize = headersize;
1221 lpDIBh->bmiHeader.biWidth = width;
1222 lpDIBh->bmiHeader.biHeight = -height;
1223 lpDIBh->bmiHeader.biSizeImage = width * height * 3;
1224
1225 lpDIBh->bmiHeader.biPlanes = 1;
1226 lpDIBh->bmiHeader.biBitCount = 24;
1227 lpDIBh->bmiHeader.biCompression = BI_RGB;
1228 lpDIBh->bmiHeader.biClrUsed = 0;
1229
1230 // These seem not needed for our purpose here.
1231 // lpDIBh->bmiHeader.biClrImportant = 0;
1232 // lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1233 // lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1234
1235 unsigned char *lpBits = (unsigned char *) malloc( width*height*3 );
1236 if( !lpBits )
1237 {
1238 wxFAIL_MSG( "could not allocate data for DIB" );
1239 free( data );
1240 free( lpDIBh );
1241 return;
1242 }
1243
1244 HBITMAP hbitmap;
1245 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1246 HDC hdc = ::GetDC(NULL);
1247 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1248
1249 unsigned char *ptdata = data, *ptbits = lpBits;
1250 for( int i=0; i<width*height; i++ )
1251 {
1252 *(ptdata++) = *(ptbits+2);
1253 *(ptdata++) = *(ptbits+1);
1254 *(ptdata++) = *(ptbits );
1255 ptbits += 3;
1256 }
1257
1258 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1259 {
1260 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1261 HDC memdc = ::CreateCompatibleDC( hdc );
1262 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1263 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1264 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1265 ::DeleteDC( memdc );
1266 unsigned char r=16, g=16, b=16; // background set to RGB(16,16,16)
1267 ptdata = data;
1268 ptbits = lpBits;
1269 for( int i=0; i<width*height; i++ )
1270 {
1271 if( *ptbits != 0 )
1272 {
1273 *(ptdata++) = r;
1274 *(ptdata++) = g;
1275 *(ptdata++) = b;
1276 }
1277 ptbits += 3;
1278 }
1279 SetMaskColour( r, g, b );
1280 }
1281
1282 ::ReleaseDC(NULL, hdc);
1283 free(lpDIBh);
1284 free(lpBits);
1285 }
1286
1287 #endif
1288
1289 #ifdef __WXGTK__
1290
1291 #include "gtk/gtk.h"
1292 #include "gdk/gdk.h"
1293 #include "gdk/gdkx.h"
1294
1295 wxBitmap wxImage::ConvertToBitmap() const
1296 {
1297 wxBitmap bitmap;
1298
1299 wxCHECK_MSG( Ok(), bitmap, "invalid image" );
1300
1301 int width = GetWidth();
1302 int height = GetHeight();
1303
1304 bitmap.SetHeight( height );
1305 bitmap.SetWidth( width );
1306
1307 // Create picture
1308
1309 GdkImage *data_image =
1310 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
1311
1312 bitmap.SetPixmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, -1 ) );
1313
1314 // Create mask
1315
1316 GdkImage *mask_image = (GdkImage*) NULL;
1317
1318 if (HasMask())
1319 {
1320 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1321
1322 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1323
1324 wxMask *mask = new wxMask();
1325 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1326
1327 bitmap.SetMask( mask );
1328 }
1329
1330 // Retrieve depth
1331
1332 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1333 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1334 int bpp = visual->depth;
1335
1336 bitmap.SetDepth( bpp );
1337
1338 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1339 if (bpp < 8) bpp = 8;
1340
1341 // Render
1342
1343 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1344 byte_order b_o = RGB;
1345
1346 if (bpp >= 24)
1347 {
1348 GdkVisual *visual = gdk_visual_get_system();
1349 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1350 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1351 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1352 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1353 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1354 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1355 }
1356
1357 int r_mask = GetMaskRed();
1358 int g_mask = GetMaskGreen();
1359 int b_mask = GetMaskBlue();
1360
1361 unsigned char* data = GetData();
1362
1363 int index = 0;
1364 for (int y = 0; y < height; y++)
1365 {
1366 for (int x = 0; x < width; x++)
1367 {
1368 int r = data[index];
1369 index++;
1370 int g = data[index];
1371 index++;
1372 int b = data[index];
1373 index++;
1374
1375 if (HasMask())
1376 {
1377 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1378 gdk_image_put_pixel( mask_image, x, y, 1 );
1379 else
1380 gdk_image_put_pixel( mask_image, x, y, 0 );
1381 }
1382
1383 switch (bpp)
1384 {
1385 case 8:
1386 {
1387 int pixel = -1;
1388 if (wxTheApp->m_colorCube)
1389 {
1390 pixel = wxTheApp->m_colorCube
1391 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1392 }
1393 else
1394 {
1395 GdkColormap *cmap = gtk_widget_get_default_colormap();
1396 GdkColor *colors = cmap->colors;
1397 int max = 3 * (65536);
1398
1399 for (int i = 0; i < cmap->size; i++)
1400 {
1401 int rdiff = (r << 8) - colors[i].red;
1402 int gdiff = (g << 8) - colors[i].green;
1403 int bdiff = (b << 8) - colors[i].blue;
1404 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1405 if (sum < max) { pixel = i; max = sum; }
1406 }
1407 }
1408
1409 gdk_image_put_pixel( data_image, x, y, pixel );
1410
1411 break;
1412 }
1413 case 15:
1414 {
1415 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1416 gdk_image_put_pixel( data_image, x, y, pixel );
1417 break;
1418 }
1419 case 16:
1420 {
1421 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1422 gdk_image_put_pixel( data_image, x, y, pixel );
1423 break;
1424 }
1425 case 32:
1426 case 24:
1427 {
1428 guint32 pixel = 0;
1429 switch (b_o)
1430 {
1431 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1432 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1433 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1434 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1435 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1436 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1437 }
1438 gdk_image_put_pixel( data_image, x, y, pixel );
1439 }
1440 default: break;
1441 }
1442 } // for
1443 } // for
1444
1445 // Blit picture
1446
1447 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1448
1449 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1450
1451 gdk_image_destroy( data_image );
1452 gdk_gc_unref( data_gc );
1453
1454 // Blit mask
1455
1456 if (HasMask())
1457 {
1458 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1459
1460 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1461
1462 gdk_image_destroy( mask_image );
1463 gdk_gc_unref( mask_gc );
1464 }
1465
1466 return bitmap;
1467 }
1468
1469 wxImage::wxImage( const wxBitmap &bitmap )
1470 {
1471 wxCHECK_RET( bitmap.Ok(), "invalid bitmap" );
1472
1473 GdkImage *gdk_image = gdk_image_get( bitmap.GetPixmap(),
1474 0, 0,
1475 bitmap.GetWidth(), bitmap.GetHeight() );
1476
1477 wxCHECK_RET( gdk_image, "couldn't create image" );
1478
1479 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1480 char unsigned *data = GetData();
1481
1482 if (!data)
1483 {
1484 gdk_image_destroy( gdk_image );
1485 wxFAIL_MSG( "couldn't create image" );
1486 return;
1487 }
1488
1489 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1490 if (bitmap.GetMask())
1491 {
1492 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1493 0, 0,
1494 bitmap.GetWidth(), bitmap.GetHeight() );
1495
1496 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1497 }
1498
1499 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1500 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1501 int bpp = visual->depth;
1502 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1503
1504 GdkColormap *cmap = gtk_widget_get_default_colormap();
1505
1506 long pos = 0;
1507 for (int j = 0; j < bitmap.GetHeight(); j++)
1508 {
1509 for (int i = 0; i < bitmap.GetWidth(); i++)
1510 {
1511 int pixel = gdk_image_get_pixel( gdk_image, i, j );
1512 if (bpp <= 8)
1513 {
1514 data[pos] = cmap->colors[pixel].red >> 8;
1515 data[pos+1] = cmap->colors[pixel].green >> 8;
1516 data[pos+2] = cmap->colors[pixel].blue >> 8;
1517 } else if (bpp == 15)
1518 {
1519 data[pos] = (pixel >> 7) & 0xf8;
1520 data[pos+1] = (pixel >> 2) & 0xf8;
1521 data[pos+2] = (pixel << 3) & 0xf8;
1522 } else if (bpp == 16)
1523 {
1524 data[pos] = (pixel >> 8) & 0xf8;
1525 data[pos+1] = (pixel >> 3) & 0xfc;
1526 data[pos+2] = (pixel << 3) & 0xf8;
1527 } else
1528 {
1529 data[pos] = (pixel >> 16) & 0xff;
1530 data[pos+1] = (pixel >> 8) & 0xff;
1531 data[pos+2] = pixel & 0xff;
1532 }
1533
1534 if (gdk_image_mask)
1535 {
1536 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1537 if (mask_pixel == 0)
1538 {
1539 data[pos] = 16;
1540 data[pos+1] = 16;
1541 data[pos+2] = 16;
1542 }
1543 }
1544
1545 pos += 3;
1546 }
1547 }
1548
1549 gdk_image_destroy( gdk_image );
1550 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1551 }
1552
1553 #endif
1554
1555 // TODO
1556
1557 #ifdef __WXMOTIF__
1558 wxBitmap wxImage::ConvertToBitmap() const
1559 {
1560 wxFAIL_MSG("Sorry, wxImage::ConvertToBitmap isn't implemented for wxMotif yet.");
1561 return wxNullBitmap;
1562 }
1563
1564 wxImage::wxImage( const wxBitmap &bitmap )
1565 {
1566 wxFAIL_MSG("Sorry, wxImage::wxImage(const wxBitmap&) isn't implemented for wxMotif yet.");
1567 }
1568 #endif