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