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