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