]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
853182a88823874600560bbbfef263b7063c41dd
[wxWidgets.git] / src / common / image.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: image.cpp
3 // Purpose: wxImage
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "image.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/image.h"
22 #include "wx/bitmap.h"
23 #include "wx/debug.h"
24 #include "wx/log.h"
25 #include "wx/app.h"
26 #ifdef wxUSE_LIBPNG
27 #include "../png/png.h"
28 #endif
29 #include "wx/filefn.h"
30 #include "wx/wfstream.h"
31 #include "wx/intl.h"
32
33 #ifdef __SALFORDC__
34 #ifdef FAR
35 #undef FAR
36 #endif
37 #endif
38
39 #ifdef __WXMSW__
40 #include <windows.h>
41 #endif
42
43 //-----------------------------------------------------------------------------
44 // wxImage
45 //-----------------------------------------------------------------------------
46
47 class wxImageRefData: public wxObjectRefData
48 {
49
50 public:
51 wxImageRefData(void);
52 ~wxImageRefData(void);
53
54 int m_width;
55 int m_height;
56 unsigned char *m_data;
57 bool m_hasMask;
58 unsigned char m_maskRed,m_maskGreen,m_maskBlue;
59 bool m_ok;
60 };
61
62 wxImageRefData::wxImageRefData(void)
63 {
64 m_width = 0;
65 m_height = 0;
66 m_data = (unsigned char*) NULL;
67 m_ok = FALSE;
68 m_maskRed = 0;
69 m_maskGreen = 0;
70 m_maskBlue = 0;
71 m_hasMask = FALSE;
72 }
73
74 wxImageRefData::~wxImageRefData(void)
75 {
76 if (m_data) free( m_data );
77 }
78
79 wxList wxImage::sm_handlers;
80
81 //-----------------------------------------------------------------------------
82
83 #define M_IMGDATA ((wxImageRefData *)m_refData)
84
85 #if !USE_SHARED_LIBRARIES
86 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
87 #endif
88
89 wxImage::wxImage()
90 {
91 }
92
93 wxImage::wxImage( int width, int height )
94 {
95 Create( width, height );
96 }
97
98 wxImage::wxImage( const wxString& name, long type )
99 {
100 LoadFile( name, type );
101 }
102
103 wxImage::wxImage( wxInputStream& stream, long type )
104 {
105 LoadFile( stream, type );
106 }
107
108 wxImage::wxImage( const wxImage& image )
109 {
110 Ref(image);
111 }
112
113 wxImage::wxImage( const wxImage* image )
114 {
115 if (image) Ref(*image);
116 }
117
118 void wxImage::Create( int width, int height )
119 {
120 m_refData = new wxImageRefData();
121
122 M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
123 if (M_IMGDATA->m_data)
124 {
125 for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
126
127 M_IMGDATA->m_width = width;
128 M_IMGDATA->m_height = height;
129 M_IMGDATA->m_ok = TRUE;
130 }
131 else
132 {
133 UnRef();
134 }
135 }
136
137 void wxImage::Destroy()
138 {
139 UnRef();
140 }
141
142 wxImage wxImage::Scale( int width, int height )
143 {
144 wxImage image;
145
146 wxCHECK_MSG( Ok(), image, "invlaid image" );
147
148 wxCHECK_MSG( (width > 0) && (height > 0), image, "invalid image size" );
149
150 image.Create( width, height );
151
152 char unsigned *data = image.GetData();
153
154 wxCHECK_MSG( data, image, "unable to create image" );
155
156 if (M_IMGDATA->m_hasMask)
157 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
158
159 double xscale = (double)width / (double)M_IMGDATA->m_width;
160 double yscale = (double)height / (double)M_IMGDATA->m_height;
161
162 for (int j = 0; j < height; j++)
163 {
164 for (int i = 0; i < width; i++)
165 {
166 int new_pos = 3*(j*width + i);
167 int old_pos = 3*((long)(j/yscale)*M_IMGDATA->m_width + (long)(i/xscale));
168 data[ new_pos ] = M_IMGDATA->m_data[ old_pos ];
169 data[ new_pos+1 ] = M_IMGDATA->m_data[ old_pos+1 ];
170 data[ new_pos+2 ] = M_IMGDATA->m_data[ old_pos+2 ];
171 }
172 }
173
174 return image;
175 }
176
177 void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
178 {
179 wxCHECK_RET( Ok(), "invalid image" );
180
181 int w = M_IMGDATA->m_width;
182 int h = M_IMGDATA->m_height;
183
184 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), "invalid image index" );
185
186 long pos = (y * w + x) * 3;
187
188 M_IMGDATA->m_data[ pos ] = r;
189 M_IMGDATA->m_data[ pos+1 ] = g;
190 M_IMGDATA->m_data[ pos+2 ] = b;
191 }
192
193 unsigned char wxImage::GetRed( int x, int y )
194 {
195 wxCHECK_MSG( Ok(), 0, "invalid image" );
196
197 int w = M_IMGDATA->m_width;
198 int h = M_IMGDATA->m_height;
199
200 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
201
202 long pos = (y * w + x) * 3;
203
204 return M_IMGDATA->m_data[pos];
205 }
206
207 unsigned char wxImage::GetGreen( int x, int y )
208 {
209 wxCHECK_MSG( Ok(), 0, "invalid image" );
210
211 int w = M_IMGDATA->m_width;
212 int h = M_IMGDATA->m_height;
213
214 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
215
216 long pos = (y * w + x) * 3;
217
218 return M_IMGDATA->m_data[pos+1];
219 }
220
221 unsigned char wxImage::GetBlue( int x, int y )
222 {
223 wxCHECK_MSG( Ok(), 0, "invalid image" );
224
225 int w = M_IMGDATA->m_width;
226 int h = M_IMGDATA->m_height;
227
228 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
229
230 long pos = (y * w + x) * 3;
231
232 return M_IMGDATA->m_data[pos+2];
233 }
234
235 bool wxImage::Ok() const
236 {
237 return (M_IMGDATA && M_IMGDATA->m_ok);
238 }
239
240 char unsigned *wxImage::GetData() const
241 {
242 wxCHECK_MSG( Ok(), (char unsigned *)NULL, "invalid image" );
243
244 return M_IMGDATA->m_data;
245 }
246
247 void wxImage::SetData( char unsigned *WXUNUSED(data) )
248 {
249 wxCHECK_RET( Ok(), "invalid image" );
250 }
251
252 void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
253 {
254 wxCHECK_RET( Ok(), "invalid image" );
255
256 M_IMGDATA->m_maskRed = r;
257 M_IMGDATA->m_maskGreen = g;
258 M_IMGDATA->m_maskBlue = b;
259 M_IMGDATA->m_hasMask = TRUE;
260 }
261
262 unsigned char wxImage::GetMaskRed() const
263 {
264 wxCHECK_MSG( Ok(), 0, "invalid image" );
265
266 return M_IMGDATA->m_maskRed;
267 }
268
269 unsigned char wxImage::GetMaskGreen() const
270 {
271 wxCHECK_MSG( Ok(), 0, "invalid image" );
272
273 return M_IMGDATA->m_maskGreen;
274 }
275
276 unsigned char wxImage::GetMaskBlue() const
277 {
278 wxCHECK_MSG( Ok(), 0, "invalid image" );
279
280 return M_IMGDATA->m_maskBlue;
281 }
282
283 void wxImage::SetMask( bool mask )
284 {
285 wxCHECK_RET( Ok(), "invalid image" );
286
287 M_IMGDATA->m_hasMask = mask;
288 }
289
290 bool wxImage::HasMask() const
291 {
292 wxCHECK_MSG( Ok(), FALSE, "invalid image" );
293
294 return M_IMGDATA->m_hasMask;
295 }
296
297 int wxImage::GetWidth() const
298 {
299 wxCHECK_MSG( Ok(), 0, "invalid image" );
300
301 return M_IMGDATA->m_width;
302 }
303
304 int wxImage::GetHeight() const
305 {
306 wxCHECK_MSG( Ok(), 0, "invalid image" );
307
308 return M_IMGDATA->m_height;
309 }
310
311 bool wxImage::LoadFile( const wxString& filename, long type )
312 {
313 if (wxFileExists(filename))
314 {
315 wxFileInputStream stream(filename);
316 return LoadFile(stream, type);
317 }
318
319 else {
320 wxLogWarning( "Image file does not exist." );
321
322 return FALSE;
323 }
324 }
325
326 bool wxImage::LoadFile( wxInputStream& stream, long type )
327 {
328 UnRef();
329
330 m_refData = new wxImageRefData;
331
332 wxImageHandler *handler = FindHandler(type);
333
334 if (handler == NULL)
335 {
336 wxLogWarning( "No image handler for type %d defined.", type );
337
338 return FALSE;
339 }
340
341 return handler->LoadFile( this, stream );
342 }
343
344 bool wxImage::SaveFile( const wxString& filename, int type )
345 {
346 wxFileOutputStream stream(filename);
347
348 if ( stream.LastError() == wxStream_NOERROR )
349 return SaveFile(stream, type);
350 else
351 return FALSE;
352 }
353
354 bool wxImage::SaveFile( wxOutputStream& stream, int type )
355 {
356 wxCHECK_MSG( Ok(), FALSE, "invalid image" );
357
358 wxImageHandler *handler = FindHandler(type);
359
360 if (handler == NULL)
361 {
362 wxLogWarning( "No image handler for type %d defined.", type );
363
364 return FALSE;
365 }
366
367 return handler->SaveFile( this, stream );
368 }
369
370 void wxImage::AddHandler( wxImageHandler *handler )
371 {
372 // make sure that the memory will be freed at the program end
373 sm_handlers.DeleteContents(TRUE);
374
375 sm_handlers.Append( handler );
376 }
377
378 void wxImage::InsertHandler( wxImageHandler *handler )
379 {
380 // make sure that the memory will be freed at the program end
381 sm_handlers.DeleteContents(TRUE);
382
383 sm_handlers.Insert( handler );
384 }
385
386 bool wxImage::RemoveHandler( const wxString& name )
387 {
388 wxImageHandler *handler = FindHandler(name);
389 if (handler)
390 {
391 sm_handlers.DeleteObject(handler);
392 return TRUE;
393 }
394 else
395 return FALSE;
396 }
397
398 wxImageHandler *wxImage::FindHandler( const wxString& name )
399 {
400 wxNode *node = sm_handlers.First();
401 while (node)
402 {
403 wxImageHandler *handler = (wxImageHandler*)node->Data();
404 if (handler->GetName().Cmp(name) == 0) return handler;
405
406 node = node->Next();
407 }
408 return (wxImageHandler *)NULL;
409 }
410
411 wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
412 {
413 wxNode *node = sm_handlers.First();
414 while (node)
415 {
416 wxImageHandler *handler = (wxImageHandler*)node->Data();
417 if ( (handler->GetExtension().Cmp(extension) == 0) &&
418 (bitmapType == -1 || handler->GetType() == bitmapType) )
419 return handler;
420 node = node->Next();
421 }
422 return (wxImageHandler*)NULL;
423 }
424
425 wxImageHandler *wxImage::FindHandler( long bitmapType )
426 {
427 wxNode *node = sm_handlers.First();
428 while (node)
429 {
430 wxImageHandler *handler = (wxImageHandler *)node->Data();
431 if (handler->GetType() == bitmapType) return handler;
432 node = node->Next();
433 }
434 return NULL;
435 }
436
437 void wxImage::InitStandardHandlers()
438 {
439 AddHandler( new wxBMPHandler );
440 #ifdef wxUSE_LIBPNG
441 AddHandler( new wxPNGHandler );
442 #endif
443 }
444
445 void wxImage::CleanUpHandlers()
446 {
447 wxNode *node = sm_handlers.First();
448 while (node)
449 {
450 wxImageHandler *handler = (wxImageHandler *)node->Data();
451 wxNode *next = node->Next();
452 delete handler;
453 delete node;
454 node = next;
455 }
456 }
457
458 //-----------------------------------------------------------------------------
459 // wxImageHandler
460 //-----------------------------------------------------------------------------
461
462 #if !USE_SHARED_LIBRARIES
463 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler,wxObject)
464 #endif
465
466 bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream) )
467 {
468 return FALSE;
469 }
470
471 bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream) )
472 {
473 return FALSE;
474 }
475
476 //-----------------------------------------------------------------------------
477 // wxPNGHandler
478 //-----------------------------------------------------------------------------
479
480 #ifdef wxUSE_LIBPNG
481
482 #if !USE_SHARED_LIBRARIES
483 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
484 #endif
485
486
487 static void _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
488 {
489 ((wxInputStream*) png_get_io_ptr( png_ptr )) -> Read(data, length);
490 }
491
492 static void _PNG_stream_writer( png_structp png_ptr, png_bytep data, png_size_t length )
493 {
494 ((wxOutputStream*) png_get_io_ptr( png_ptr )) -> Write(data, length);
495 }
496
497 bool wxPNGHandler::LoadFile( wxImage *image, wxInputStream& stream )
498 {
499 // VZ: as this function uses setjmp() the only fool proof error handling
500 // method is to use goto (setjmp is not really C++ dtors friendly...)
501
502 unsigned char **lines = (unsigned char **) NULL;
503 unsigned int i;
504 png_infop info_ptr = (png_infop) NULL;
505
506 image->Destroy();
507
508 png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
509 (voidp) NULL,
510 (png_error_ptr) NULL,
511 (png_error_ptr) NULL );
512 if (!png_ptr)
513 goto error;
514
515 info_ptr = png_create_info_struct( png_ptr );
516 if (!info_ptr)
517 goto error;
518
519 if (setjmp(png_ptr->jmpbuf))
520 goto error;
521
522 if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
523 goto error;
524
525 png_set_read_fn( png_ptr, &stream, _PNG_stream_reader);
526
527 png_uint_32 width,height;
528 int bit_depth,color_type,interlace_type;
529
530 png_read_info( png_ptr, info_ptr );
531 png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL );
532
533 if (color_type == PNG_COLOR_TYPE_PALETTE)
534 png_set_expand( png_ptr );
535
536 png_set_strip_16( png_ptr );
537 png_set_packing( png_ptr );
538 if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS))
539 png_set_expand( png_ptr );
540 png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
541
542 image->Create( width, height );
543
544 if (!image->Ok())
545 goto error;
546
547 lines = (unsigned char **)malloc( height * sizeof(unsigned char *) );
548 if (lines == NULL)
549 goto error;
550
551 for (i = 0; i < height; i++)
552 {
553 if ((lines[i] = (unsigned char *)malloc(width * (sizeof(unsigned char) * 4))) == NULL)
554 {
555 for ( unsigned int n = 0; n < i; n++ )
556 free( lines[n] );
557 goto error;
558 }
559 }
560
561 // loaded successfully!
562 {
563 int transp = 0;
564 png_read_image( png_ptr, lines );
565 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
566 unsigned char *ptr = image->GetData();
567 if ((color_type == PNG_COLOR_TYPE_GRAY) ||
568 (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
569 {
570 for (unsigned int y = 0; y < height; y++)
571 {
572 unsigned char *ptr2 = lines[y];
573 for (unsigned int x = 0; x < width; x++)
574 {
575 unsigned char r = *ptr2++;
576 unsigned char a = *ptr2++;
577 if (a < 128)
578 {
579 *ptr++ = 255;
580 *ptr++ = 0;
581 *ptr++ = 255;
582 transp = 1;
583 }
584 else
585 {
586 *ptr++ = r;
587 *ptr++ = r;
588 *ptr++ = r;
589 }
590 }
591 }
592 }
593 else
594 {
595 for (unsigned int y = 0; y < height; y++)
596 {
597 unsigned char *ptr2 = lines[y];
598 for (unsigned int x = 0; x < width; x++)
599 {
600 unsigned char r = *ptr2++;
601 unsigned char g = *ptr2++;
602 unsigned char b = *ptr2++;
603 unsigned char a = *ptr2++;
604 if (a < 128)
605 {
606 *ptr++ = 255;
607 *ptr++ = 0;
608 *ptr++ = 255;
609 transp = 1;
610 }
611 else
612 {
613 if ((r == 255) && (g == 0) && (b == 255)) r = 254;
614 *ptr++ = r;
615 *ptr++ = g;
616 *ptr++ = b;
617 }
618 }
619 }
620 }
621
622 for ( unsigned int j = 0; j < height; j++ )
623 free( lines[j] );
624 free( lines );
625
626 if (transp)
627 {
628 image->SetMaskColour( 255, 0, 255 );
629 }
630 else
631 {
632 image->SetMask( FALSE );
633 }
634 }
635
636 return TRUE;
637
638 error:
639 wxLogError(_("Couldn't load a PNG image - probably file is corrupted."));
640
641 if ( image->Ok() )
642 {
643 image->Destroy();
644 }
645
646 if ( lines )
647 {
648 free( lines );
649 }
650
651 if ( png_ptr )
652 {
653 if ( info_ptr )
654 {
655 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
656 free(info_ptr);
657 }
658 else
659 png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
660 }
661 return FALSE;
662 }
663
664
665 bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream )
666 {
667 {
668 png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
669 if (!png_ptr)
670 {
671 return FALSE;
672 }
673
674 png_infop info_ptr = png_create_info_struct(png_ptr);
675 if (info_ptr == NULL)
676 {
677 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
678 return FALSE;
679 }
680
681 if (setjmp(png_ptr->jmpbuf))
682 {
683 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
684 return FALSE;
685 }
686
687 png_set_write_fn( png_ptr, &stream, _PNG_stream_writer, NULL);
688
689 png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
690 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
691 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
692
693 png_color_8 sig_bit;
694 sig_bit.red = 8;
695 sig_bit.green = 8;
696 sig_bit.blue = 8;
697 sig_bit.alpha = 8;
698 png_set_sBIT( png_ptr, info_ptr, &sig_bit );
699 png_write_info( png_ptr, info_ptr );
700 png_set_shift( png_ptr, &sig_bit );
701 png_set_packing( png_ptr );
702
703 unsigned char *data = (unsigned char *)malloc( image->GetWidth()*4 );
704 if (!data)
705 {
706 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
707 return FALSE;
708 }
709
710 for (int y = 0; y < image->GetHeight(); y++)
711 {
712 unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
713 for (int x = 0; x < image->GetWidth(); x++)
714 {
715 data[(x << 2) + 0] = *ptr++;
716 data[(x << 2) + 1] = *ptr++;
717 data[(x << 2) + 2] = *ptr++;
718 if ((data[(x << 2) + 0] == image->GetMaskRed()) &&
719 (data[(x << 2) + 1] == image->GetMaskGreen()) &&
720 (data[(x << 2) + 2] == image->GetMaskBlue()))
721 {
722 data[(x << 2) + 3] = 0;
723 }
724 else
725 {
726 data[(x << 2) + 3] = 255;
727 }
728 }
729 png_bytep row_ptr = data;
730 png_write_rows( png_ptr, &row_ptr, 1 );
731 }
732
733 free(data);
734 png_write_end( png_ptr, info_ptr );
735 png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );
736 }
737 return TRUE;
738 }
739
740 #endif
741
742 // wxUSE_LIBPNG
743
744 //-----------------------------------------------------------------------------
745 // wxBMPHandler
746 //-----------------------------------------------------------------------------
747
748 #if !USE_SHARED_LIBRARIES
749 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
750 #endif
751
752 bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
753 {
754 unsigned char *data, *ptr;
755 int done, i, bpp, planes, comp, ncolors, line, column,
756 linesize, linepos, rshift = 0, gshift = 0, bshift = 0;
757 unsigned char aByte;
758 short int word;
759 long int dbuf[4], dword, rmask = 0, gmask = 0, bmask = 0, offset,
760 size;
761 off_t start_offset = stream.TellI();
762 signed char bbuf[4];
763 struct _cmap
764 {
765 unsigned char r, g, b;
766 }
767 *cmap = NULL;
768 #ifndef BI_RGB
769 #define BI_RGB 0
770 #define BI_RLE8 1
771 #define BI_RLE4 2
772 #endif
773
774 #ifndef BI_BITFIELDS
775 #define BI_BITFIELDS 3
776 #endif
777
778 image->Destroy();
779
780 done = 0;
781 /*
782 * Reading the bmp header
783 */
784
785 stream.Read(&bbuf, 2);
786
787 stream.Read(dbuf, 4 * 4);
788
789 size = dbuf[0];
790 offset = dbuf[2];
791
792 stream.Read(dbuf, 4 * 2);
793 int width = (int)dbuf[0];
794 int height = (int)dbuf[1];
795 if (width > 32767)
796 {
797 wxLogError( "Image width > 32767 pixels for file\n" );
798 return FALSE;
799 }
800 if (height > 32767)
801 {
802 wxLogError( "Image height > 32767 pixels for file\n" );
803 return FALSE;
804 }
805 stream.Read(&word, 2);
806 planes = (int)word;
807 stream.Read(&word, 2);
808 bpp = (int)word;
809 if (bpp != 1 && bpp != 4 && bpp != 8 && bpp && 16 && bpp != 24 && bpp != 32)
810 {
811 wxLogError( "unknown bitdepth in file\n" );
812 return FALSE;
813 }
814 stream.Read(dbuf, 4 * 4);
815 comp = (int)dbuf[0];
816 if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
817 {
818 wxLogError( "unknown encoding in Windows BMP file\n" );
819 return FALSE;
820 }
821 stream.Read(dbuf, 4 * 2);
822 ncolors = (int)dbuf[0];
823 if (ncolors == 0)
824 ncolors = 1 << bpp;
825 /* some more sanity checks */
826 if (((comp == BI_RLE4) && (bpp != 4)) || ((comp == BI_RLE8) && (bpp != 8)) || ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
827 {
828 wxLogError( "encoding of BMP doesn't match bitdepth\n" );
829 return FALSE;
830 }
831 if (bpp < 16)
832 {
833 cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
834
835 if (!cmap)
836 {
837 wxLogError( "Cannot allocate RAM for color map in BMP file\n" );
838 return FALSE;
839 }
840 }
841 else
842 cmap = NULL;
843
844 image->Create( width, height );
845 ptr = image->GetData();
846 if (!ptr)
847 {
848 wxLogError( "Cannot allocate RAM for RGB data in file\n" );
849 if (cmap)
850 free(cmap);
851 return FALSE;
852 }
853
854 /*
855 * Reading the palette, if it exists.
856 */
857 if (bpp < 16 && ncolors != 0)
858 {
859 for (i = 0; i < ncolors; i++)
860 {
861 stream.Read(bbuf, 4);
862 cmap[i].b = bbuf[0];
863 cmap[i].g = bbuf[1];
864 cmap[i].r = bbuf[2];
865 }
866 }
867 else if (bpp == 16 || bpp == 32)
868 {
869 if (comp == BI_BITFIELDS)
870 {
871 int bit = 0;
872
873 stream.Read(dbuf, 4 * 3);
874 bmask = dbuf[0];
875 gmask = dbuf[1];
876 rmask = dbuf[2];
877 /* find shift amount.. ugly, but i can't think of a better way */
878 for (bit = 0; bit < bpp; bit++)
879 {
880 if (bmask & (1 << bit))
881 bshift = bit;
882 if (gmask & (1 << bit))
883 gshift = bit;
884 if (rmask & (1 << bit))
885 rshift = bit;
886 }
887 }
888 else if (bpp == 16)
889 {
890 rmask = 0x7C00;
891 gmask = 0x03E0;
892 bmask = 0x001F;
893 rshift = 10;
894 gshift = 5;
895 bshift = 0;
896 }
897 else if (bpp == 32)
898 {
899 rmask = 0x00FF0000;
900 gmask = 0x0000FF00;
901 bmask = 0x000000FF;
902 rshift = 16;
903 gshift = 8;
904 bshift = 0;
905 }
906 }
907
908 /*
909 * Reading the image data
910 */
911 stream.SeekI(start_offset + offset);
912 data = ptr;
913
914 /* set the whole image to the background color */
915 if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
916 {
917 for (i = 0; i < width * height; i++)
918 {
919 *ptr++ = cmap[0].r;
920 *ptr++ = cmap[0].g;
921 *ptr++ = cmap[0].b;
922 }
923 ptr = data;
924 }
925 line = 0;
926 column = 0;
927 #define poffset (line * width * 3 + column * 3)
928
929 /*
930 * BMPs are stored upside down... hmmmmmmmmmm....
931 */
932
933 linesize = ((width * bpp + 31) / 32) * 4;
934 for (line = (height - 1); line >= 0; line--)
935 {
936 linepos = 0;
937 for (column = 0; column < width;)
938 {
939 if (bpp < 16)
940 {
941 int index;
942
943 linepos++;
944 aByte = stream.GetC();
945 if (bpp == 1)
946 {
947 int bit = 0;
948
949 for (bit = 0; bit < 8; bit++)
950 {
951 index = ((aByte & (0x80 >> bit)) ? 1 : 0);
952 ptr[poffset] = cmap[index].r;
953 ptr[poffset + 1] = cmap[index].g;
954 ptr[poffset + 2] = cmap[index].b;
955 column++;
956 }
957 }
958 else if (bpp == 4)
959 {
960 if (comp == BI_RLE4)
961 {
962 wxLogError( "can't deal with 4bit encoded yet.\n");
963 image->Destroy();
964 free(cmap);
965 return FALSE;
966 }
967 else
968 {
969 int nibble = 0;
970
971 for (nibble = 0; nibble < 2; nibble++)
972 {
973 index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
974 if (index >= 16)
975 index = 15;
976 ptr[poffset] = cmap[index].r;
977 ptr[poffset + 1] = cmap[index].g;
978 ptr[poffset + 2] = cmap[index].b;
979 column++;
980 }
981 }
982 }
983 else if (bpp == 8)
984 {
985 if (comp == BI_RLE8)
986 {
987 unsigned char first;
988
989 first = aByte;
990 aByte = stream.GetC();
991 if (first == 0)
992 {
993 if (aByte == 0)
994 {
995 /* column = width; */
996 }
997 else if (aByte == 1)
998 {
999 column = width;
1000 line = -1;
1001 }
1002 else if (aByte == 2)
1003 {
1004 aByte = stream.GetC();
1005 column += aByte;
1006 linepos = column * bpp / 8;
1007 aByte = stream.GetC();
1008 line += aByte;
1009 }
1010 else
1011 {
1012 int absolute = aByte;
1013
1014 for (i = 0; i < absolute; i++)
1015 {
1016 linepos++;
1017 aByte = stream.GetC();
1018 ptr[poffset] = cmap[aByte].r;
1019 ptr[poffset + 1] = cmap[aByte].g;
1020 ptr[poffset + 2] = cmap[aByte].b;
1021 column++;
1022 }
1023 if (absolute & 0x01)
1024 aByte = stream.GetC();
1025 }
1026 }
1027 else
1028 {
1029 for (i = 0; i < first; i++)
1030 {
1031 ptr[poffset] = cmap[aByte].r;
1032 ptr[poffset + 1] = cmap[aByte].g;
1033 ptr[poffset + 2] = cmap[aByte].b;
1034 column++;
1035 linepos++;
1036 }
1037 }
1038 }
1039 else
1040 {
1041 ptr[poffset] = cmap[aByte].r;
1042 ptr[poffset + 1] = cmap[aByte].g;
1043 ptr[poffset + 2] = cmap[aByte].b;
1044 column++;
1045 linepos += size;
1046 }
1047 }
1048 }
1049 else if (bpp == 24)
1050 {
1051 stream.Read(&bbuf, 3);
1052 linepos += 3;
1053 ptr[poffset] = (unsigned char)bbuf[2];
1054 ptr[poffset + 1] = (unsigned char)bbuf[1];
1055 ptr[poffset + 2] = (unsigned char)bbuf[0];
1056 column++;
1057 }
1058 else if (bpp == 16)
1059 {
1060 unsigned char temp;
1061
1062 stream.Read(&word, 2);
1063 linepos += 2;
1064 temp = (word & rmask) >> rshift;
1065 ptr[poffset] = temp;
1066 temp = (word & gmask) >> gshift;
1067 ptr[poffset + 1] = temp;
1068 temp = (word & bmask) >> gshift;
1069 ptr[poffset + 2] = temp;
1070 column++;
1071 }
1072 else
1073 {
1074 unsigned char temp;
1075
1076 stream.Read(&dword, 4);
1077 linepos += 4;
1078 temp = (dword & rmask) >> rshift;
1079 ptr[poffset] = temp;
1080 temp = (dword & gmask) >> gshift;
1081 ptr[poffset + 1] = temp;
1082 temp = (dword & bmask) >> bshift;
1083 ptr[poffset + 2] = temp;
1084 column++;
1085 }
1086 }
1087 while ((linepos < linesize) && (comp != 1) && (comp != 2))
1088 {
1089 stream.Read(&aByte, 1);
1090 linepos += 1;
1091 if (stream.LastError() != wxStream_NOERROR)
1092 break;
1093 }
1094 }
1095 if (cmap) free(cmap);
1096
1097 image->SetMask( FALSE );
1098
1099 return TRUE;
1100 }
1101
1102 #ifdef __WXMSW__
1103
1104 wxBitmap wxImage::ConvertToBitmap() const
1105 {
1106 // sizeLimit is the MS upper limit for the DIB size
1107 int sizeLimit = 1024*768*3;
1108
1109 // width and height of the device-dependent bitmap
1110 int width = GetWidth();
1111 int bmpHeight = GetHeight();
1112
1113 // calc the number of bytes per scanline and padding
1114 int bytePerLine = width*3;
1115 int sizeDWORD = sizeof( DWORD );
1116 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1117 int padding = 0;
1118 if( lineBoundary.rem > 0 )
1119 {
1120 padding = sizeDWORD - lineBoundary.rem;
1121 bytePerLine += padding;
1122 }
1123 // calc the number of DIBs and heights of DIBs
1124 int numDIB = 1;
1125 int hRemain = 0;
1126 int height = sizeLimit/bytePerLine;
1127 if( height >= bmpHeight )
1128 height = bmpHeight;
1129 else
1130 {
1131 div_t result = div( bmpHeight, height );
1132 numDIB = result.quot;
1133 hRemain = result.rem;
1134 if( hRemain >0 ) numDIB++;
1135 }
1136
1137 // set bitmap parameters
1138 wxBitmap bitmap;
1139 wxCHECK_MSG( Ok(), bitmap, "invalid image" );
1140 bitmap.SetWidth( width );
1141 bitmap.SetHeight( bmpHeight );
1142 bitmap.SetDepth( wxDisplayDepth() );
1143
1144 // create a DIB header
1145 int headersize = sizeof(BITMAPINFOHEADER);
1146 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1147 wxCHECK_MSG( lpDIBh, bitmap, "could not allocate memory for DIB header" );
1148 // Fill in the DIB header
1149 lpDIBh->bmiHeader.biSize = headersize;
1150 lpDIBh->bmiHeader.biWidth = (DWORD)width;
1151 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1152 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1153 // the general formula for biSizeImage:
1154 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
1155 lpDIBh->bmiHeader.biPlanes = 1;
1156 lpDIBh->bmiHeader.biBitCount = 24;
1157 lpDIBh->bmiHeader.biCompression = BI_RGB;
1158 lpDIBh->bmiHeader.biClrUsed = 0;
1159 // These seem not really needed for our purpose here.
1160 lpDIBh->bmiHeader.biClrImportant = 0;
1161 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1162 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1163 // memory for DIB data
1164 unsigned char *lpBits;
1165 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
1166 if( !lpBits )
1167 {
1168 wxFAIL_MSG( "could not allocate memory for DIB" );
1169 free( lpDIBh );
1170 return bitmap;
1171 }
1172
1173 // create and set the device-dependent bitmap
1174 HDC hdc = ::GetDC(NULL);
1175 HDC memdc = ::CreateCompatibleDC( hdc );
1176 HBITMAP hbitmap;
1177 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
1178 ::SelectObject( memdc, hbitmap);
1179
1180 // copy image data into DIB data and then into DDB (in a loop)
1181 unsigned char *data = GetData();
1182 int i, j, n;
1183 int origin = 0;
1184 unsigned char *ptdata = data;
1185 unsigned char *ptbits;
1186
1187 for( n=0; n<numDIB; n++ )
1188 {
1189 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
1190 {
1191 // redefine height and size of the (possibly) last smaller DIB
1192 // memory is not reallocated
1193 height = hRemain;
1194 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1195 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1196 }
1197 ptbits = lpBits;
1198
1199 for( j=0; j<height; j++ )
1200 {
1201 for( i=0; i<width; i++ )
1202 {
1203 *(ptbits++) = *(ptdata+2);
1204 *(ptbits++) = *(ptdata+1);
1205 *(ptbits++) = *(ptdata );
1206 ptdata += 3;
1207 }
1208 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
1209 }
1210 ::StretchDIBits( memdc, 0, origin, width, height,\
1211 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1212 origin += height;
1213 // if numDIB = 1, lines below can also be used
1214 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1215 // The above line is equivalent to the following two lines.
1216 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1217 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1218 // or the following lines
1219 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1220 // HDC memdc = ::CreateCompatibleDC( hdc );
1221 // ::SelectObject( memdc, hbitmap);
1222 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1223 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1224 // ::SelectObject( memdc, 0 );
1225 // ::DeleteDC( memdc );
1226 }
1227 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
1228
1229 // similarly, created an mono-bitmap for the possible mask
1230 if( HasMask() )
1231 {
1232 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
1233 ::SelectObject( memdc, hbitmap);
1234 if( numDIB == 1 ) height = bmpHeight;
1235 else height = sizeLimit/bytePerLine;
1236 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1237 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1238 origin = 0;
1239 unsigned char r = GetMaskRed();
1240 unsigned char g = GetMaskGreen();
1241 unsigned char b = GetMaskBlue();
1242 unsigned char zero = 0, one = 255;
1243 ptdata = data;
1244 for( n=0; n<numDIB; n++ )
1245 {
1246 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
1247 {
1248 // redefine height and size of the (possibly) last smaller DIB
1249 // memory is not reallocated
1250 height = hRemain;
1251 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1252 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1253 }
1254 ptbits = lpBits;
1255 for( int j=0; j<height; j++ )
1256 {
1257 for( int i=0; i<width; i++ )
1258 {
1259 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
1260 {
1261 *(ptbits++) = one;
1262 *(ptbits++) = one;
1263 *(ptbits++) = one;
1264 }
1265 else
1266 {
1267 *(ptbits++) = zero;
1268 *(ptbits++) = zero;
1269 *(ptbits++) = zero;
1270 }
1271 }
1272 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
1273 }
1274 ::StretchDIBits( memdc, 0, origin, width, height,\
1275 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1276 origin += height;
1277 }
1278 // create a wxMask object
1279 wxMask *mask = new wxMask();
1280 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
1281 bitmap.SetMask( mask );
1282 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1283 /* The following can also be used but is slow to run
1284 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1285 wxMask *mask = new wxMask( bitmap, colour );
1286 bitmap.SetMask( mask );
1287 */
1288 }
1289
1290 // free allocated resources
1291 ::SelectObject( memdc, 0 );
1292 ::DeleteDC( memdc );
1293 ::ReleaseDC(NULL, hdc);
1294 free(lpDIBh);
1295 free(lpBits);
1296
1297 // check the wxBitmap object
1298 if( bitmap.GetHBITMAP() )
1299 bitmap.SetOk( TRUE );
1300 else
1301 bitmap.SetOk( FALSE );
1302
1303 return bitmap;
1304 }
1305
1306 wxImage::wxImage( const wxBitmap &bitmap )
1307 {
1308 // check the bitmap
1309 if( !bitmap.Ok() )
1310 {
1311 wxFAIL_MSG( "invalid bitmap" );
1312 return;
1313 }
1314
1315 // create an wxImage object
1316 int width = bitmap.GetWidth();
1317 int height = bitmap.GetHeight();
1318 Create( width, height );
1319 unsigned char *data = GetData();
1320 if( !data )
1321 {
1322 wxFAIL_MSG( "could not allocate data for image" );
1323 return;
1324 }
1325
1326 // calc the number of bytes per scanline and padding in the DIB
1327 int bytePerLine = width*3;
1328 int sizeDWORD = sizeof( DWORD );
1329 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1330 int padding = 0;
1331 if( lineBoundary.rem > 0 )
1332 {
1333 padding = sizeDWORD - lineBoundary.rem;
1334 bytePerLine += padding;
1335 }
1336
1337 // create a DIB header
1338 int headersize = sizeof(BITMAPINFOHEADER);
1339 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1340 if( !lpDIBh )
1341 {
1342 wxFAIL_MSG( "could not allocate data for DIB header" );
1343 free( data );
1344 return;
1345 }
1346 // Fill in the DIB header
1347 lpDIBh->bmiHeader.biSize = headersize;
1348 lpDIBh->bmiHeader.biWidth = width;
1349 lpDIBh->bmiHeader.biHeight = -height;
1350 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1351 lpDIBh->bmiHeader.biPlanes = 1;
1352 lpDIBh->bmiHeader.biBitCount = 24;
1353 lpDIBh->bmiHeader.biCompression = BI_RGB;
1354 lpDIBh->bmiHeader.biClrUsed = 0;
1355 // These seem not really needed for our purpose here.
1356 lpDIBh->bmiHeader.biClrImportant = 0;
1357 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1358 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1359 // memory for DIB data
1360 unsigned char *lpBits;
1361 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1362 if( !lpBits )
1363 {
1364 wxFAIL_MSG( "could not allocate data for DIB" );
1365 free( data );
1366 free( lpDIBh );
1367 return;
1368 }
1369
1370 // copy data from the device-dependent bitmap to the DIB
1371 HDC hdc = ::GetDC(NULL);
1372 HBITMAP hbitmap;
1373 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1374 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1375
1376 // copy DIB data into the wxImage object
1377 int i, j;
1378 unsigned char *ptdata = data;
1379 unsigned char *ptbits = lpBits;
1380 for( i=0; i<height; i++ )
1381 {
1382 for( j=0; j<width; j++ )
1383 {
1384 *(ptdata++) = *(ptbits+2);
1385 *(ptdata++) = *(ptbits+1);
1386 *(ptdata++) = *(ptbits );
1387 ptbits += 3;
1388 }
1389 ptbits += padding;
1390 }
1391
1392 // similarly, set data according to the possible mask bitmap
1393 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1394 {
1395 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1396 // memory DC created, color set, data copied, and memory DC deleted
1397 HDC memdc = ::CreateCompatibleDC( hdc );
1398 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1399 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1400 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1401 ::DeleteDC( memdc );
1402 // background color set to RGB(16,16,16) in consistent with wxGTK
1403 unsigned char r=16, g=16, b=16;
1404 ptdata = data;
1405 ptbits = lpBits;
1406 for( i=0; i<height; i++ )
1407 {
1408 for( j=0; j<width; j++ )
1409 {
1410 if( *ptbits != 0 )
1411 ptdata += 3;
1412 else
1413 {
1414 *(ptdata++) = r;
1415 *(ptdata++) = g;
1416 *(ptdata++) = b;
1417 }
1418 ptbits += 3;
1419 }
1420 ptbits += padding;
1421 }
1422 SetMaskColour( r, g, b );
1423 SetMask( TRUE );
1424 }
1425 else
1426 {
1427 SetMask( FALSE );
1428 }
1429 // free allocated resources
1430 ::ReleaseDC(NULL, hdc);
1431 free(lpDIBh);
1432 free(lpBits);
1433 }
1434
1435 #endif
1436
1437 #ifdef __WXGTK__
1438
1439 #include "gtk/gtk.h"
1440 #include "gdk/gdk.h"
1441 #include "gdk/gdkx.h"
1442
1443 wxBitmap wxImage::ConvertToBitmap() const
1444 {
1445 wxBitmap bitmap;
1446
1447 wxCHECK_MSG( Ok(), bitmap, "invalid image" );
1448
1449 int width = GetWidth();
1450 int height = GetHeight();
1451
1452 bitmap.SetHeight( height );
1453 bitmap.SetWidth( width );
1454
1455 // Create picture
1456
1457 GdkImage *data_image =
1458 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
1459
1460 bitmap.SetPixmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, -1 ) );
1461
1462 // Create mask
1463
1464 GdkImage *mask_image = (GdkImage*) NULL;
1465
1466 if (HasMask())
1467 {
1468 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1469
1470 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1471
1472 wxMask *mask = new wxMask();
1473 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1474
1475 bitmap.SetMask( mask );
1476 }
1477
1478 // Retrieve depth
1479
1480 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1481 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1482 int bpp = visual->depth;
1483
1484 bitmap.SetDepth( bpp );
1485
1486 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1487 if (bpp < 8) bpp = 8;
1488
1489 // Render
1490
1491 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1492 byte_order b_o = RGB;
1493
1494 if (bpp >= 24)
1495 {
1496 GdkVisual *visual = gdk_visual_get_system();
1497 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1498 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1499 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1500 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1501 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1502 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1503 }
1504
1505 int r_mask = GetMaskRed();
1506 int g_mask = GetMaskGreen();
1507 int b_mask = GetMaskBlue();
1508
1509 unsigned char* data = GetData();
1510
1511 int index = 0;
1512 for (int y = 0; y < height; y++)
1513 {
1514 for (int x = 0; x < width; x++)
1515 {
1516 int r = data[index];
1517 index++;
1518 int g = data[index];
1519 index++;
1520 int b = data[index];
1521 index++;
1522
1523 if (HasMask())
1524 {
1525 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1526 gdk_image_put_pixel( mask_image, x, y, 1 );
1527 else
1528 gdk_image_put_pixel( mask_image, x, y, 0 );
1529 }
1530
1531 if (HasMask())
1532 {
1533 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1534 gdk_image_put_pixel( mask_image, x, y, 1 );
1535 else
1536 gdk_image_put_pixel( mask_image, x, y, 0 );
1537 }
1538
1539 switch (bpp)
1540 {
1541 case 8:
1542 {
1543 int pixel = -1;
1544 if (wxTheApp->m_colorCube)
1545 {
1546 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1547 }
1548 else
1549 {
1550 GdkColormap *cmap = gtk_widget_get_default_colormap();
1551 GdkColor *colors = cmap->colors;
1552 int max = 3 * (65536);
1553
1554 for (int i = 0; i < cmap->size; i++)
1555 {
1556 int rdiff = (r << 8) - colors[i].red;
1557 int gdiff = (g << 8) - colors[i].green;
1558 int bdiff = (b << 8) - colors[i].blue;
1559 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1560 if (sum < max) { pixel = i; max = sum; }
1561 }
1562 }
1563
1564 gdk_image_put_pixel( data_image, x, y, pixel );
1565
1566 break;
1567 }
1568 case 15:
1569 {
1570 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1571 gdk_image_put_pixel( data_image, x, y, pixel );
1572 break;
1573 }
1574 case 16:
1575 {
1576 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1577 gdk_image_put_pixel( data_image, x, y, pixel );
1578 break;
1579 }
1580 case 32:
1581 case 24:
1582 {
1583 guint32 pixel = 0;
1584 switch (b_o)
1585 {
1586 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1587 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1588 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1589 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1590 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1591 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1592 }
1593 gdk_image_put_pixel( data_image, x, y, pixel );
1594 }
1595 default: break;
1596 }
1597 } // for
1598 } // for
1599
1600 // Blit picture
1601
1602 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1603
1604 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1605
1606 gdk_image_destroy( data_image );
1607 gdk_gc_unref( data_gc );
1608
1609 // Blit mask
1610
1611 if (HasMask())
1612 {
1613 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1614
1615 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1616
1617 gdk_image_destroy( mask_image );
1618 gdk_gc_unref( mask_gc );
1619 }
1620
1621 return bitmap;
1622 }
1623
1624 wxImage::wxImage( const wxBitmap &bitmap )
1625 {
1626 wxCHECK_RET( bitmap.Ok(), "invalid bitmap" );
1627
1628 GdkImage *gdk_image = gdk_image_get( bitmap.GetPixmap(),
1629 0, 0,
1630 bitmap.GetWidth(), bitmap.GetHeight() );
1631
1632 wxCHECK_RET( gdk_image, "couldn't create image" );
1633
1634 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1635 char unsigned *data = GetData();
1636
1637 if (!data)
1638 {
1639 gdk_image_destroy( gdk_image );
1640 wxFAIL_MSG( "couldn't create image" );
1641 return;
1642 }
1643
1644 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1645 if (bitmap.GetMask())
1646 {
1647 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1648 0, 0,
1649 bitmap.GetWidth(), bitmap.GetHeight() );
1650
1651 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1652 }
1653
1654 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1655 if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
1656 int bpp = visual->depth;
1657 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1658
1659 GdkColormap *cmap = gtk_widget_get_default_colormap();
1660
1661 long pos = 0;
1662 for (int j = 0; j < bitmap.GetHeight(); j++)
1663 {
1664 for (int i = 0; i < bitmap.GetWidth(); i++)
1665 {
1666 int pixel = gdk_image_get_pixel( gdk_image, i, j );
1667 if (bpp <= 8)
1668 {
1669 data[pos] = cmap->colors[pixel].red >> 8;
1670 data[pos+1] = cmap->colors[pixel].green >> 8;
1671 data[pos+2] = cmap->colors[pixel].blue >> 8;
1672 } else if (bpp == 15)
1673 {
1674 data[pos] = (pixel >> 7) & 0xf8;
1675 data[pos+1] = (pixel >> 2) & 0xf8;
1676 data[pos+2] = (pixel << 3) & 0xf8;
1677 } else if (bpp == 16)
1678 {
1679 data[pos] = (pixel >> 8) & 0xf8;
1680 data[pos+1] = (pixel >> 3) & 0xfc;
1681 data[pos+2] = (pixel << 3) & 0xf8;
1682 } else
1683 {
1684 data[pos] = (pixel >> 16) & 0xff;
1685 data[pos+1] = (pixel >> 8) & 0xff;
1686 data[pos+2] = pixel & 0xff;
1687 }
1688
1689 if (gdk_image_mask)
1690 {
1691 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1692 if (mask_pixel == 0)
1693 {
1694 data[pos] = 16;
1695 data[pos+1] = 16;
1696 data[pos+2] = 16;
1697 }
1698 }
1699
1700 pos += 3;
1701 }
1702 }
1703
1704 gdk_image_destroy( gdk_image );
1705 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1706 }
1707
1708 #endif
1709
1710 #ifdef __WXMOTIF__
1711
1712 #include <Xm/Xm.h>
1713 #include "wx/utils.h"
1714 #include <math.h>
1715
1716 wxBitmap wxImage::ConvertToBitmap() const
1717 {
1718 wxBitmap bitmap;
1719
1720 wxCHECK_MSG( Ok(), bitmap, "invalid image" );
1721
1722 int width = GetWidth();
1723 int height = GetHeight();
1724
1725 bitmap.SetHeight( height );
1726 bitmap.SetWidth( width );
1727
1728 Display *dpy = (Display*) wxGetDisplay();
1729 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1730 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1731
1732 // Create image
1733
1734 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
1735 data_image->data = new char[ data_image->bytes_per_line * data_image->height ];
1736
1737 bitmap.Create( width, height, bpp );
1738
1739 /*
1740 // Create mask
1741
1742 GdkImage *mask_image = (GdkImage*) NULL;
1743
1744 if (HasMask())
1745 {
1746 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1747
1748 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1749
1750 wxMask *mask = new wxMask();
1751 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1752
1753 bitmap.SetMask( mask );
1754 }
1755 */
1756
1757 // Retrieve depth info
1758
1759 XVisualInfo vinfo_template;
1760 XVisualInfo *vi;
1761
1762 vinfo_template.visual = vis;
1763 vinfo_template.visualid = XVisualIDFromVisual( vis );
1764 vinfo_template.depth = bpp;
1765 int nitem = 0;
1766
1767 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1768
1769 if (!vi)
1770 {
1771 printf("no visual.\n" );
1772 return wxNullBitmap;
1773 }
1774
1775 XFree( vi );
1776
1777 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1778 if (bpp < 8) bpp = 8;
1779
1780 // Render
1781
1782 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1783 byte_order b_o = RGB;
1784
1785 if (bpp >= 24)
1786 {
1787 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1788 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1789 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1790 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1791 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1792 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1793 }
1794
1795 /*
1796 int r_mask = GetMaskRed();
1797 int g_mask = GetMaskGreen();
1798 int b_mask = GetMaskBlue();
1799 */
1800
1801 XColor colors[256];
1802 if (bpp == 8)
1803 {
1804 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
1805
1806 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1807 XQueryColors( dpy, cmap, colors, 256 );
1808 }
1809
1810 unsigned char* data = GetData();
1811
1812 int index = 0;
1813 for (int y = 0; y < height; y++)
1814 {
1815 for (int x = 0; x < width; x++)
1816 {
1817 int r = data[index];
1818 index++;
1819 int g = data[index];
1820 index++;
1821 int b = data[index];
1822 index++;
1823
1824 /*
1825 if (HasMask())
1826 {
1827 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1828 gdk_image_put_pixel( mask_image, x, y, 1 );
1829 else
1830 gdk_image_put_pixel( mask_image, x, y, 0 );
1831 }
1832 */
1833
1834 switch (bpp)
1835 {
1836 case 8:
1837 {
1838 int pixel = -1;
1839 /*
1840 if (wxTheApp->m_colorCube)
1841 {
1842 pixel = wxTheApp->m_colorCube
1843 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1844 }
1845 else
1846 {
1847 */
1848 int max = 3 * (65536);
1849 for (int i = 0; i < 256; i++)
1850 {
1851 int rdiff = (r << 8) - colors[i].red;
1852 int gdiff = (g << 8) - colors[i].green;
1853 int bdiff = (b << 8) - colors[i].blue;
1854 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1855 if (sum < max) { pixel = i; max = sum; }
1856 }
1857 /*
1858 }
1859 */
1860 XPutPixel( data_image, x, y, pixel );
1861 break;
1862 }
1863 case 15:
1864 {
1865 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1866 XPutPixel( data_image, x, y, pixel );
1867 break;
1868 }
1869 case 16:
1870 {
1871 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1872 XPutPixel( data_image, x, y, pixel );
1873 break;
1874 }
1875 case 32:
1876 case 24:
1877 {
1878 int pixel = 0;
1879 switch (b_o)
1880 {
1881 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1882 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1883 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1884 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1885 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1886 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1887 }
1888 XPutPixel( data_image, x, y, pixel );
1889 }
1890 default: break;
1891 }
1892 } // for
1893 } // for
1894
1895 // Blit picture
1896
1897 XGCValues gcvalues;
1898 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
1899 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
1900 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
1901
1902 XDestroyImage( data_image );
1903 XFreeGC( dpy, gc );
1904
1905 /*
1906 // Blit mask
1907
1908 if (HasMask())
1909 {
1910 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1911
1912 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1913
1914 gdk_image_destroy( mask_image );
1915 gdk_gc_unref( mask_gc );
1916 }
1917 */
1918
1919 return bitmap;
1920 }
1921
1922 wxImage::wxImage( const wxBitmap &bitmap )
1923 {
1924 wxCHECK_RET( bitmap.Ok(), "invalid bitmap" );
1925
1926 Display *dpy = (Display*) wxGetDisplay();
1927 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1928 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1929
1930 XImage *ximage = XGetImage( dpy,
1931 (Drawable)bitmap.GetPixmap(),
1932 0, 0,
1933 bitmap.GetWidth(), bitmap.GetHeight(),
1934 AllPlanes, ZPixmap );
1935
1936 wxCHECK_RET( ximage, "couldn't create image" );
1937
1938 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1939 char unsigned *data = GetData();
1940
1941 if (!data)
1942 {
1943 XDestroyImage( ximage );
1944 wxFAIL_MSG( "couldn't create image" );
1945 return;
1946 }
1947
1948 /*
1949 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1950 if (bitmap.GetMask())
1951 {
1952 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1953 0, 0,
1954 bitmap.GetWidth(), bitmap.GetHeight() );
1955
1956 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1957 }
1958 */
1959
1960 // Retrieve depth info
1961
1962 XVisualInfo vinfo_template;
1963 XVisualInfo *vi;
1964
1965 vinfo_template.visual = vis;
1966 vinfo_template.visualid = XVisualIDFromVisual( vis );
1967 vinfo_template.depth = bpp;
1968 int nitem = 0;
1969
1970 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1971
1972 if (!vi)
1973 {
1974 printf("no visual.\n" );
1975 return;
1976 }
1977
1978 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1979
1980 XFree( vi );
1981
1982 XColor colors[256];
1983 if (bpp == 8)
1984 {
1985 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
1986
1987 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1988 XQueryColors( dpy, cmap, colors, 256 );
1989 }
1990
1991 long pos = 0;
1992 for (int j = 0; j < bitmap.GetHeight(); j++)
1993 {
1994 for (int i = 0; i < bitmap.GetWidth(); i++)
1995 {
1996 int pixel = XGetPixel( ximage, i, j );
1997 if (bpp <= 8)
1998 {
1999 data[pos] = colors[pixel].red >> 8;
2000 data[pos+1] = colors[pixel].green >> 8;
2001 data[pos+2] = colors[pixel].blue >> 8;
2002 } else if (bpp == 15)
2003 {
2004 data[pos] = (pixel >> 7) & 0xf8;
2005 data[pos+1] = (pixel >> 2) & 0xf8;
2006 data[pos+2] = (pixel << 3) & 0xf8;
2007 } else if (bpp == 16)
2008 {
2009 data[pos] = (pixel >> 8) & 0xf8;
2010 data[pos+1] = (pixel >> 3) & 0xfc;
2011 data[pos+2] = (pixel << 3) & 0xf8;
2012 } else
2013 {
2014 data[pos] = (pixel >> 16) & 0xff;
2015 data[pos+1] = (pixel >> 8) & 0xff;
2016 data[pos+2] = pixel & 0xff;
2017 }
2018
2019 /*
2020 if (gdk_image_mask)
2021 {
2022 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2023 if (mask_pixel == 0)
2024 {
2025 data[pos] = 16;
2026 data[pos+1] = 16;
2027 data[pos+2] = 16;
2028 }
2029 }
2030 */
2031
2032 pos += 3;
2033 }
2034 }
2035
2036 XDestroyImage( ximage );
2037 /*
2038 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2039 */
2040 }
2041 #endif