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