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