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