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