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