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