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