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