]> git.saurik.com Git - wxWidgets.git/blame - src/common/image.cpp
Minor GTK fixes for wxGrid.
[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{
fd0eed64 48public:
edccf428
VZ
49 wxImageRefData();
50 ~wxImageRefData();
c7abc967 51
dbda9e86
JS
52 int m_width;
53 int m_height;
54 unsigned char *m_data;
55 bool m_hasMask;
56 unsigned char m_maskRed,m_maskGreen,m_maskBlue;
57 bool m_ok;
01111366
RR
58};
59
edccf428 60wxImageRefData::wxImageRefData()
01111366 61{
fd0eed64
RR
62 m_width = 0;
63 m_height = 0;
64 m_data = (unsigned char*) NULL;
65 m_ok = FALSE;
66 m_maskRed = 0;
67 m_maskGreen = 0;
68 m_maskBlue = 0;
69 m_hasMask = FALSE;
01111366
RR
70}
71
edccf428 72wxImageRefData::~wxImageRefData()
01111366 73{
97fdfcc9 74 if (m_data)
58c837a4 75 free( m_data );
01111366
RR
76}
77
78wxList wxImage::sm_handlers;
79
80//-----------------------------------------------------------------------------
81
82#define M_IMGDATA ((wxImageRefData *)m_refData)
83
edccf428 84 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
01111366
RR
85
86wxImage::wxImage()
87{
88}
89
90wxImage::wxImage( int width, int height )
91{
fd0eed64 92 Create( width, height );
01111366
RR
93}
94
95wxImage::wxImage( const wxString& name, long type )
96{
fd0eed64 97 LoadFile( name, type );
01111366
RR
98}
99
9e9ee68e
VS
100wxImage::wxImage( const wxString& name, const wxString& mimetype )
101{
102 LoadFile( name, mimetype );
103}
104
e02afc7a 105#if wxUSE_STREAMS
3d05544e
JS
106wxImage::wxImage( wxInputStream& stream, long type )
107{
108 LoadFile( stream, type );
109}
9e9ee68e
VS
110
111wxImage::wxImage( wxInputStream& stream, const wxString& mimetype )
112{
113 LoadFile( stream, mimetype );
114}
e02afc7a 115#endif // wxUSE_STREAMS
3d05544e 116
4698648f
VZ
117wxImage::wxImage( const wxImage& image )
118{
119 Ref(image);
01111366
RR
120}
121
4698648f
VZ
122wxImage::wxImage( const wxImage* image )
123{
124 if (image) Ref(*image);
01111366
RR
125}
126
127void wxImage::Create( int width, int height )
128{
fd0eed64 129 m_refData = new wxImageRefData();
c7abc967 130
fd0eed64
RR
131 M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
132 if (M_IMGDATA->m_data)
133 {
134 for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
c7abc967 135
fd0eed64
RR
136 M_IMGDATA->m_width = width;
137 M_IMGDATA->m_height = height;
138 M_IMGDATA->m_ok = TRUE;
139 }
140 else
141 {
142 UnRef();
143 }
01111366
RR
144}
145
146void wxImage::Destroy()
147{
fd0eed64 148 UnRef();
01111366
RR
149}
150
ce9a75d2 151wxImage wxImage::Scale( int width, int height ) const
4bc67cc5
RR
152{
153 wxImage image;
c7abc967 154
223d09f6 155 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
c7abc967 156
223d09f6 157 wxCHECK_MSG( (width > 0) && (height > 0), image, wxT("invalid image size") );
c7abc967 158
4bc67cc5 159 image.Create( width, height );
c7abc967 160
4bc67cc5 161 char unsigned *data = image.GetData();
c7abc967 162
223d09f6 163 wxCHECK_MSG( data, image, wxT("unable to create image") );
c7abc967 164
4bc67cc5
RR
165 if (M_IMGDATA->m_hasMask)
166 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
c7abc967 167
6e13c196
RR
168 long old_height = M_IMGDATA->m_height;
169 long old_width = M_IMGDATA->m_width;
c7abc967 170
6e13c196
RR
171 char unsigned *source_data = M_IMGDATA->m_data;
172 char unsigned *target_data = data;
c7abc967 173
6e13c196 174 for (long j = 0; j < height; j++)
4bc67cc5 175 {
6e13c196 176 long y_offset = (j * old_height / height) * old_width;
c7abc967 177
6e13c196 178 for (long i = 0; i < width; i++)
4698648f 179 {
c7abc967
VZ
180 memcpy( target_data,
181 source_data + 3*(y_offset + ((i * old_width )/ width)),
dbda9e86 182 3 );
6e13c196 183 target_data += 3;
4698648f 184 }
4bc67cc5 185 }
c7abc967 186
4bc67cc5
RR
187 return image;
188}
4698648f 189
7b2471a0
SB
190wxImage wxImage::GetSubImage( const wxRect &rect ) const
191{
192 wxImage image;
193
223d09f6 194 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
7b2471a0 195
58c837a4
RR
196 wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()),
197 image, wxT("invalid subimage size") );
7b2471a0
SB
198
199 int subwidth=rect.GetWidth();
200 const int subheight=rect.GetHeight();
201
202 image.Create( subwidth, subheight );
203
204 char unsigned *subdata = image.GetData(), *data=GetData();
205
223d09f6 206 wxCHECK_MSG( subdata, image, wxT("unable to create image") );
7b2471a0
SB
207
208 if (M_IMGDATA->m_hasMask)
209 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
210
211 const int subleft=3*rect.GetLeft();
212 const int width=3*GetWidth();
213 subwidth*=3;
995612e2 214
7b2471a0
SB
215 data+=rect.GetTop()*width+subleft;
216
217 for (long j = 0; j < subheight; ++j)
218 {
219 memcpy( subdata, data, subwidth);
220 subdata+=subwidth;
995612e2 221 data+=width;
7b2471a0
SB
222 }
223
224 return image;
225}
226
be25e480
RR
227void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1,
228 unsigned char r2, unsigned char g2, unsigned char b2 )
229{
230 wxCHECK_RET( Ok(), wxT("invalid image") );
231
232 char unsigned *data = GetData();
233
234 const int w = GetWidth();
235 const int h = GetHeight();
236
237 for (int j = 0; j < h; j++)
238 for (int i = 0; i < w; i++)
069d0f27
VZ
239 {
240 if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1))
241 {
242 data[0] = r2;
243 data[1] = g2;
244 data[2] = b2;
245 }
246 data += 3;
247 }
be25e480
RR
248}
249
ef539066
RR
250void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
251{
223d09f6 252 wxCHECK_RET( Ok(), wxT("invalid image") );
c7abc967 253
ef539066
RR
254 int w = M_IMGDATA->m_width;
255 int h = M_IMGDATA->m_height;
c7abc967 256
223d09f6 257 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
c7abc967 258
ef539066 259 long pos = (y * w + x) * 3;
c7abc967 260
ef539066
RR
261 M_IMGDATA->m_data[ pos ] = r;
262 M_IMGDATA->m_data[ pos+1 ] = g;
263 M_IMGDATA->m_data[ pos+2 ] = b;
264}
265
266unsigned char wxImage::GetRed( int x, int y )
267{
223d09f6 268 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 269
ef539066
RR
270 int w = M_IMGDATA->m_width;
271 int h = M_IMGDATA->m_height;
c7abc967 272
223d09f6 273 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
c7abc967 274
ef539066 275 long pos = (y * w + x) * 3;
c7abc967 276
ef539066
RR
277 return M_IMGDATA->m_data[pos];
278}
279
280unsigned char wxImage::GetGreen( int x, int y )
281{
223d09f6 282 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 283
ef539066
RR
284 int w = M_IMGDATA->m_width;
285 int h = M_IMGDATA->m_height;
c7abc967 286
223d09f6 287 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
c7abc967 288
ef539066 289 long pos = (y * w + x) * 3;
c7abc967 290
ef539066
RR
291 return M_IMGDATA->m_data[pos+1];
292}
293
294unsigned char wxImage::GetBlue( int x, int y )
295{
223d09f6 296 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 297
ef539066
RR
298 int w = M_IMGDATA->m_width;
299 int h = M_IMGDATA->m_height;
c7abc967 300
223d09f6 301 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
c7abc967 302
ef539066 303 long pos = (y * w + x) * 3;
c7abc967 304
ef539066
RR
305 return M_IMGDATA->m_data[pos+2];
306}
4698648f
VZ
307
308bool wxImage::Ok() const
309{
310 return (M_IMGDATA && M_IMGDATA->m_ok);
01111366
RR
311}
312
313char unsigned *wxImage::GetData() const
314{
223d09f6 315 wxCHECK_MSG( Ok(), (char unsigned *)NULL, wxT("invalid image") );
c7abc967 316
fd0eed64 317 return M_IMGDATA->m_data;
01111366
RR
318}
319
58a8ab88 320void wxImage::SetData( char unsigned *data )
01111366 321{
223d09f6 322 wxCHECK_RET( Ok(), wxT("invalid image") );
58a8ab88 323
ed58dbea
RR
324 wxImageRefData *newRefData = new wxImageRefData();
325
326 newRefData->m_width = M_IMGDATA->m_width;
327 newRefData->m_height = M_IMGDATA->m_height;
328 newRefData->m_data = data;
329 newRefData->m_ok = TRUE;
330 newRefData->m_maskRed = M_IMGDATA->m_maskRed;
331 newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
332 newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
333 newRefData->m_hasMask = M_IMGDATA->m_hasMask;
995612e2 334
ed58dbea 335 UnRef();
995612e2 336
ed58dbea 337 m_refData = newRefData;
01111366
RR
338}
339
340void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
341{
223d09f6 342 wxCHECK_RET( Ok(), wxT("invalid image") );
c7abc967 343
fd0eed64
RR
344 M_IMGDATA->m_maskRed = r;
345 M_IMGDATA->m_maskGreen = g;
346 M_IMGDATA->m_maskBlue = b;
347 M_IMGDATA->m_hasMask = TRUE;
01111366
RR
348}
349
350unsigned char wxImage::GetMaskRed() const
351{
223d09f6 352 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 353
fd0eed64 354 return M_IMGDATA->m_maskRed;
01111366
RR
355}
356
357unsigned char wxImage::GetMaskGreen() const
358{
223d09f6 359 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 360
fd0eed64 361 return M_IMGDATA->m_maskGreen;
01111366
RR
362}
363
364unsigned char wxImage::GetMaskBlue() const
365{
223d09f6 366 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 367
fd0eed64 368 return M_IMGDATA->m_maskBlue;
01111366 369}
4698648f 370
01111366
RR
371void wxImage::SetMask( bool mask )
372{
223d09f6 373 wxCHECK_RET( Ok(), wxT("invalid image") );
c7abc967 374
fd0eed64 375 M_IMGDATA->m_hasMask = mask;
01111366
RR
376}
377
378bool wxImage::HasMask() const
379{
223d09f6 380 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
c7abc967 381
fd0eed64 382 return M_IMGDATA->m_hasMask;
01111366
RR
383}
384
4698648f
VZ
385int wxImage::GetWidth() const
386{
223d09f6 387 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 388
4698648f 389 return M_IMGDATA->m_width;
01111366
RR
390}
391
4698648f
VZ
392int wxImage::GetHeight() const
393{
223d09f6 394 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
c7abc967 395
4698648f 396 return M_IMGDATA->m_height;
01111366
RR
397}
398
399bool wxImage::LoadFile( const wxString& filename, long type )
400{
e02afc7a 401#if wxUSE_STREAMS
3d05544e 402 if (wxFileExists(filename))
fd0eed64 403 {
3d05544e 404 wxFileInputStream stream(filename);
069d0f27 405 wxBufferedInputStream bstream( stream );
1b055864 406 return LoadFile(bstream, type);
3d05544e 407 }
97fdfcc9 408 else
58c837a4
RR
409 {
410 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
9e9ee68e
VS
411
412 return FALSE;
413 }
414#else // !wxUSE_STREAMS
415 return FALSE;
416#endif // wxUSE_STREAMS
417}
418
419bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype )
420{
421#if wxUSE_STREAMS
422 if (wxFileExists(filename))
423 {
424 wxFileInputStream stream(filename);
069d0f27 425 wxBufferedInputStream bstream( stream );
1b055864 426 return LoadFile(bstream, mimetype);
9e9ee68e 427 }
97fdfcc9 428 else
58c837a4
RR
429 {
430 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
c7abc967 431
fd0eed64
RR
432 return FALSE;
433 }
e02afc7a 434#else // !wxUSE_STREAMS
dbda9e86 435 return FALSE;
e02afc7a 436#endif // wxUSE_STREAMS
1ccbb61a
VZ
437}
438
439bool wxImage::SaveFile( const wxString& filename, int type )
440{
e02afc7a 441#if wxUSE_STREAMS
1ccbb61a 442 wxFileOutputStream stream(filename);
9e9ee68e 443
1ccbb61a 444 if ( stream.LastError() == wxStream_NOERROR )
1b055864 445 {
069d0f27 446 wxBufferedOutputStream bstream( stream );
1b055864
RR
447 return SaveFile(bstream, type);
448 }
1ccbb61a 449 else
e02afc7a 450#endif // wxUSE_STREAMS
1ccbb61a 451 return FALSE;
3d05544e 452}
01111366 453
9e9ee68e
VS
454bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype )
455{
456#if wxUSE_STREAMS
457 wxFileOutputStream stream(filename);
c7abc967 458
9e9ee68e 459 if ( stream.LastError() == wxStream_NOERROR )
1b055864 460 {
069d0f27 461 wxBufferedOutputStream bstream( stream );
1b055864
RR
462 return SaveFile(bstream, mimetype);
463 }
9e9ee68e
VS
464 else
465#endif // wxUSE_STREAMS
466 return FALSE;
467}
468
87202f78
SB
469bool wxImage::CanRead( const wxString &name )
470{
471#if wxUSE_STREAMS
472 wxFileInputStream stream(name);
473 return CanRead(stream);
474#else
475 return FALSE;
476#endif
477}
478
e02afc7a 479#if wxUSE_STREAMS
deb2fec0 480
87202f78
SB
481bool wxImage::CanRead( wxInputStream &stream )
482{
483 wxList &list=GetHandlers();
004fd0c8 484
87202f78 485 for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
004fd0c8 486 {
87202f78
SB
487 wxImageHandler *handler=(wxImageHandler*)node->GetData();
488 if (handler->CanRead( stream ))
069d0f27 489 return TRUE;
87202f78
SB
490 }
491
492 return FALSE;
493}
494
3d05544e
JS
495bool wxImage::LoadFile( wxInputStream& stream, long type )
496{
497 UnRef();
c7abc967 498
fd0eed64 499 m_refData = new wxImageRefData;
c7abc967 500
deb2fec0
SB
501 wxImageHandler *handler;
502
503 if (type==wxBITMAP_TYPE_ANY)
504 {
995612e2 505 wxList &list=GetHandlers();
deb2fec0 506
995612e2
VZ
507 for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
508 {
509 handler=(wxImageHandler*)node->GetData();
510 if (handler->CanRead( stream ))
511 return handler->LoadFile( this, stream );
7b2471a0 512
995612e2 513 }
deb2fec0 514
58c837a4 515 wxLogWarning( _("No handler found for image type.") );
995612e2 516 return FALSE;
deb2fec0
SB
517 }
518
519 handler = FindHandler(type);
c7abc967 520
4698648f 521 if (handler == NULL)
fd0eed64 522 {
58c837a4 523 wxLogWarning( _("No image handler for type %d defined."), type );
c7abc967 524
fd0eed64
RR
525 return FALSE;
526 }
c7abc967 527
3d05544e 528 return handler->LoadFile( this, stream );
01111366
RR
529}
530
9e9ee68e
VS
531bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype )
532{
533 UnRef();
534
535 m_refData = new wxImageRefData;
536
537 wxImageHandler *handler = FindHandlerMime(mimetype);
538
539 if (handler == NULL)
540 {
58c837a4 541 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
9e9ee68e
VS
542
543 return FALSE;
544 }
545
546 return handler->LoadFile( this, stream );
547}
548
3d05544e 549bool wxImage::SaveFile( wxOutputStream& stream, int type )
01111366 550{
223d09f6 551 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
c7abc967 552
fd0eed64 553 wxImageHandler *handler = FindHandler(type);
c7abc967 554
4698648f 555 if (handler == NULL)
fd0eed64 556 {
58c837a4 557 wxLogWarning( _("No image handler for type %d defined."), type );
9e9ee68e
VS
558
559 return FALSE;
560 }
561
562 return handler->SaveFile( this, stream );
563}
564
565bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype )
566{
223d09f6 567 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
c7abc967 568
9e9ee68e 569 wxImageHandler *handler = FindHandlerMime(mimetype);
c7abc967 570
9e9ee68e
VS
571 if (handler == NULL)
572 {
58c837a4 573 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
c7abc967 574
dbda9e86 575 return FALSE;
fd0eed64 576 }
c7abc967 577
3d05544e 578 return handler->SaveFile( this, stream );
01111366 579}
e02afc7a 580#endif // wxUSE_STREAMS
01111366
RR
581
582void wxImage::AddHandler( wxImageHandler *handler )
583{
4698648f
VZ
584 // make sure that the memory will be freed at the program end
585 sm_handlers.DeleteContents(TRUE);
c7abc967 586
01111366
RR
587 sm_handlers.Append( handler );
588}
589
590void wxImage::InsertHandler( wxImageHandler *handler )
591{
4698648f
VZ
592 // make sure that the memory will be freed at the program end
593 sm_handlers.DeleteContents(TRUE);
c7abc967 594
01111366
RR
595 sm_handlers.Insert( handler );
596}
597
598bool wxImage::RemoveHandler( const wxString& name )
599{
fd0eed64
RR
600 wxImageHandler *handler = FindHandler(name);
601 if (handler)
602 {
603 sm_handlers.DeleteObject(handler);
604 return TRUE;
605 }
606 else
607 return FALSE;
01111366
RR
608}
609
610wxImageHandler *wxImage::FindHandler( const wxString& name )
611{
fd0eed64
RR
612 wxNode *node = sm_handlers.First();
613 while (node)
614 {
615 wxImageHandler *handler = (wxImageHandler*)node->Data();
ce3ed50d 616 if (handler->GetName().Cmp(name) == 0) return handler;
c7abc967 617
fd0eed64
RR
618 node = node->Next();
619 }
620 return (wxImageHandler *)NULL;
01111366
RR
621}
622
623wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
624{
fd0eed64
RR
625 wxNode *node = sm_handlers.First();
626 while (node)
627 {
628 wxImageHandler *handler = (wxImageHandler*)node->Data();
ce3ed50d 629 if ( (handler->GetExtension().Cmp(extension) == 0) &&
fd0eed64 630 (bitmapType == -1 || handler->GetType() == bitmapType) )
dbda9e86 631 return handler;
fd0eed64
RR
632 node = node->Next();
633 }
634 return (wxImageHandler*)NULL;
01111366
RR
635}
636
637wxImageHandler *wxImage::FindHandler( long bitmapType )
638{
fd0eed64
RR
639 wxNode *node = sm_handlers.First();
640 while (node)
641 {
642 wxImageHandler *handler = (wxImageHandler *)node->Data();
643 if (handler->GetType() == bitmapType) return handler;
644 node = node->Next();
645 }
646 return NULL;
647}
648
9e9ee68e
VS
649wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
650{
651 wxNode *node = sm_handlers.First();
652 while (node)
653 {
654 wxImageHandler *handler = (wxImageHandler *)node->Data();
655 if (handler->GetMimeType().IsSameAs(mimetype, FALSE)) return handler;
656 node = node->Next();
657 }
658 return NULL;
659}
660
fd0eed64
RR
661void wxImage::InitStandardHandlers()
662{
deb2fec0 663 AddHandler( new wxBMPHandler );
01111366
RR
664}
665
666void wxImage::CleanUpHandlers()
667{
fd0eed64
RR
668 wxNode *node = sm_handlers.First();
669 while (node)
670 {
671 wxImageHandler *handler = (wxImageHandler *)node->Data();
672 wxNode *next = node->Next();
673 delete handler;
674 delete node;
675 node = next;
676 }
01111366
RR
677}
678
679//-----------------------------------------------------------------------------
680// wxImageHandler
681//-----------------------------------------------------------------------------
682
63d963a1 683IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject)
01111366 684
e02afc7a 685#if wxUSE_STREAMS
700ec454 686bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
01111366 687{
fd0eed64 688 return FALSE;
01111366
RR
689}
690
deb2fec0 691bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) )
01111366 692{
fd0eed64 693 return FALSE;
01111366 694}
0828c087 695
700ec454
RR
696int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
697{
698 return 1;
699}
700
0828c087
VS
701bool wxImageHandler::CanRead( const wxString& name )
702{
0828c087
VS
703 if (wxFileExists(name))
704 {
705 wxFileInputStream stream(name);
706 return CanRead(stream);
707 }
708
709 else {
58c837a4 710 wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() );
0828c087
VS
711
712 return FALSE;
713 }
68874acf 714// return FALSE;
0828c087
VS
715}
716
e02afc7a 717#endif // wxUSE_STREAMS
01111366 718
01111366 719//-----------------------------------------------------------------------------
ce4169a4 720// MSW conversion routines
01111366
RR
721//-----------------------------------------------------------------------------
722
e3554471
JS
723#ifdef __WXMSW__
724
725wxBitmap wxImage::ConvertToBitmap() const
726{
0655ad29
VZ
727 if ( !Ok() )
728 return wxNullBitmap;
729
dbda9e86 730 // sizeLimit is the MS upper limit for the DIB size
48c12cb1 731#ifdef WIN32
c7abc967 732 int sizeLimit = 1024*768*3;
48c12cb1
PA
733#else
734 int sizeLimit = 0x7fff ;
735#endif
c7abc967 736
dbda9e86 737 // width and height of the device-dependent bitmap
bba6f3bd
UA
738 int width = GetWidth();
739 int bmpHeight = GetHeight();
c7abc967 740
dbda9e86 741 // calc the number of bytes per scanline and padding
bba6f3bd
UA
742 int bytePerLine = width*3;
743 int sizeDWORD = sizeof( DWORD );
bae41ce1 744 int lineBoundary = bytePerLine % sizeDWORD;
bba6f3bd 745 int padding = 0;
bae41ce1 746 if( lineBoundary > 0 )
bba6f3bd 747 {
bae41ce1 748 padding = sizeDWORD - lineBoundary;
bba6f3bd
UA
749 bytePerLine += padding;
750 }
dbda9e86 751 // calc the number of DIBs and heights of DIBs
bba6f3bd
UA
752 int numDIB = 1;
753 int hRemain = 0;
754 int height = sizeLimit/bytePerLine;
755 if( height >= bmpHeight )
c7abc967 756 height = bmpHeight;
bba6f3bd
UA
757 else
758 {
bae41ce1
UA
759 numDIB = bmpHeight / height;
760 hRemain = bmpHeight % height;
dbda9e86 761 if( hRemain >0 ) numDIB++;
bba6f3bd 762 }
c7abc967 763
dbda9e86 764 // set bitmap parameters
bba6f3bd 765 wxBitmap bitmap;
223d09f6 766 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
bba6f3bd
UA
767 bitmap.SetWidth( width );
768 bitmap.SetHeight( bmpHeight );
769 bitmap.SetDepth( wxDisplayDepth() );
c7abc967 770
dbda9e86 771 // create a DIB header
bba6f3bd 772 int headersize = sizeof(BITMAPINFOHEADER);
8f177c8e 773 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
223d09f6 774 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
dbda9e86 775 // Fill in the DIB header
bba6f3bd
UA
776 lpDIBh->bmiHeader.biSize = headersize;
777 lpDIBh->bmiHeader.biWidth = (DWORD)width;
778 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
779 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
dbda9e86
JS
780 // the general formula for biSizeImage:
781 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
bba6f3bd
UA
782 lpDIBh->bmiHeader.biPlanes = 1;
783 lpDIBh->bmiHeader.biBitCount = 24;
784 lpDIBh->bmiHeader.biCompression = BI_RGB;
785 lpDIBh->bmiHeader.biClrUsed = 0;
dbda9e86 786 // These seem not really needed for our purpose here.
bba6f3bd
UA
787 lpDIBh->bmiHeader.biClrImportant = 0;
788 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
789 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
dbda9e86 790 // memory for DIB data
bba6f3bd
UA
791 unsigned char *lpBits;
792 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
793 if( !lpBits )
794 {
223d09f6 795 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
bba6f3bd
UA
796 free( lpDIBh );
797 return bitmap;
798 }
c7abc967 799
dbda9e86 800 // create and set the device-dependent bitmap
bba6f3bd
UA
801 HDC hdc = ::GetDC(NULL);
802 HDC memdc = ::CreateCompatibleDC( hdc );
803 HBITMAP hbitmap;
804 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
c7abc967
VZ
805 ::SelectObject( memdc, hbitmap);
806
dbda9e86 807 // copy image data into DIB data and then into DDB (in a loop)
bba6f3bd
UA
808 unsigned char *data = GetData();
809 int i, j, n;
810 int origin = 0;
811 unsigned char *ptdata = data;
812 unsigned char *ptbits;
c7abc967 813
bba6f3bd
UA
814 for( n=0; n<numDIB; n++ )
815 {
dbda9e86
JS
816 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
817 {
818 // redefine height and size of the (possibly) last smaller DIB
819 // memory is not reallocated
c7abc967 820 height = hRemain;
bba6f3bd
UA
821 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
822 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
dbda9e86 823 }
bba6f3bd 824 ptbits = lpBits;
c7abc967 825
bba6f3bd
UA
826 for( j=0; j<height; j++ )
827 {
828 for( i=0; i<width; i++ )
829 {
830 *(ptbits++) = *(ptdata+2);
831 *(ptbits++) = *(ptdata+1);
832 *(ptbits++) = *(ptdata );
833 ptdata += 3;
dbda9e86
JS
834 }
835 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
bba6f3bd
UA
836 }
837 ::StretchDIBits( memdc, 0, origin, width, height,\
dbda9e86
JS
838 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
839 origin += height;
840 // if numDIB = 1, lines below can also be used
841 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
842 // The above line is equivalent to the following two lines.
843 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
844 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
845 // or the following lines
846 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
847 // HDC memdc = ::CreateCompatibleDC( hdc );
c7abc967 848 // ::SelectObject( memdc, hbitmap);
dbda9e86 849 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
995612e2 850 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
c7abc967
VZ
851 // ::SelectObject( memdc, 0 );
852 // ::DeleteDC( memdc );
e3554471 853 }
bba6f3bd 854 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
c7abc967 855
dbda9e86 856 // similarly, created an mono-bitmap for the possible mask
bba6f3bd
UA
857 if( HasMask() )
858 {
859 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
0bafad0c 860 HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap);
c7abc967 861 if( numDIB == 1 ) height = bmpHeight;
bba6f3bd
UA
862 else height = sizeLimit/bytePerLine;
863 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
864 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
865 origin = 0;
866 unsigned char r = GetMaskRed();
867 unsigned char g = GetMaskGreen();
868 unsigned char b = GetMaskBlue();
869 unsigned char zero = 0, one = 255;
870 ptdata = data;
871 for( n=0; n<numDIB; n++ )
872 {
873 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
874 {
dbda9e86
JS
875 // redefine height and size of the (possibly) last smaller DIB
876 // memory is not reallocated
c7abc967 877 height = hRemain;
bba6f3bd
UA
878 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
879 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
dbda9e86 880 }
bba6f3bd
UA
881 ptbits = lpBits;
882 for( int j=0; j<height; j++ )
883 {
dbda9e86 884 for(i=0; i<width; i++ )
bba6f3bd 885 {
8208e181 886 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
069d0f27
VZ
887 unsigned char cr = (*(ptdata++)) ;
888 unsigned char cg = (*(ptdata++)) ;
889 unsigned char cb = (*(ptdata++)) ;
890
8208e181 891 if( ( cr !=r) || (cg!=g) || (cb!=b) )
bba6f3bd
UA
892 {
893 *(ptbits++) = one;
894 *(ptbits++) = one;
895 *(ptbits++) = one;
896 }
897 else
898 {
899 *(ptbits++) = zero;
900 *(ptbits++) = zero;
901 *(ptbits++) = zero;
902 }
903 }
dbda9e86 904 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
bba6f3bd
UA
905 }
906 ::StretchDIBits( memdc, 0, origin, width, height,\
dbda9e86
JS
907 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
908 origin += height;
909 }
910 // create a wxMask object
bba6f3bd
UA
911 wxMask *mask = new wxMask();
912 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
913 bitmap.SetMask( mask );
dbda9e86
JS
914 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
915 /* The following can also be used but is slow to run
bba6f3bd
UA
916 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
917 wxMask *mask = new wxMask( bitmap, colour );
918 bitmap.SetMask( mask );
dbda9e86 919 */
0bafad0c
VZ
920
921 ::SelectObject( memdc, hbmpOld );
bba6f3bd 922 }
c7abc967
VZ
923
924 // free allocated resources
c7abc967
VZ
925 ::DeleteDC( memdc );
926 ::ReleaseDC(NULL, hdc);
bba6f3bd
UA
927 free(lpDIBh);
928 free(lpBits);
c7abc967 929
6d167489 930#if WXWIN_COMPATIBILITY_2
dbda9e86 931 // check the wxBitmap object
6d167489
VZ
932 bitmap.GetBitmapData()->SetOk();
933#endif // WXWIN_COMPATIBILITY_2
c7abc967 934
bba6f3bd 935 return bitmap;
e3554471
JS
936}
937
e3554471
JS
938wxImage::wxImage( const wxBitmap &bitmap )
939{
dbda9e86 940 // check the bitmap
bba6f3bd
UA
941 if( !bitmap.Ok() )
942 {
223d09f6 943 wxFAIL_MSG( wxT("invalid bitmap") );
bba6f3bd
UA
944 return;
945 }
c7abc967 946
dbda9e86 947 // create an wxImage object
bba6f3bd
UA
948 int width = bitmap.GetWidth();
949 int height = bitmap.GetHeight();
c7abc967 950 Create( width, height );
bba6f3bd
UA
951 unsigned char *data = GetData();
952 if( !data )
953 {
223d09f6 954 wxFAIL_MSG( wxT("could not allocate data for image") );
bba6f3bd
UA
955 return;
956 }
c7abc967 957
dbda9e86 958 // calc the number of bytes per scanline and padding in the DIB
bba6f3bd
UA
959 int bytePerLine = width*3;
960 int sizeDWORD = sizeof( DWORD );
bae41ce1 961 int lineBoundary = bytePerLine % sizeDWORD;
bba6f3bd 962 int padding = 0;
bae41ce1 963 if( lineBoundary > 0 )
bba6f3bd 964 {
bae41ce1 965 padding = sizeDWORD - lineBoundary;
bba6f3bd
UA
966 bytePerLine += padding;
967 }
c7abc967 968
dbda9e86 969 // create a DIB header
bba6f3bd 970 int headersize = sizeof(BITMAPINFOHEADER);
8f177c8e 971 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
bba6f3bd
UA
972 if( !lpDIBh )
973 {
223d09f6 974 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
bba6f3bd
UA
975 free( data );
976 return;
977 }
dbda9e86 978 // Fill in the DIB header
bba6f3bd
UA
979 lpDIBh->bmiHeader.biSize = headersize;
980 lpDIBh->bmiHeader.biWidth = width;
981 lpDIBh->bmiHeader.biHeight = -height;
982 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
983 lpDIBh->bmiHeader.biPlanes = 1;
984 lpDIBh->bmiHeader.biBitCount = 24;
985 lpDIBh->bmiHeader.biCompression = BI_RGB;
986 lpDIBh->bmiHeader.biClrUsed = 0;
dbda9e86 987 // These seem not really needed for our purpose here.
bba6f3bd
UA
988 lpDIBh->bmiHeader.biClrImportant = 0;
989 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
990 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
dbda9e86 991 // memory for DIB data
bba6f3bd
UA
992 unsigned char *lpBits;
993 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
994 if( !lpBits )
e3554471 995 {
223d09f6 996 wxFAIL_MSG( wxT("could not allocate data for DIB") );
bba6f3bd
UA
997 free( data );
998 free( lpDIBh );
999 return;
4698648f 1000 }
c7abc967 1001
dbda9e86 1002 // copy data from the device-dependent bitmap to the DIB
bba6f3bd
UA
1003 HDC hdc = ::GetDC(NULL);
1004 HBITMAP hbitmap;
1005 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1006 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
c7abc967 1007
dbda9e86 1008 // copy DIB data into the wxImage object
bba6f3bd
UA
1009 int i, j;
1010 unsigned char *ptdata = data;
1011 unsigned char *ptbits = lpBits;
1012 for( i=0; i<height; i++ )
1013 {
1014 for( j=0; j<width; j++ )
1015 {
1016 *(ptdata++) = *(ptbits+2);
1017 *(ptdata++) = *(ptbits+1);
1018 *(ptdata++) = *(ptbits );
1019 ptbits += 3;
dbda9e86 1020 }
bba6f3bd 1021 ptbits += padding;
c7abc967
VZ
1022 }
1023
dbda9e86 1024 // similarly, set data according to the possible mask bitmap
bba6f3bd
UA
1025 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1026 {
1027 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
dbda9e86 1028 // memory DC created, color set, data copied, and memory DC deleted
bba6f3bd
UA
1029 HDC memdc = ::CreateCompatibleDC( hdc );
1030 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1031 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1032 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
c7abc967 1033 ::DeleteDC( memdc );
dbda9e86 1034 // background color set to RGB(16,16,16) in consistent with wxGTK
c7abc967 1035 unsigned char r=16, g=16, b=16;
bba6f3bd
UA
1036 ptdata = data;
1037 ptbits = lpBits;
1038 for( i=0; i<height; i++ )
1039 {
1040 for( j=0; j<width; j++ )
1041 {
1042 if( *ptbits != 0 )
dbda9e86
JS
1043 ptdata += 3;
1044 else
bba6f3bd
UA
1045 {
1046 *(ptdata++) = r;
1047 *(ptdata++) = g;
1048 *(ptdata++) = b;
dbda9e86 1049 }
bba6f3bd
UA
1050 ptbits += 3;
1051 }
1052 ptbits += padding;
c7abc967 1053 }
bba6f3bd
UA
1054 SetMaskColour( r, g, b );
1055 SetMask( TRUE );
c7abc967 1056 }
bba6f3bd
UA
1057 else
1058 {
1059 SetMask( FALSE );
c7abc967
VZ
1060 }
1061 // free allocated resources
1062 ::ReleaseDC(NULL, hdc);
bba6f3bd
UA
1063 free(lpDIBh);
1064 free(lpBits);
e3554471
JS
1065}
1066
1067#endif
1068
7c74e7fe
SC
1069#ifdef __WXMAC__
1070
1071#include <PictUtils.h>
1072
1073extern CTabHandle wxMacCreateColorTable( int numColors ) ;
1074extern void wxMacDestroyColorTable( CTabHandle colors ) ;
1075extern void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) ;
1076extern GWorldPtr wxMacCreateGWorld( int height , int width , int depth ) ;
1077extern void wxMacDestroyGWorld( GWorldPtr gw ) ;
1078
1079wxBitmap wxImage::ConvertToBitmap() const
1080{
1081 // width and height of the device-dependent bitmap
1082 int width = GetWidth();
1083 int height = GetHeight();
1084
1085 // Create picture
97fdfcc9 1086
7c74e7fe 1087 wxBitmap bitmap( width , height , wxDisplayDepth() ) ;
97fdfcc9 1088
7c74e7fe 1089 // Create mask
97fdfcc9 1090
7c74e7fe
SC
1091 if (HasMask())
1092 {
069d0f27 1093 /*
7c74e7fe 1094 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
97fdfcc9 1095
7c74e7fe 1096 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
97fdfcc9 1097
7c74e7fe
SC
1098 wxMask *mask = new wxMask();
1099 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
97fdfcc9 1100
7c74e7fe
SC
1101 bitmap.SetMask( mask );
1102 */
1103 }
97fdfcc9 1104
7c74e7fe 1105 // Render
97fdfcc9 1106
7c74e7fe
SC
1107 int r_mask = GetMaskRed();
1108 int g_mask = GetMaskGreen();
1109 int b_mask = GetMaskBlue();
97fdfcc9 1110
069d0f27
VZ
1111 CGrafPtr origPort ;
1112 GDHandle origDevice ;
1113
1114 GetGWorld( &origPort , &origDevice ) ;
1115 SetGWorld( bitmap.GetHBITMAP() , NULL ) ;
7c74e7fe
SC
1116
1117 register unsigned char* data = GetData();
97fdfcc9 1118
7c74e7fe
SC
1119 int index = 0;
1120 for (int y = 0; y < height; y++)
1121 {
7c74e7fe
SC
1122 for (int x = 0; x < width; x++)
1123 {
069d0f27
VZ
1124 unsigned char r = data[index++];
1125 unsigned char g = data[index++];
1126 unsigned char b = data[index++];
1127 RGBColor color ;
1128 color.red = ( r << 8 ) + r ;
1129 color.green = ( g << 8 ) + g ;
1130 color.blue = ( b << 8 ) + b ;
1131 SetCPixel( x , y , &color ) ;
1132 }
7c74e7fe
SC
1133 } // for height
1134
069d0f27 1135 SetGWorld( origPort , origDevice ) ;
97fdfcc9 1136
8208e181
SC
1137 if ( HasMask() )
1138 {
1139 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1140 wxMask *mask = new wxMask( bitmap, colour );
1141 bitmap.SetMask( mask );
1142 }
7c74e7fe 1143 return bitmap;
97fdfcc9 1144
7c74e7fe
SC
1145}
1146
1147wxImage::wxImage( const wxBitmap &bitmap )
1148{
1149 // check the bitmap
1150 if( !bitmap.Ok() )
1151 {
1152 wxFAIL_MSG( "invalid bitmap" );
1153 return;
1154 }
97fdfcc9 1155
7c74e7fe
SC
1156 // create an wxImage object
1157 int width = bitmap.GetWidth();
1158 int height = bitmap.GetHeight();
97fdfcc9 1159 Create( width, height );
7c74e7fe
SC
1160 /*
1161 unsigned char *data = GetData();
1162 if( !data )
1163 {
1164 wxFAIL_MSG( "could not allocate data for image" );
1165 return;
1166 }
97fdfcc9 1167
7c74e7fe
SC
1168 // calc the number of bytes per scanline and padding in the DIB
1169 int bytePerLine = width*3;
1170 int sizeDWORD = sizeof( DWORD );
1171 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1172 int padding = 0;
97fdfcc9 1173 if( lineBoundary.rem > 0 )
7c74e7fe
SC
1174 {
1175 padding = sizeDWORD - lineBoundary.rem;
1176 bytePerLine += padding;
1177 }
97fdfcc9 1178
7c74e7fe
SC
1179 // create a DIB header
1180 int headersize = sizeof(BITMAPINFOHEADER);
1181 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1182 if( !lpDIBh )
1183 {
1184 wxFAIL_MSG( "could not allocate data for DIB header" );
1185 free( data );
1186 return;
1187 }
1188 // Fill in the DIB header
1189 lpDIBh->bmiHeader.biSize = headersize;
1190 lpDIBh->bmiHeader.biWidth = width;
1191 lpDIBh->bmiHeader.biHeight = -height;
1192 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1193 lpDIBh->bmiHeader.biPlanes = 1;
1194 lpDIBh->bmiHeader.biBitCount = 24;
1195 lpDIBh->bmiHeader.biCompression = BI_RGB;
1196 lpDIBh->bmiHeader.biClrUsed = 0;
1197 // These seem not really needed for our purpose here.
1198 lpDIBh->bmiHeader.biClrImportant = 0;
1199 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1200 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1201 // memory for DIB data
1202 unsigned char *lpBits;
1203 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1204 if( !lpBits )
1205 {
1206 wxFAIL_MSG( "could not allocate data for DIB" );
1207 free( data );
1208 free( lpDIBh );
1209 return;
1210 }
97fdfcc9 1211
7c74e7fe
SC
1212 // copy data from the device-dependent bitmap to the DIB
1213 HDC hdc = ::GetDC(NULL);
1214 HBITMAP hbitmap;
1215 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1216 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
97fdfcc9 1217
7c74e7fe
SC
1218 // copy DIB data into the wxImage object
1219 int i, j;
1220 unsigned char *ptdata = data;
1221 unsigned char *ptbits = lpBits;
1222 for( i=0; i<height; i++ )
1223 {
1224 for( j=0; j<width; j++ )
1225 {
1226 *(ptdata++) = *(ptbits+2);
1227 *(ptdata++) = *(ptbits+1);
1228 *(ptdata++) = *(ptbits );
1229 ptbits += 3;
1230 }
1231 ptbits += padding;
069d0f27 1232 }
97fdfcc9 1233
7c74e7fe
SC
1234 // similarly, set data according to the possible mask bitmap
1235 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1236 {
1237 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1238 // memory DC created, color set, data copied, and memory DC deleted
1239 HDC memdc = ::CreateCompatibleDC( hdc );
1240 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1241 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1242 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
97fdfcc9 1243 ::DeleteDC( memdc );
7c74e7fe 1244 // background color set to RGB(16,16,16) in consistent with wxGTK
97fdfcc9 1245 unsigned char r=16, g=16, b=16;
7c74e7fe
SC
1246 ptdata = data;
1247 ptbits = lpBits;
1248 for( i=0; i<height; i++ )
1249 {
1250 for( j=0; j<width; j++ )
1251 {
1252 if( *ptbits != 0 )
1253 ptdata += 3;
1254 else
1255 {
1256 *(ptdata++) = r;
1257 *(ptdata++) = g;
1258 *(ptdata++) = b;
1259 }
1260 ptbits += 3;
1261 }
1262 ptbits += padding;
97fdfcc9 1263 }
7c74e7fe
SC
1264 SetMaskColour( r, g, b );
1265 SetMask( TRUE );
8f177c8e 1266 }
7c74e7fe
SC
1267 else
1268 {
1269 SetMask( FALSE );
8f177c8e 1270 }
97fdfcc9
DW
1271 // free allocated resources
1272 ::ReleaseDC(NULL, hdc);
7c74e7fe
SC
1273 free(lpDIBh);
1274 free(lpBits);
1275 */
1276}
1277
1278#endif
1279
ce4169a4
RR
1280//-----------------------------------------------------------------------------
1281// GTK conversion routines
1282//-----------------------------------------------------------------------------
1283
99c67c77
RR
1284#ifdef __WXGTK__
1285
20e05ffb
RR
1286#include <gtk/gtk.h>
1287#include <gdk/gdk.h>
1288#include <gdk/gdkx.h>
83624f79 1289
ba0730de 1290#if (GTK_MINOR_VERSION > 0)
20e05ffb 1291#include <gdk/gdkrgb.h>
ba0730de
RR
1292#endif
1293
d76fe38b
RR
1294extern GtkWidget *wxRootWindow;
1295
82ea63e6
RR
1296wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue )
1297{
1298 wxBitmap bitmap;
1299
1300 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1301
1302 int width = GetWidth();
1303 int height = GetHeight();
1304
1305 bitmap.SetHeight( height );
1306 bitmap.SetWidth( width );
1307
d76fe38b 1308 bitmap.SetBitmap( gdk_pixmap_new( wxRootWindow->window, width, height, 1 ) );
82ea63e6
RR
1309
1310 bitmap.SetDepth( 1 );
1311
103aab26
RR
1312 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1313 wxASSERT( visual );
1314
82ea63e6
RR
1315 // Create picture image
1316
1317 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1318
1319 GdkImage *data_image =
103aab26 1320 gdk_image_new_bitmap( visual, data_data, width, height );
82ea63e6
RR
1321
1322 // Create mask image
1323
1324 GdkImage *mask_image = (GdkImage*) NULL;
1325
1326 if (HasMask())
1327 {
1328 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1329
103aab26 1330 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
82ea63e6
RR
1331
1332 wxMask *mask = new wxMask();
d76fe38b 1333 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
82ea63e6
RR
1334
1335 bitmap.SetMask( mask );
1336 }
1337
1338 int r_mask = GetMaskRed();
1339 int g_mask = GetMaskGreen();
1340 int b_mask = GetMaskBlue();
1341
1342 unsigned char* data = GetData();
1343
1344 int index = 0;
1345 for (int y = 0; y < height; y++)
1346 {
1347 for (int x = 0; x < width; x++)
1348 {
1349 int r = data[index];
1350 index++;
1351 int g = data[index];
1352 index++;
1353 int b = data[index];
1354 index++;
1355
1356 if (HasMask())
1357 {
1358 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1359 gdk_image_put_pixel( mask_image, x, y, 1 );
1360 else
1361 gdk_image_put_pixel( mask_image, x, y, 0 );
1362 }
1363
1364 if ((r == red) && (b == blue) && (g == green))
1365 gdk_image_put_pixel( data_image, x, y, 1 );
1366 else
1367 gdk_image_put_pixel( data_image, x, y, 0 );
1368
1369 } // for
1370 } // for
1371
1372 // Blit picture
1373
1374 GdkGC *data_gc = gdk_gc_new( bitmap.GetBitmap() );
1375
1376 gdk_draw_image( bitmap.GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1377
1378 gdk_image_destroy( data_image );
1379 gdk_gc_unref( data_gc );
1380
1381 // Blit mask
1382
1383 if (HasMask())
1384 {
1385 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1386
1387 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1388
1389 gdk_image_destroy( mask_image );
1390 gdk_gc_unref( mask_gc );
1391 }
1392
1393 return bitmap;
1394}
1395
1396
99c67c77
RR
1397wxBitmap wxImage::ConvertToBitmap() const
1398{
1399 wxBitmap bitmap;
c7abc967 1400
223d09f6 1401 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
c7abc967 1402
99c67c77
RR
1403 int width = GetWidth();
1404 int height = GetHeight();
c7abc967 1405
99c67c77
RR
1406 bitmap.SetHeight( height );
1407 bitmap.SetWidth( width );
c7abc967 1408
d76fe38b 1409 bitmap.SetPixmap( gdk_pixmap_new( wxRootWindow->window, width, height, -1 ) );
ba0730de 1410
103aab26 1411 // Retrieve depth
c7abc967 1412
103aab26
RR
1413 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1414 wxASSERT( visual );
1415
ba0730de 1416 int bpp = visual->depth;
c7abc967 1417
ba0730de 1418 bitmap.SetDepth( bpp );
c7abc967 1419
ba0730de
RR
1420 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1421 if (bpp < 8) bpp = 8;
c7abc967 1422
ba0730de
RR
1423#if (GTK_MINOR_VERSION > 0)
1424
1425 if (!HasMask() && (bpp > 8))
1426 {
1427 static bool s_hasInitialized = FALSE;
c7abc967 1428
995612e2
VZ
1429 if (!s_hasInitialized)
1430 {
1431 gdk_rgb_init();
1432 s_hasInitialized = TRUE;
1433 }
c7abc967 1434
ba0730de 1435 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
c7abc967 1436
995612e2
VZ
1437 gdk_draw_rgb_image( bitmap.GetPixmap(),
1438 gc,
1439 0, 0,
1440 width, height,
1441 GDK_RGB_DITHER_NONE,
1442 GetData(),
1443 width*3 );
c7abc967 1444
ba0730de 1445 gdk_gc_unref( gc );
c7abc967 1446
995612e2 1447 return bitmap;
ba0730de 1448 }
c7abc967 1449
ba0730de 1450#endif
c7abc967 1451
ba0730de 1452 // Create picture image
c7abc967 1453
99c67c77 1454 GdkImage *data_image =
103aab26 1455 gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
c7abc967 1456
ba0730de 1457 // Create mask image
c7abc967 1458
99c67c77 1459 GdkImage *mask_image = (GdkImage*) NULL;
c7abc967 1460
99c67c77
RR
1461 if (HasMask())
1462 {
1463 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
c7abc967 1464
103aab26 1465 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
c7abc967 1466
4698648f 1467 wxMask *mask = new wxMask();
d76fe38b 1468 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
c7abc967 1469
4698648f 1470 bitmap.SetMask( mask );
99c67c77 1471 }
c7abc967 1472
99c67c77 1473 // Render
c7abc967 1474
99c67c77
RR
1475 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1476 byte_order b_o = RGB;
c7abc967 1477
99c67c77
RR
1478 if (bpp >= 24)
1479 {
99c67c77
RR
1480 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1481 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1482 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1483 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1484 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1485 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1486 }
c7abc967 1487
99c67c77
RR
1488 int r_mask = GetMaskRed();
1489 int g_mask = GetMaskGreen();
1490 int b_mask = GetMaskBlue();
c7abc967 1491
99c67c77 1492 unsigned char* data = GetData();
c7abc967 1493
99c67c77
RR
1494 int index = 0;
1495 for (int y = 0; y < height; y++)
1496 {
1497 for (int x = 0; x < width; x++)
1498 {
1499 int r = data[index];
4698648f 1500 index++;
99c67c77 1501 int g = data[index];
4698648f 1502 index++;
99c67c77 1503 int b = data[index];
4698648f 1504 index++;
c7abc967 1505
4698648f
VZ
1506 if (HasMask())
1507 {
1508 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1509 gdk_image_put_pixel( mask_image, x, y, 1 );
1510 else
1511 gdk_image_put_pixel( mask_image, x, y, 0 );
1512 }
c7abc967 1513
4698648f
VZ
1514 switch (bpp)
1515 {
dbda9e86 1516 case 8:
4698648f 1517 {
f6fcbb63 1518 int pixel = -1;
4698648f
VZ
1519 if (wxTheApp->m_colorCube)
1520 {
38274997 1521 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
4698648f 1522 }
f6fcbb63 1523 else
4698648f
VZ
1524 {
1525 GdkColormap *cmap = gtk_widget_get_default_colormap();
f6fcbb63
RR
1526 GdkColor *colors = cmap->colors;
1527 int max = 3 * (65536);
c7abc967 1528
f6fcbb63
RR
1529 for (int i = 0; i < cmap->size; i++)
1530 {
1531 int rdiff = (r << 8) - colors[i].red;
1532 int gdiff = (g << 8) - colors[i].green;
1533 int bdiff = (b << 8) - colors[i].blue;
1534 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1535 if (sum < max) { pixel = i; max = sum; }
4698648f 1536 }
99c67c77 1537 }
c7abc967 1538
4698648f 1539 gdk_image_put_pixel( data_image, x, y, pixel );
c7abc967 1540
4698648f
VZ
1541 break;
1542 }
dbda9e86 1543 case 15:
4698648f
VZ
1544 {
1545 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1546 gdk_image_put_pixel( data_image, x, y, pixel );
1547 break;
1548 }
dbda9e86 1549 case 16:
4698648f
VZ
1550 {
1551 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1552 gdk_image_put_pixel( data_image, x, y, pixel );
1553 break;
1554 }
dbda9e86
JS
1555 case 32:
1556 case 24:
4698648f
VZ
1557 {
1558 guint32 pixel = 0;
1559 switch (b_o)
1560 {
dbda9e86
JS
1561 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1562 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1563 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1564 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1565 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1566 case GBR: pixel = (g << 16) | (b << 8) | r; break;
4698648f
VZ
1567 }
1568 gdk_image_put_pixel( data_image, x, y, pixel );
1569 }
dbda9e86 1570 default: break;
4698648f 1571 }
99c67c77
RR
1572 } // for
1573 } // for
c7abc967 1574
99c67c77 1575 // Blit picture
c7abc967 1576
99c67c77 1577 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
c7abc967 1578
99c67c77 1579 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
c7abc967 1580
99c67c77
RR
1581 gdk_image_destroy( data_image );
1582 gdk_gc_unref( data_gc );
c7abc967 1583
99c67c77 1584 // Blit mask
c7abc967 1585
99c67c77
RR
1586 if (HasMask())
1587 {
1588 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
c7abc967 1589
99c67c77 1590 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
c7abc967 1591
99c67c77
RR
1592 gdk_image_destroy( mask_image );
1593 gdk_gc_unref( mask_gc );
1594 }
c7abc967 1595
99c67c77
RR
1596 return bitmap;
1597}
1598
1599wxImage::wxImage( const wxBitmap &bitmap )
1600{
223d09f6 1601 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
c7abc967 1602
c6d73ef6
RR
1603 GdkImage *gdk_image = (GdkImage*) NULL;
1604 if (bitmap.GetPixmap())
1605 {
1606 gdk_image = gdk_image_get( bitmap.GetPixmap(),
1607 0, 0,
1608 bitmap.GetWidth(), bitmap.GetHeight() );
1609 } else
1610 if (bitmap.GetBitmap())
1611 {
1612 gdk_image = gdk_image_get( bitmap.GetBitmap(),
1613 0, 0,
1614 bitmap.GetWidth(), bitmap.GetHeight() );
1615 } else
1616 {
1617 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1618 }
c7abc967 1619
223d09f6 1620 wxCHECK_RET( gdk_image, wxT("couldn't create image") );
c7abc967 1621
99c67c77
RR
1622 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1623 char unsigned *data = GetData();
c7abc967 1624
99c67c77
RR
1625 if (!data)
1626 {
1627 gdk_image_destroy( gdk_image );
223d09f6 1628 wxFAIL_MSG( wxT("couldn't create image") );
4698648f 1629 return;
99c67c77 1630 }
c7abc967 1631
99c67c77
RR
1632 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1633 if (bitmap.GetMask())
1634 {
1635 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
dbda9e86
JS
1636 0, 0,
1637 bitmap.GetWidth(), bitmap.GetHeight() );
c7abc967 1638
4698648f 1639 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
99c67c77 1640 }
c7abc967 1641
be25e480 1642 int bpp = -1;
cf3da716
RR
1643 int red_shift_right = 0;
1644 int green_shift_right = 0;
1645 int blue_shift_right = 0;
1646 int red_shift_left = 0;
1647 int green_shift_left = 0;
1648 int blue_shift_left = 0;
1649 bool use_shift = FALSE;
1650
c6d73ef6 1651 if (bitmap.GetPixmap())
be25e480
RR
1652 {
1653 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
c6d73ef6 1654
d76fe38b 1655 if (visual == NULL) visual = gdk_window_get_visual( wxRootWindow->window );
be25e480 1656 bpp = visual->depth;
cf3da716
RR
1657 if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1658 red_shift_right = visual->red_shift;
1659 red_shift_left = 8-visual->red_prec;
1660 green_shift_right = visual->green_shift;
1661 green_shift_left = 8-visual->green_prec;
1662 blue_shift_right = visual->blue_shift;
1663 blue_shift_left = 8-visual->blue_prec;
1664
1665 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
be25e480
RR
1666 }
1667 if (bitmap.GetBitmap())
1668 {
1669 bpp = 1;
1670 }
c7abc967 1671
cf3da716 1672
99c67c77 1673 GdkColormap *cmap = gtk_widget_get_default_colormap();
c7abc967 1674
99c67c77
RR
1675 long pos = 0;
1676 for (int j = 0; j < bitmap.GetHeight(); j++)
1677 {
1678 for (int i = 0; i < bitmap.GetWidth(); i++)
1679 {
cf3da716 1680 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
069d0f27
VZ
1681 if (bpp == 1)
1682 {
1683 if (pixel == 0)
1684 {
cf3da716 1685 data[pos] = 0;
be25e480
RR
1686 data[pos+1] = 0;
1687 data[pos+2] = 0;
069d0f27
VZ
1688 }
1689 else
1690 {
cf3da716 1691 data[pos] = 255;
be25e480
RR
1692 data[pos+1] = 255;
1693 data[pos+2] = 255;
069d0f27 1694 }
cf3da716
RR
1695 }
1696 else if (use_shift)
99c67c77 1697 {
cf3da716
RR
1698 data[pos] = (pixel >> red_shift_right) << red_shift_left;
1699 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1700 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
069d0f27 1701 }
cf3da716 1702 else if (cmap->colors)
99c67c77 1703 {
cf3da716
RR
1704 data[pos] = cmap->colors[pixel].red >> 8;
1705 data[pos+1] = cmap->colors[pixel].green >> 8;
1706 data[pos+2] = cmap->colors[pixel].blue >> 8;
1707 }
1708 else
99c67c77 1709 {
cf3da716
RR
1710 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1711 }
c7abc967 1712
4698648f
VZ
1713 if (gdk_image_mask)
1714 {
1715 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1716 if (mask_pixel == 0)
1717 {
99c67c77
RR
1718 data[pos] = 16;
1719 data[pos+1] = 16;
1720 data[pos+2] = 16;
dbda9e86 1721 }
4698648f 1722 }
c7abc967 1723
99c67c77
RR
1724 pos += 3;
1725 }
1726 }
c7abc967 1727
99c67c77
RR
1728 gdk_image_destroy( gdk_image );
1729 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1730}
1731
1732#endif
ee4c6942 1733
ce4169a4
RR
1734//-----------------------------------------------------------------------------
1735// Motif conversion routines
1736//-----------------------------------------------------------------------------
1737
ee4c6942 1738#ifdef __WXMOTIF__
338dd992
JJ
1739#ifdef __VMS__
1740#pragma message disable nosimpint
1741#endif
b75867a6 1742#include <Xm/Xm.h>
338dd992
JJ
1743#ifdef __VMS__
1744#pragma message enable nosimpint
1745#endif
b75867a6 1746#include "wx/utils.h"
38274997 1747#include <math.h>
b75867a6 1748
88195b2b
JS
1749/*
1750
1751Date: Wed, 05 Jan 2000 11:45:40 +0100
1752From: Frits Boel <boel@niob.knaw.nl>
1753To: julian.smart@ukonline.co.uk
1754Subject: Patch for Motif ConvertToBitmap
1755
1756Hi Julian,
1757
1758I've been working on a wxWin application for image processing. From the
1759beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1760till I looked in the source code of image.cpp. I saw that converting a
1761wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1762to the 256 colors of the palet. A very time-consuming piece of code!
1763
1764Because I wanted a faster application, I've made a 'patch' for this. In
1765short: every pixel of the image is compared to a sorted list with
1766colors. If the color is found in the list, the palette entry is
1767returned; if the color is not found, the color palette is searched and
1768then the palette entry is returned and the color added to the sorted
1769list.
1770
1771Maybe there is another method for this, namely changing the palette
1772itself (if the colors are known, as is the case with tiffs with a
1773colormap). I did not look at this, maybe someone else did?
1774
1775The code of the patch is attached, have a look on it, and maybe you will
1776ship it with the next release of wxMotif?
1777
1778Regards,
1779
1780Frits Boel
1781Software engineer at Hubrecht Laboratory, The Netherlands.
1782
1783*/
1784
1785class wxSearchColor
1786{
1787public:
1788 wxSearchColor( void );
1789 wxSearchColor( int size, XColor *colors );
1790 ~wxSearchColor( void );
1791
1792 int SearchColor( int r, int g, int b );
1793private:
1794 int AddColor( unsigned int value, int pos );
1795
1796 int size;
1797 XColor *colors;
1798 unsigned int *color;
1799 int *entry;
1800
1801 int bottom;
1802 int top;
1803};
1804
1805wxSearchColor::wxSearchColor( void )
1806{
069d0f27
VZ
1807 size = 0;
1808 colors = (XColor*) NULL;
1809 color = (unsigned int *) NULL;
1810 entry = (int*) NULL;
88195b2b 1811
069d0f27
VZ
1812 bottom = 0;
1813 top = 0;
88195b2b
JS
1814}
1815
069d0f27 1816wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
88195b2b
JS
1817{
1818 int i;
069d0f27
VZ
1819 size = size_;
1820 colors = colors_;
1821 color = new unsigned int[size];
1822 entry = new int [size];
88195b2b 1823
069d0f27
VZ
1824 for (i = 0; i < size; i++ ) {
1825 entry[i] = -1;
1826 }
88195b2b 1827
069d0f27 1828 bottom = top = ( size >> 1 );
88195b2b
JS
1829}
1830
1831wxSearchColor::~wxSearchColor( void )
1832{
069d0f27
VZ
1833 if ( color ) delete color;
1834 if ( entry ) delete entry;
88195b2b
JS
1835}
1836
1837int wxSearchColor::SearchColor( int r, int g, int b )
1838{
1839 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
069d0f27
VZ
1840 int begin = bottom;
1841 int end = top;
88195b2b
JS
1842 int middle;
1843
1844 while ( begin <= end ) {
1845
1846 middle = ( begin + end ) >> 1;
1847
069d0f27
VZ
1848 if ( value == color[middle] ) {
1849 return( entry[middle] );
1850 } else if ( value < color[middle] ) {
88195b2b
JS
1851 end = middle - 1;
1852 } else {
1853 begin = middle + 1;
1854 }
1855
1856 }
1857
1858 return AddColor( value, middle );
1859}
1860
1861int wxSearchColor::AddColor( unsigned int value, int pos )
1862{
1863 int i;
1864 int pixel = -1;
1865 int max = 3 * (65536);
1866 for ( i = 0; i < 256; i++ ) {
1867 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
1868 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
1869 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
1870 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1871 if (sum < max) { pixel = i; max = sum; }
1872 }
1873
069d0f27
VZ
1874 if ( entry[pos] < 0 ) {
1875 color[pos] = value;
1876 entry[pos] = pixel;
1877 } else if ( value < color[pos] ) {
88195b2b 1878
069d0f27
VZ
1879 if ( bottom > 0 ) {
1880 for ( i = bottom; i < pos; i++ ) {
1881 color[i-1] = color[i];
1882 entry[i-1] = entry[i];
88195b2b 1883 }
069d0f27
VZ
1884 bottom--;
1885 color[pos-1] = value;
1886 entry[pos-1] = pixel;
1887 } else if ( top < size-1 ) {
1888 for ( i = top; i >= pos; i-- ) {
1889 color[i+1] = color[i];
1890 entry[i+1] = entry[i];
88195b2b 1891 }
069d0f27
VZ
1892 top++;
1893 color[pos] = value;
1894 entry[pos] = pixel;
88195b2b
JS
1895 }
1896
1897 } else {
1898
069d0f27
VZ
1899 if ( top < size-1 ) {
1900 for ( i = top; i > pos; i-- ) {
1901 color[i+1] = color[i];
1902 entry[i+1] = entry[i];
88195b2b 1903 }
069d0f27
VZ
1904 top++;
1905 color[pos+1] = value;
1906 entry[pos+1] = pixel;
1907 } else if ( bottom > 0 ) {
1908 for ( i = bottom; i < pos; i++ ) {
1909 color[i-1] = color[i];
1910 entry[i-1] = entry[i];
88195b2b 1911 }
069d0f27
VZ
1912 bottom--;
1913 color[pos] = value;
1914 entry[pos] = pixel;
88195b2b
JS
1915 }
1916
1917 }
1918
1919 return( pixel );
1920}
1921
ee4c6942
JS
1922wxBitmap wxImage::ConvertToBitmap() const
1923{
b75867a6 1924 wxBitmap bitmap;
c7abc967 1925
223d09f6 1926 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
a91b47e8 1927
b75867a6
RR
1928 int width = GetWidth();
1929 int height = GetHeight();
c7abc967 1930
b75867a6
RR
1931 bitmap.SetHeight( height );
1932 bitmap.SetWidth( width );
c7abc967 1933
b75867a6
RR
1934 Display *dpy = (Display*) wxGetDisplay();
1935 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1936 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
c7abc967 1937
b75867a6 1938 // Create image
c7abc967 1939
b75867a6 1940 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
a91b47e8 1941 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
c7abc967 1942
b75867a6 1943 bitmap.Create( width, height, bpp );
a91b47e8 1944
dbda9e86 1945 /*
b75867a6 1946 // Create mask
c7abc967 1947
dbda9e86 1948 GdkImage *mask_image = (GdkImage*) NULL;
c7abc967 1949
dbda9e86
JS
1950 if (HasMask())
1951 {
b75867a6 1952 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
c7abc967 1953
dbda9e86 1954 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
c7abc967 1955
dbda9e86
JS
1956 wxMask *mask = new wxMask();
1957 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
c7abc967 1958
dbda9e86
JS
1959 bitmap.SetMask( mask );
1960 }
1961 */
c7abc967 1962
b75867a6 1963 // Retrieve depth info
c7abc967 1964
b75867a6
RR
1965 XVisualInfo vinfo_template;
1966 XVisualInfo *vi;
c7abc967 1967
b75867a6
RR
1968 vinfo_template.visual = vis;
1969 vinfo_template.visualid = XVisualIDFromVisual( vis );
1970 vinfo_template.depth = bpp;
1971 int nitem = 0;
c7abc967 1972
b75867a6 1973 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
c7abc967 1974
223d09f6 1975 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
c7abc967 1976
38274997 1977 XFree( vi );
a91b47e8 1978
b75867a6
RR
1979 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1980 if (bpp < 8) bpp = 8;
c7abc967 1981
b75867a6 1982 // Render
c7abc967 1983
b75867a6
RR
1984 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1985 byte_order b_o = RGB;
c7abc967 1986
b75867a6
RR
1987 if (bpp >= 24)
1988 {
1989 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1990 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1991 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1992 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1993 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1994 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1995 }
c7abc967 1996
dbda9e86 1997 /*
b75867a6
RR
1998 int r_mask = GetMaskRed();
1999 int g_mask = GetMaskGreen();
2000 int b_mask = GetMaskBlue();
dbda9e86 2001 */
c7abc967 2002
38274997
RR
2003 XColor colors[256];
2004 if (bpp == 8)
2005 {
dbda9e86 2006 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
c7abc967 2007
38274997 2008 for (int i = 0; i < 256; i++) colors[i].pixel = i;
dbda9e86 2009 XQueryColors( dpy, cmap, colors, 256 );
38274997 2010 }
c7abc967 2011
88195b2b 2012 wxSearchColor scolor( 256, colors );
b75867a6 2013 unsigned char* data = GetData();
c7abc967 2014
b75867a6
RR
2015 int index = 0;
2016 for (int y = 0; y < height; y++)
2017 {
2018 for (int x = 0; x < width; x++)
2019 {
2020 int r = data[index];
dbda9e86 2021 index++;
b75867a6 2022 int g = data[index];
dbda9e86 2023 index++;
b75867a6 2024 int b = data[index];
dbda9e86 2025 index++;
c7abc967 2026
dbda9e86
JS
2027 /*
2028 if (HasMask())
2029 {
2030 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2031 gdk_image_put_pixel( mask_image, x, y, 1 );
2032 else
2033 gdk_image_put_pixel( mask_image, x, y, 0 );
2034 }
2035 */
c7abc967 2036
dbda9e86
JS
2037 switch (bpp)
2038 {
2039 case 8:
2040 {
88195b2b 2041#if 0 // Old, slower code
b75867a6 2042 int pixel = -1;
dbda9e86
JS
2043 /*
2044 if (wxTheApp->m_colorCube)
2045 {
2046 pixel = wxTheApp->m_colorCube
c7abc967
VZ
2047 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2048 }
b75867a6 2049 else
dbda9e86
JS
2050 {
2051 */
2052 int max = 3 * (65536);
2053 for (int i = 0; i < 256; i++)
2054 {
2055 int rdiff = (r << 8) - colors[i].red;
2056 int gdiff = (g << 8) - colors[i].green;
2057 int bdiff = (b << 8) - colors[i].blue;
2058 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2059 if (sum < max) { pixel = i; max = sum; }
2060 }
2061 /*
2062 }
2063 */
88195b2b
JS
2064#endif
2065
069d0f27
VZ
2066 // And this is all to get the 'right' color...
2067 int pixel = scolor.SearchColor( r, g, b );
dbda9e86
JS
2068 XPutPixel( data_image, x, y, pixel );
2069 break;
2070 }
2071 case 15:
2072 {
2073 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
2074 XPutPixel( data_image, x, y, pixel );
2075 break;
2076 }
2077 case 16:
2078 {
2079 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
2080 XPutPixel( data_image, x, y, pixel );
2081 break;
2082 }
2083 case 32:
2084 case 24:
2085 {
2086 int pixel = 0;
2087 switch (b_o)
2088 {
2089 case RGB: pixel = (r << 16) | (g << 8) | b; break;
2090 case RBG: pixel = (r << 16) | (b << 8) | g; break;
2091 case BRG: pixel = (b << 16) | (r << 8) | g; break;
2092 case BGR: pixel = (b << 16) | (g << 8) | r; break;
2093 case GRB: pixel = (g << 16) | (r << 8) | b; break;
2094 case GBR: pixel = (g << 16) | (b << 8) | r; break;
2095 }
2096 XPutPixel( data_image, x, y, pixel );
2097 }
2098 default: break;
2099 }
b75867a6
RR
2100 } // for
2101 } // for
c7abc967 2102
b75867a6 2103 // Blit picture
c7abc967 2104
b75867a6
RR
2105 XGCValues gcvalues;
2106 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
2107 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
2108 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
c7abc967 2109
b75867a6
RR
2110 XDestroyImage( data_image );
2111 XFreeGC( dpy, gc );
c7abc967 2112
dbda9e86 2113 /*
b75867a6 2114 // Blit mask
c7abc967 2115
dbda9e86
JS
2116 if (HasMask())
2117 {
2118 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
c7abc967 2119
b75867a6 2120 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
c7abc967 2121
dbda9e86
JS
2122 gdk_image_destroy( mask_image );
2123 gdk_gc_unref( mask_gc );
2124 }
2125 */
c7abc967 2126
b75867a6 2127 return bitmap;
ee4c6942
JS
2128}
2129
2130wxImage::wxImage( const wxBitmap &bitmap )
2131{
223d09f6 2132 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
c7abc967 2133
38274997
RR
2134 Display *dpy = (Display*) wxGetDisplay();
2135 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2136 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
c7abc967 2137
38274997 2138 XImage *ximage = XGetImage( dpy,
dbda9e86
JS
2139 (Drawable)bitmap.GetPixmap(),
2140 0, 0,
2141 bitmap.GetWidth(), bitmap.GetHeight(),
2142 AllPlanes, ZPixmap );
c7abc967 2143
223d09f6 2144 wxCHECK_RET( ximage, wxT("couldn't create image") );
c7abc967 2145
38274997
RR
2146 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2147 char unsigned *data = GetData();
c7abc967 2148
38274997
RR
2149 if (!data)
2150 {
2151 XDestroyImage( ximage );
223d09f6 2152 wxFAIL_MSG( wxT("couldn't create image") );
38274997
RR
2153 return;
2154 }
c7abc967 2155
dbda9e86 2156 /*
38274997
RR
2157 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2158 if (bitmap.GetMask())
2159 {
dbda9e86
JS
2160 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2161 0, 0,
2162 bitmap.GetWidth(), bitmap.GetHeight() );
c7abc967 2163
dbda9e86
JS
2164 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2165 }
2166 */
c7abc967 2167
38274997 2168 // Retrieve depth info
c7abc967 2169
38274997
RR
2170 XVisualInfo vinfo_template;
2171 XVisualInfo *vi;
c7abc967 2172
38274997
RR
2173 vinfo_template.visual = vis;
2174 vinfo_template.visualid = XVisualIDFromVisual( vis );
2175 vinfo_template.depth = bpp;
2176 int nitem = 0;
c7abc967 2177
38274997 2178 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
c7abc967 2179
223d09f6 2180 wxCHECK_RET( vi, wxT("no visual") );
c7abc967 2181
38274997 2182 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
c7abc967 2183
38274997 2184 XFree( vi );
c7abc967 2185
38274997
RR
2186 XColor colors[256];
2187 if (bpp == 8)
2188 {
dbda9e86 2189 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
c7abc967 2190
38274997 2191 for (int i = 0; i < 256; i++) colors[i].pixel = i;
dbda9e86 2192 XQueryColors( dpy, cmap, colors, 256 );
38274997 2193 }
c7abc967 2194
38274997
RR
2195 long pos = 0;
2196 for (int j = 0; j < bitmap.GetHeight(); j++)
2197 {
2198 for (int i = 0; i < bitmap.GetWidth(); i++)
2199 {
dbda9e86 2200 int pixel = XGetPixel( ximage, i, j );
38274997
RR
2201 if (bpp <= 8)
2202 {
2203 data[pos] = colors[pixel].red >> 8;
2204 data[pos+1] = colors[pixel].green >> 8;
2205 data[pos+2] = colors[pixel].blue >> 8;
2206 } else if (bpp == 15)
2207 {
2208 data[pos] = (pixel >> 7) & 0xf8;
2209 data[pos+1] = (pixel >> 2) & 0xf8;
2210 data[pos+2] = (pixel << 3) & 0xf8;
2211 } else if (bpp == 16)
2212 {
2213 data[pos] = (pixel >> 8) & 0xf8;
2214 data[pos+1] = (pixel >> 3) & 0xfc;
2215 data[pos+2] = (pixel << 3) & 0xf8;
2216 } else
2217 {
2218 data[pos] = (pixel >> 16) & 0xff;
2219 data[pos+1] = (pixel >> 8) & 0xff;
2220 data[pos+2] = pixel & 0xff;
2221 }
c7abc967 2222
dbda9e86 2223 /*
38274997
RR
2224 if (gdk_image_mask)
2225 {
dbda9e86
JS
2226 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2227 if (mask_pixel == 0)
2228 {
2229 data[pos] = 16;
2230 data[pos+1] = 16;
2231 data[pos+2] = 16;
38274997 2232 }
dbda9e86
JS
2233 }
2234 */
c7abc967 2235
38274997
RR
2236 pos += 3;
2237 }
2238 }
c7abc967 2239
38274997 2240 XDestroyImage( ximage );
dbda9e86 2241 /*
38274997 2242 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
dbda9e86 2243 */
ee4c6942
JS
2244}
2245#endif
a91b47e8 2246
004fd0c8
DW
2247#ifdef __WXPM__
2248// OS/2 Presentation manager conversion routings
2249
2250wxBitmap wxImage::ConvertToBitmap() const
2251{
2252 if ( !Ok() )
2253 return wxNullBitmap;
2254 wxBitmap bitmap; // remove
2255// TODO:
2256/*
2257 int sizeLimit = 1024*768*3;
2258
2259 // width and height of the device-dependent bitmap
2260 int width = GetWidth();
2261 int bmpHeight = GetHeight();
2262
2263 // calc the number of bytes per scanline and padding
2264 int bytePerLine = width*3;
2265 int sizeDWORD = sizeof( DWORD );
2266 int lineBoundary = bytePerLine % sizeDWORD;
2267 int padding = 0;
2268 if( lineBoundary > 0 )
2269 {
2270 padding = sizeDWORD - lineBoundary;
2271 bytePerLine += padding;
2272 }
2273 // calc the number of DIBs and heights of DIBs
2274 int numDIB = 1;
2275 int hRemain = 0;
2276 int height = sizeLimit/bytePerLine;
2277 if( height >= bmpHeight )
2278 height = bmpHeight;
2279 else
2280 {
2281 numDIB = bmpHeight / height;
2282 hRemain = bmpHeight % height;
2283 if( hRemain >0 ) numDIB++;
2284 }
2285
2286 // set bitmap parameters
2287 wxBitmap bitmap;
2288 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2289 bitmap.SetWidth( width );
2290 bitmap.SetHeight( bmpHeight );
2291 bitmap.SetDepth( wxDisplayDepth() );
2292
2293 // create a DIB header
2294 int headersize = sizeof(BITMAPINFOHEADER);
2295 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2296 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2297 // Fill in the DIB header
2298 lpDIBh->bmiHeader.biSize = headersize;
2299 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2300 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2301 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2302 // the general formula for biSizeImage:
2303 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2304 lpDIBh->bmiHeader.biPlanes = 1;
2305 lpDIBh->bmiHeader.biBitCount = 24;
2306 lpDIBh->bmiHeader.biCompression = BI_RGB;
2307 lpDIBh->bmiHeader.biClrUsed = 0;
2308 // These seem not really needed for our purpose here.
2309 lpDIBh->bmiHeader.biClrImportant = 0;
2310 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2311 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2312 // memory for DIB data
2313 unsigned char *lpBits;
2314 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2315 if( !lpBits )
2316 {
2317 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2318 free( lpDIBh );
2319 return bitmap;
2320 }
2321
2322 // create and set the device-dependent bitmap
2323 HDC hdc = ::GetDC(NULL);
2324 HDC memdc = ::CreateCompatibleDC( hdc );
2325 HBITMAP hbitmap;
2326 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2327 ::SelectObject( memdc, hbitmap);
2328
2329 // copy image data into DIB data and then into DDB (in a loop)
2330 unsigned char *data = GetData();
2331 int i, j, n;
2332 int origin = 0;
2333 unsigned char *ptdata = data;
2334 unsigned char *ptbits;
2335
2336 for( n=0; n<numDIB; n++ )
2337 {
2338 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2339 {
2340 // redefine height and size of the (possibly) last smaller DIB
2341 // memory is not reallocated
2342 height = hRemain;
2343 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2344 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2345 }
2346 ptbits = lpBits;
2347
2348 for( j=0; j<height; j++ )
2349 {
2350 for( i=0; i<width; i++ )
2351 {
2352 *(ptbits++) = *(ptdata+2);
2353 *(ptbits++) = *(ptdata+1);
2354 *(ptbits++) = *(ptdata );
2355 ptdata += 3;
2356 }
2357 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2358 }
2359 ::StretchDIBits( memdc, 0, origin, width, height,\
2360 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2361 origin += height;
2362 // if numDIB = 1, lines below can also be used
2363 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2364 // The above line is equivalent to the following two lines.
2365 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2366 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2367 // or the following lines
2368 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2369 // HDC memdc = ::CreateCompatibleDC( hdc );
2370 // ::SelectObject( memdc, hbitmap);
2371 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2372 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2373 // ::SelectObject( memdc, 0 );
2374 // ::DeleteDC( memdc );
2375 }
2376 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2377
2378 // similarly, created an mono-bitmap for the possible mask
2379 if( HasMask() )
2380 {
2381 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2382 ::SelectObject( memdc, hbitmap);
2383 if( numDIB == 1 ) height = bmpHeight;
2384 else height = sizeLimit/bytePerLine;
2385 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2386 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2387 origin = 0;
2388 unsigned char r = GetMaskRed();
2389 unsigned char g = GetMaskGreen();
2390 unsigned char b = GetMaskBlue();
2391 unsigned char zero = 0, one = 255;
2392 ptdata = data;
2393 for( n=0; n<numDIB; n++ )
2394 {
2395 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2396 {
2397 // redefine height and size of the (possibly) last smaller DIB
2398 // memory is not reallocated
2399 height = hRemain;
2400 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2401 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2402 }
2403 ptbits = lpBits;
2404 for( int j=0; j<height; j++ )
2405 {
2406 for(i=0; i<width; i++ )
2407 {
2408 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2409 {
2410 *(ptbits++) = one;
2411 *(ptbits++) = one;
2412 *(ptbits++) = one;
2413 }
2414 else
2415 {
2416 *(ptbits++) = zero;
2417 *(ptbits++) = zero;
2418 *(ptbits++) = zero;
2419 }
2420 }
2421 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2422 }
2423 ::StretchDIBits( memdc, 0, origin, width, height,\
2424 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2425 origin += height;
2426 }
2427 // create a wxMask object
2428 wxMask *mask = new wxMask();
2429 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2430 bitmap.SetMask( mask );
2431 }
2432
2433 // free allocated resources
2434 ::SelectObject( memdc, 0 );
2435 ::DeleteDC( memdc );
2436 ::ReleaseDC(NULL, hdc);
2437 free(lpDIBh);
2438 free(lpBits);
2439
2440 // check the wxBitmap object
2441 if( bitmap.GetHBITMAP() )
2442 bitmap.SetOk( TRUE );
2443 else
2444 bitmap.SetOk( FALSE );
2445*/
2446 return bitmap;
2447}
2448
2449wxImage::wxImage( const wxBitmap &bitmap )
2450{
2451 // check the bitmap
2452 if( !bitmap.Ok() )
2453 {
2454 wxFAIL_MSG( wxT("invalid bitmap") );
2455 return;
2456 }
2457
2458 // create an wxImage object
2459 int width = bitmap.GetWidth();
2460 int height = bitmap.GetHeight();
2461 Create( width, height );
2462 unsigned char *data = GetData();
2463 if( !data )
2464 {
2465 wxFAIL_MSG( wxT("could not allocate data for image") );
2466 return;
2467 }
2468
2469 // calc the number of bytes per scanline and padding in the DIB
2470 int bytePerLine = width*3;
2471 int sizeDWORD = sizeof( DWORD );
2472 int lineBoundary = bytePerLine % sizeDWORD;
2473 int padding = 0;
2474 if( lineBoundary > 0 )
2475 {
2476 padding = sizeDWORD - lineBoundary;
2477 bytePerLine += padding;
2478 }
2479// TODO:
2480/*
2481 // create a DIB header
2482 int headersize = sizeof(BITMAPINFOHEADER);
2483 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2484 if( !lpDIBh )
2485 {
2486 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2487 free( data );
2488 return;
2489 }
2490 // Fill in the DIB header
2491 lpDIBh->bmiHeader.biSize = headersize;
2492 lpDIBh->bmiHeader.biWidth = width;
2493 lpDIBh->bmiHeader.biHeight = -height;
2494 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2495 lpDIBh->bmiHeader.biPlanes = 1;
2496 lpDIBh->bmiHeader.biBitCount = 24;
2497 lpDIBh->bmiHeader.biCompression = BI_RGB;
2498 lpDIBh->bmiHeader.biClrUsed = 0;
2499 // These seem not really needed for our purpose here.
2500 lpDIBh->bmiHeader.biClrImportant = 0;
2501 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2502 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2503 // memory for DIB data
2504 unsigned char *lpBits;
2505 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2506 if( !lpBits )
2507 {
2508 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2509 free( data );
2510 free( lpDIBh );
2511 return;
2512 }
2513
2514 // copy data from the device-dependent bitmap to the DIB
2515 HDC hdc = ::GetDC(NULL);
2516 HBITMAP hbitmap;
2517 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2518 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2519
2520 // copy DIB data into the wxImage object
2521 int i, j;
2522 unsigned char *ptdata = data;
2523 unsigned char *ptbits = lpBits;
2524 for( i=0; i<height; i++ )
2525 {
2526 for( j=0; j<width; j++ )
2527 {
2528 *(ptdata++) = *(ptbits+2);
2529 *(ptdata++) = *(ptbits+1);
2530 *(ptdata++) = *(ptbits );
2531 ptbits += 3;
2532 }
2533 ptbits += padding;
2534 }
2535
2536 // similarly, set data according to the possible mask bitmap
2537 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2538 {
2539 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2540 // memory DC created, color set, data copied, and memory DC deleted
2541 HDC memdc = ::CreateCompatibleDC( hdc );
2542 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2543 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2544 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2545 ::DeleteDC( memdc );
2546 // background color set to RGB(16,16,16) in consistent with wxGTK
2547 unsigned char r=16, g=16, b=16;
2548 ptdata = data;
2549 ptbits = lpBits;
2550 for( i=0; i<height; i++ )
2551 {
2552 for( j=0; j<width; j++ )
2553 {
2554 if( *ptbits != 0 )
2555 ptdata += 3;
2556 else
2557 {
2558 *(ptdata++) = r;
2559 *(ptdata++) = g;
2560 *(ptdata++) = b;
2561 }
2562 ptbits += 3;
2563 }
2564 ptbits += padding;
2565 }
2566 SetMaskColour( r, g, b );
2567 SetMask( TRUE );
2568 }
2569 else
2570 {
2571 SetMask( FALSE );
2572 }
2573 // free allocated resources
2574 ::ReleaseDC(NULL, hdc);
2575 free(lpDIBh);
2576 free(lpBits);
2577*/
2578}
2579
2580#endif
2581
a91b47e8
JS
2582// A module to allow wxImage initialization/cleanup
2583// without calling these functions from app.cpp or from
2584// the user's application.
2585
2586class wxImageModule: public wxModule
2587{
2588DECLARE_DYNAMIC_CLASS(wxImageModule)
2589public:
2590 wxImageModule() {}
2591 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2592 void OnExit() { wxImage::CleanUpHandlers(); };
2593};
2594
2595IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
c9d01afd
GRG
2596
2597
2598//-----------------------------------------------------------------------------
2599
89d00456
GRG
2600// GRG, Dic/99
2601// Counts and returns the number of different colours. Optionally stops
cc9f7d79
GRG
2602// when it exceeds 'stopafter' different colours. This is useful, for
2603// example, to see if the image can be saved as 8-bit (256 colour or
2604// less, in this case it would be invoked as CountColours(256)). Default
2605// value for stopafter is -1 (don't care).
89d00456 2606//
cc9f7d79 2607unsigned long wxImage::CountColours( unsigned long stopafter )
89d00456
GRG
2608{
2609 wxHashTable h;
2610 wxNode *node;
2611 wxHNode *hnode;
2612 unsigned char r, g, b, *p;
2613 unsigned long size, nentries, key;
2614
2615 p = GetData();
2616 size = GetWidth() * GetHeight();
2617 nentries = 0;
2618
cc9f7d79 2619 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
89d00456
GRG
2620 {
2621 r = *(p++);
2622 g = *(p++);
2623 b = *(p++);
2624 key = (r << 16) | (g << 8) | b;
2625
2626 hnode = (wxHNode *) h.Get(key);
2627
2628 if (!hnode)
2629 {
2630 h.Put(key, (wxObject *)(new wxHNode));
2631 nentries++;
2632 }
2633 }
2634
2635 // delete all HNodes
2636 h.BeginFind();
2637 while ((node = h.Next()) != NULL)
2638 delete (wxHNode *)node->GetData();
2639
2640 return nentries;
2641}
2642
2643
c9d01afd
GRG
2644// GRG, Dic/99
2645// Computes the histogram of the image and fills a hash table, indexed
2646// with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2647// wxHNode contains an 'index' (useful to build a palette with the image
2648// colours) and a 'value', which is the number of pixels in the image with
2649// that colour.
89d00456 2650//
c9d01afd
GRG
2651unsigned long wxImage::ComputeHistogram( wxHashTable &h )
2652{
2653 unsigned char r, g, b, *p;
2654 unsigned long size, nentries, key;
2655 wxHNode *hnode;
2656
2657 p = GetData();
2658 size = GetWidth() * GetHeight();
2659 nentries = 0;
2660
2661 for (unsigned long j = 0; j < size; j++)
2662 {
2663 r = *(p++);
2664 g = *(p++);
2665 b = *(p++);
2666 key = (r << 16) | (g << 8) | b;
2667
2668 hnode = (wxHNode *) h.Get(key);
2669
2670 if (hnode)
2671 hnode->value++;
2672 else
2673 {
2674 hnode = new wxHNode();
97fdfcc9 2675 hnode->index = nentries++;
c9d01afd
GRG
2676 hnode->value = 1;
2677
2678 h.Put(key, (wxObject *)hnode);
2679 }
2680 }
2681
2682 return nentries;
2683}
2684
2685