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