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