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