]> git.saurik.com Git - wxWidgets.git/blame - src/common/image.cpp
splitter in bin format
[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
1312 // Create picture image
1313
1314 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1315
1316 GdkImage *data_image =
1317 gdk_image_new_bitmap( gdk_visual_get_system(), data_data, width, height );
1318
1319 // Create mask image
1320
1321 GdkImage *mask_image = (GdkImage*) NULL;
1322
1323 if (HasMask())
1324 {
1325 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1326
1327 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1328
1329 wxMask *mask = new wxMask();
d76fe38b 1330 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
82ea63e6
RR
1331
1332 bitmap.SetMask( mask );
1333 }
1334
1335 int r_mask = GetMaskRed();
1336 int g_mask = GetMaskGreen();
1337 int b_mask = GetMaskBlue();
1338
1339 unsigned char* data = GetData();
1340
1341 int index = 0;
1342 for (int y = 0; y < height; y++)
1343 {
1344 for (int x = 0; x < width; x++)
1345 {
1346 int r = data[index];
1347 index++;
1348 int g = data[index];
1349 index++;
1350 int b = data[index];
1351 index++;
1352
1353 if (HasMask())
1354 {
1355 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1356 gdk_image_put_pixel( mask_image, x, y, 1 );
1357 else
1358 gdk_image_put_pixel( mask_image, x, y, 0 );
1359 }
1360
1361 if ((r == red) && (b == blue) && (g == green))
1362 gdk_image_put_pixel( data_image, x, y, 1 );
1363 else
1364 gdk_image_put_pixel( data_image, x, y, 0 );
1365
1366 } // for
1367 } // for
1368
1369 // Blit picture
1370
1371 GdkGC *data_gc = gdk_gc_new( bitmap.GetBitmap() );
1372
1373 gdk_draw_image( bitmap.GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1374
1375 gdk_image_destroy( data_image );
1376 gdk_gc_unref( data_gc );
1377
1378 // Blit mask
1379
1380 if (HasMask())
1381 {
1382 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1383
1384 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1385
1386 gdk_image_destroy( mask_image );
1387 gdk_gc_unref( mask_gc );
1388 }
1389
1390 return bitmap;
1391}
1392
1393
99c67c77
RR
1394wxBitmap wxImage::ConvertToBitmap() const
1395{
1396 wxBitmap bitmap;
c7abc967 1397
223d09f6 1398 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
c7abc967 1399
99c67c77
RR
1400 int width = GetWidth();
1401 int height = GetHeight();
c7abc967 1402
99c67c77
RR
1403 bitmap.SetHeight( height );
1404 bitmap.SetWidth( width );
c7abc967 1405
d76fe38b 1406 bitmap.SetPixmap( gdk_pixmap_new( wxRootWindow->window, width, height, -1 ) );
ba0730de
RR
1407
1408 // Retrieve depth
c7abc967 1409
ba0730de 1410 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
b134516c 1411 if (visual == NULL) visual = gdk_visual_get_system();
ba0730de 1412 int bpp = visual->depth;
c7abc967 1413
ba0730de 1414 bitmap.SetDepth( bpp );
c7abc967 1415
ba0730de
RR
1416 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1417 if (bpp < 8) bpp = 8;
c7abc967 1418
ba0730de
RR
1419#if (GTK_MINOR_VERSION > 0)
1420
1421 if (!HasMask() && (bpp > 8))
1422 {
1423 static bool s_hasInitialized = FALSE;
c7abc967 1424
995612e2
VZ
1425 if (!s_hasInitialized)
1426 {
1427 gdk_rgb_init();
1428 s_hasInitialized = TRUE;
1429 }
c7abc967 1430
ba0730de 1431 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
c7abc967 1432
995612e2
VZ
1433 gdk_draw_rgb_image( bitmap.GetPixmap(),
1434 gc,
1435 0, 0,
1436 width, height,
1437 GDK_RGB_DITHER_NONE,
1438 GetData(),
1439 width*3 );
c7abc967 1440
ba0730de 1441 gdk_gc_unref( gc );
c7abc967 1442
995612e2 1443 return bitmap;
ba0730de 1444 }
c7abc967 1445
ba0730de 1446#endif
c7abc967 1447
ba0730de 1448 // Create picture image
c7abc967 1449
99c67c77 1450 GdkImage *data_image =
b134516c 1451 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
c7abc967 1452
ba0730de 1453 // Create mask image
c7abc967 1454
99c67c77 1455 GdkImage *mask_image = (GdkImage*) NULL;
c7abc967 1456
99c67c77
RR
1457 if (HasMask())
1458 {
1459 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
c7abc967 1460
b134516c 1461 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
c7abc967 1462
4698648f 1463 wxMask *mask = new wxMask();
d76fe38b 1464 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
c7abc967 1465
4698648f 1466 bitmap.SetMask( mask );
99c67c77 1467 }
c7abc967 1468
99c67c77 1469 // Render
c7abc967 1470
99c67c77
RR
1471 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1472 byte_order b_o = RGB;
c7abc967 1473
99c67c77
RR
1474 if (bpp >= 24)
1475 {
b134516c 1476 GdkVisual *visual = gdk_visual_get_system();
99c67c77
RR
1477 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1478 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1479 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1480 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1481 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1482 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1483 }
c7abc967 1484
99c67c77
RR
1485 int r_mask = GetMaskRed();
1486 int g_mask = GetMaskGreen();
1487 int b_mask = GetMaskBlue();
c7abc967 1488
99c67c77 1489 unsigned char* data = GetData();
c7abc967 1490
99c67c77
RR
1491 int index = 0;
1492 for (int y = 0; y < height; y++)
1493 {
1494 for (int x = 0; x < width; x++)
1495 {
1496 int r = data[index];
4698648f 1497 index++;
99c67c77 1498 int g = data[index];
4698648f 1499 index++;
99c67c77 1500 int b = data[index];
4698648f 1501 index++;
c7abc967 1502
4698648f
VZ
1503 if (HasMask())
1504 {
1505 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1506 gdk_image_put_pixel( mask_image, x, y, 1 );
1507 else
1508 gdk_image_put_pixel( mask_image, x, y, 0 );
1509 }
c7abc967 1510
4698648f
VZ
1511 switch (bpp)
1512 {
dbda9e86 1513 case 8:
4698648f 1514 {
f6fcbb63 1515 int pixel = -1;
4698648f
VZ
1516 if (wxTheApp->m_colorCube)
1517 {
38274997 1518 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
4698648f 1519 }
f6fcbb63 1520 else
4698648f
VZ
1521 {
1522 GdkColormap *cmap = gtk_widget_get_default_colormap();
f6fcbb63
RR
1523 GdkColor *colors = cmap->colors;
1524 int max = 3 * (65536);
c7abc967 1525
f6fcbb63
RR
1526 for (int i = 0; i < cmap->size; i++)
1527 {
1528 int rdiff = (r << 8) - colors[i].red;
1529 int gdiff = (g << 8) - colors[i].green;
1530 int bdiff = (b << 8) - colors[i].blue;
1531 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1532 if (sum < max) { pixel = i; max = sum; }
4698648f 1533 }
99c67c77 1534 }
c7abc967 1535
4698648f 1536 gdk_image_put_pixel( data_image, x, y, pixel );
c7abc967 1537
4698648f
VZ
1538 break;
1539 }
dbda9e86 1540 case 15:
4698648f
VZ
1541 {
1542 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1543 gdk_image_put_pixel( data_image, x, y, pixel );
1544 break;
1545 }
dbda9e86 1546 case 16:
4698648f
VZ
1547 {
1548 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1549 gdk_image_put_pixel( data_image, x, y, pixel );
1550 break;
1551 }
dbda9e86
JS
1552 case 32:
1553 case 24:
4698648f
VZ
1554 {
1555 guint32 pixel = 0;
1556 switch (b_o)
1557 {
dbda9e86
JS
1558 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1559 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1560 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1561 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1562 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1563 case GBR: pixel = (g << 16) | (b << 8) | r; break;
4698648f
VZ
1564 }
1565 gdk_image_put_pixel( data_image, x, y, pixel );
1566 }
dbda9e86 1567 default: break;
4698648f 1568 }
99c67c77
RR
1569 } // for
1570 } // for
c7abc967 1571
99c67c77 1572 // Blit picture
c7abc967 1573
99c67c77 1574 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
c7abc967 1575
99c67c77 1576 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
c7abc967 1577
99c67c77
RR
1578 gdk_image_destroy( data_image );
1579 gdk_gc_unref( data_gc );
c7abc967 1580
99c67c77 1581 // Blit mask
c7abc967 1582
99c67c77
RR
1583 if (HasMask())
1584 {
1585 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
c7abc967 1586
99c67c77 1587 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
c7abc967 1588
99c67c77
RR
1589 gdk_image_destroy( mask_image );
1590 gdk_gc_unref( mask_gc );
1591 }
c7abc967 1592
99c67c77
RR
1593 return bitmap;
1594}
1595
1596wxImage::wxImage( const wxBitmap &bitmap )
1597{
223d09f6 1598 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
c7abc967 1599
c6d73ef6
RR
1600 GdkImage *gdk_image = (GdkImage*) NULL;
1601 if (bitmap.GetPixmap())
1602 {
1603 gdk_image = gdk_image_get( bitmap.GetPixmap(),
1604 0, 0,
1605 bitmap.GetWidth(), bitmap.GetHeight() );
1606 } else
1607 if (bitmap.GetBitmap())
1608 {
1609 gdk_image = gdk_image_get( bitmap.GetBitmap(),
1610 0, 0,
1611 bitmap.GetWidth(), bitmap.GetHeight() );
1612 } else
1613 {
1614 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1615 }
c7abc967 1616
223d09f6 1617 wxCHECK_RET( gdk_image, wxT("couldn't create image") );
c7abc967 1618
99c67c77
RR
1619 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1620 char unsigned *data = GetData();
c7abc967 1621
99c67c77
RR
1622 if (!data)
1623 {
1624 gdk_image_destroy( gdk_image );
223d09f6 1625 wxFAIL_MSG( wxT("couldn't create image") );
4698648f 1626 return;
99c67c77 1627 }
c7abc967 1628
99c67c77
RR
1629 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1630 if (bitmap.GetMask())
1631 {
1632 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
dbda9e86
JS
1633 0, 0,
1634 bitmap.GetWidth(), bitmap.GetHeight() );
c7abc967 1635
4698648f 1636 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
99c67c77 1637 }
c7abc967 1638
be25e480 1639 int bpp = -1;
cf3da716
RR
1640 int red_shift_right = 0;
1641 int green_shift_right = 0;
1642 int blue_shift_right = 0;
1643 int red_shift_left = 0;
1644 int green_shift_left = 0;
1645 int blue_shift_left = 0;
1646 bool use_shift = FALSE;
1647
c6d73ef6 1648 if (bitmap.GetPixmap())
be25e480
RR
1649 {
1650 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
c6d73ef6 1651
d76fe38b 1652 if (visual == NULL) visual = gdk_window_get_visual( wxRootWindow->window );
be25e480 1653 bpp = visual->depth;
cf3da716
RR
1654 if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1655 red_shift_right = visual->red_shift;
1656 red_shift_left = 8-visual->red_prec;
1657 green_shift_right = visual->green_shift;
1658 green_shift_left = 8-visual->green_prec;
1659 blue_shift_right = visual->blue_shift;
1660 blue_shift_left = 8-visual->blue_prec;
1661
1662 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
be25e480
RR
1663 }
1664 if (bitmap.GetBitmap())
1665 {
1666 bpp = 1;
1667 }
c7abc967 1668
cf3da716 1669
99c67c77 1670 GdkColormap *cmap = gtk_widget_get_default_colormap();
c7abc967 1671
99c67c77
RR
1672 long pos = 0;
1673 for (int j = 0; j < bitmap.GetHeight(); j++)
1674 {
1675 for (int i = 0; i < bitmap.GetWidth(); i++)
1676 {
cf3da716 1677 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
069d0f27
VZ
1678 if (bpp == 1)
1679 {
1680 if (pixel == 0)
1681 {
cf3da716 1682 data[pos] = 0;
be25e480
RR
1683 data[pos+1] = 0;
1684 data[pos+2] = 0;
069d0f27
VZ
1685 }
1686 else
1687 {
cf3da716 1688 data[pos] = 255;
be25e480
RR
1689 data[pos+1] = 255;
1690 data[pos+2] = 255;
069d0f27 1691 }
cf3da716
RR
1692 }
1693 else if (use_shift)
99c67c77 1694 {
cf3da716
RR
1695 data[pos] = (pixel >> red_shift_right) << red_shift_left;
1696 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1697 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
069d0f27 1698 }
cf3da716 1699 else if (cmap->colors)
99c67c77 1700 {
cf3da716
RR
1701 data[pos] = cmap->colors[pixel].red >> 8;
1702 data[pos+1] = cmap->colors[pixel].green >> 8;
1703 data[pos+2] = cmap->colors[pixel].blue >> 8;
1704 }
1705 else
99c67c77 1706 {
cf3da716
RR
1707 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1708 }
c7abc967 1709
4698648f
VZ
1710 if (gdk_image_mask)
1711 {
1712 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1713 if (mask_pixel == 0)
1714 {
99c67c77
RR
1715 data[pos] = 16;
1716 data[pos+1] = 16;
1717 data[pos+2] = 16;
dbda9e86 1718 }
4698648f 1719 }
c7abc967 1720
99c67c77
RR
1721 pos += 3;
1722 }
1723 }
c7abc967 1724
99c67c77
RR
1725 gdk_image_destroy( gdk_image );
1726 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1727}
1728
1729#endif
ee4c6942 1730
ce4169a4
RR
1731//-----------------------------------------------------------------------------
1732// Motif conversion routines
1733//-----------------------------------------------------------------------------
1734
ee4c6942 1735#ifdef __WXMOTIF__
338dd992
JJ
1736#ifdef __VMS__
1737#pragma message disable nosimpint
1738#endif
b75867a6 1739#include <Xm/Xm.h>
338dd992
JJ
1740#ifdef __VMS__
1741#pragma message enable nosimpint
1742#endif
b75867a6 1743#include "wx/utils.h"
38274997 1744#include <math.h>
b75867a6 1745
88195b2b
JS
1746/*
1747
1748Date: Wed, 05 Jan 2000 11:45:40 +0100
1749From: Frits Boel <boel@niob.knaw.nl>
1750To: julian.smart@ukonline.co.uk
1751Subject: Patch for Motif ConvertToBitmap
1752
1753Hi Julian,
1754
1755I've been working on a wxWin application for image processing. From the
1756beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1757till I looked in the source code of image.cpp. I saw that converting a
1758wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1759to the 256 colors of the palet. A very time-consuming piece of code!
1760
1761Because I wanted a faster application, I've made a 'patch' for this. In
1762short: every pixel of the image is compared to a sorted list with
1763colors. If the color is found in the list, the palette entry is
1764returned; if the color is not found, the color palette is searched and
1765then the palette entry is returned and the color added to the sorted
1766list.
1767
1768Maybe there is another method for this, namely changing the palette
1769itself (if the colors are known, as is the case with tiffs with a
1770colormap). I did not look at this, maybe someone else did?
1771
1772The code of the patch is attached, have a look on it, and maybe you will
1773ship it with the next release of wxMotif?
1774
1775Regards,
1776
1777Frits Boel
1778Software engineer at Hubrecht Laboratory, The Netherlands.
1779
1780*/
1781
1782class wxSearchColor
1783{
1784public:
1785 wxSearchColor( void );
1786 wxSearchColor( int size, XColor *colors );
1787 ~wxSearchColor( void );
1788
1789 int SearchColor( int r, int g, int b );
1790private:
1791 int AddColor( unsigned int value, int pos );
1792
1793 int size;
1794 XColor *colors;
1795 unsigned int *color;
1796 int *entry;
1797
1798 int bottom;
1799 int top;
1800};
1801
1802wxSearchColor::wxSearchColor( void )
1803{
069d0f27
VZ
1804 size = 0;
1805 colors = (XColor*) NULL;
1806 color = (unsigned int *) NULL;
1807 entry = (int*) NULL;
88195b2b 1808
069d0f27
VZ
1809 bottom = 0;
1810 top = 0;
88195b2b
JS
1811}
1812
069d0f27 1813wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
88195b2b
JS
1814{
1815 int i;
069d0f27
VZ
1816 size = size_;
1817 colors = colors_;
1818 color = new unsigned int[size];
1819 entry = new int [size];
88195b2b 1820
069d0f27
VZ
1821 for (i = 0; i < size; i++ ) {
1822 entry[i] = -1;
1823 }
88195b2b 1824
069d0f27 1825 bottom = top = ( size >> 1 );
88195b2b
JS
1826}
1827
1828wxSearchColor::~wxSearchColor( void )
1829{
069d0f27
VZ
1830 if ( color ) delete color;
1831 if ( entry ) delete entry;
88195b2b
JS
1832}
1833
1834int wxSearchColor::SearchColor( int r, int g, int b )
1835{
1836 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
069d0f27
VZ
1837 int begin = bottom;
1838 int end = top;
88195b2b
JS
1839 int middle;
1840
1841 while ( begin <= end ) {
1842
1843 middle = ( begin + end ) >> 1;
1844
069d0f27
VZ
1845 if ( value == color[middle] ) {
1846 return( entry[middle] );
1847 } else if ( value < color[middle] ) {
88195b2b
JS
1848 end = middle - 1;
1849 } else {
1850 begin = middle + 1;
1851 }
1852
1853 }
1854
1855 return AddColor( value, middle );
1856}
1857
1858int wxSearchColor::AddColor( unsigned int value, int pos )
1859{
1860 int i;
1861 int pixel = -1;
1862 int max = 3 * (65536);
1863 for ( i = 0; i < 256; i++ ) {
1864 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
1865 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
1866 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
1867 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1868 if (sum < max) { pixel = i; max = sum; }
1869 }
1870
069d0f27
VZ
1871 if ( entry[pos] < 0 ) {
1872 color[pos] = value;
1873 entry[pos] = pixel;
1874 } else if ( value < color[pos] ) {
88195b2b 1875
069d0f27
VZ
1876 if ( bottom > 0 ) {
1877 for ( i = bottom; i < pos; i++ ) {
1878 color[i-1] = color[i];
1879 entry[i-1] = entry[i];
88195b2b 1880 }
069d0f27
VZ
1881 bottom--;
1882 color[pos-1] = value;
1883 entry[pos-1] = pixel;
1884 } else if ( top < size-1 ) {
1885 for ( i = top; i >= pos; i-- ) {
1886 color[i+1] = color[i];
1887 entry[i+1] = entry[i];
88195b2b 1888 }
069d0f27
VZ
1889 top++;
1890 color[pos] = value;
1891 entry[pos] = pixel;
88195b2b
JS
1892 }
1893
1894 } else {
1895
069d0f27
VZ
1896 if ( top < size-1 ) {
1897 for ( i = top; i > pos; i-- ) {
1898 color[i+1] = color[i];
1899 entry[i+1] = entry[i];
88195b2b 1900 }
069d0f27
VZ
1901 top++;
1902 color[pos+1] = value;
1903 entry[pos+1] = pixel;
1904 } else if ( bottom > 0 ) {
1905 for ( i = bottom; i < pos; i++ ) {
1906 color[i-1] = color[i];
1907 entry[i-1] = entry[i];
88195b2b 1908 }
069d0f27
VZ
1909 bottom--;
1910 color[pos] = value;
1911 entry[pos] = pixel;
88195b2b
JS
1912 }
1913
1914 }
1915
1916 return( pixel );
1917}
1918
ee4c6942
JS
1919wxBitmap wxImage::ConvertToBitmap() const
1920{
b75867a6 1921 wxBitmap bitmap;
c7abc967 1922
223d09f6 1923 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
a91b47e8 1924
b75867a6
RR
1925 int width = GetWidth();
1926 int height = GetHeight();
c7abc967 1927
b75867a6
RR
1928 bitmap.SetHeight( height );
1929 bitmap.SetWidth( width );
c7abc967 1930
b75867a6
RR
1931 Display *dpy = (Display*) wxGetDisplay();
1932 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1933 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
c7abc967 1934
b75867a6 1935 // Create image
c7abc967 1936
b75867a6 1937 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
a91b47e8 1938 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
c7abc967 1939
b75867a6 1940 bitmap.Create( width, height, bpp );
a91b47e8 1941
dbda9e86 1942 /*
b75867a6 1943 // Create mask
c7abc967 1944
dbda9e86 1945 GdkImage *mask_image = (GdkImage*) NULL;
c7abc967 1946
dbda9e86
JS
1947 if (HasMask())
1948 {
b75867a6 1949 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
c7abc967 1950
dbda9e86 1951 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
c7abc967 1952
dbda9e86
JS
1953 wxMask *mask = new wxMask();
1954 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
c7abc967 1955
dbda9e86
JS
1956 bitmap.SetMask( mask );
1957 }
1958 */
c7abc967 1959
b75867a6 1960 // Retrieve depth info
c7abc967 1961
b75867a6
RR
1962 XVisualInfo vinfo_template;
1963 XVisualInfo *vi;
c7abc967 1964
b75867a6
RR
1965 vinfo_template.visual = vis;
1966 vinfo_template.visualid = XVisualIDFromVisual( vis );
1967 vinfo_template.depth = bpp;
1968 int nitem = 0;
c7abc967 1969
b75867a6 1970 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
c7abc967 1971
223d09f6 1972 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
c7abc967 1973
38274997 1974 XFree( vi );
a91b47e8 1975
b75867a6
RR
1976 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1977 if (bpp < 8) bpp = 8;
c7abc967 1978
b75867a6 1979 // Render
c7abc967 1980
b75867a6
RR
1981 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1982 byte_order b_o = RGB;
c7abc967 1983
b75867a6
RR
1984 if (bpp >= 24)
1985 {
1986 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1987 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1988 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1989 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1990 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1991 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1992 }
c7abc967 1993
dbda9e86 1994 /*
b75867a6
RR
1995 int r_mask = GetMaskRed();
1996 int g_mask = GetMaskGreen();
1997 int b_mask = GetMaskBlue();
dbda9e86 1998 */
c7abc967 1999
38274997
RR
2000 XColor colors[256];
2001 if (bpp == 8)
2002 {
dbda9e86 2003 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
c7abc967 2004
38274997 2005 for (int i = 0; i < 256; i++) colors[i].pixel = i;
dbda9e86 2006 XQueryColors( dpy, cmap, colors, 256 );
38274997 2007 }
c7abc967 2008
88195b2b 2009 wxSearchColor scolor( 256, colors );
b75867a6 2010 unsigned char* data = GetData();
c7abc967 2011
b75867a6
RR
2012 int index = 0;
2013 for (int y = 0; y < height; y++)
2014 {
2015 for (int x = 0; x < width; x++)
2016 {
2017 int r = data[index];
dbda9e86 2018 index++;
b75867a6 2019 int g = data[index];
dbda9e86 2020 index++;
b75867a6 2021 int b = data[index];
dbda9e86 2022 index++;
c7abc967 2023
dbda9e86
JS
2024 /*
2025 if (HasMask())
2026 {
2027 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2028 gdk_image_put_pixel( mask_image, x, y, 1 );
2029 else
2030 gdk_image_put_pixel( mask_image, x, y, 0 );
2031 }
2032 */
c7abc967 2033
dbda9e86
JS
2034 switch (bpp)
2035 {
2036 case 8:
2037 {
88195b2b 2038#if 0 // Old, slower code
b75867a6 2039 int pixel = -1;
dbda9e86
JS
2040 /*
2041 if (wxTheApp->m_colorCube)
2042 {
2043 pixel = wxTheApp->m_colorCube
c7abc967
VZ
2044 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2045 }
b75867a6 2046 else
dbda9e86
JS
2047 {
2048 */
2049 int max = 3 * (65536);
2050 for (int i = 0; i < 256; i++)
2051 {
2052 int rdiff = (r << 8) - colors[i].red;
2053 int gdiff = (g << 8) - colors[i].green;
2054 int bdiff = (b << 8) - colors[i].blue;
2055 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2056 if (sum < max) { pixel = i; max = sum; }
2057 }
2058 /*
2059 }
2060 */
88195b2b
JS
2061#endif
2062
069d0f27
VZ
2063 // And this is all to get the 'right' color...
2064 int pixel = scolor.SearchColor( r, g, b );
dbda9e86
JS
2065 XPutPixel( data_image, x, y, pixel );
2066 break;
2067 }
2068 case 15:
2069 {
2070 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
2071 XPutPixel( data_image, x, y, pixel );
2072 break;
2073 }
2074 case 16:
2075 {
2076 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
2077 XPutPixel( data_image, x, y, pixel );
2078 break;
2079 }
2080 case 32:
2081 case 24:
2082 {
2083 int pixel = 0;
2084 switch (b_o)
2085 {
2086 case RGB: pixel = (r << 16) | (g << 8) | b; break;
2087 case RBG: pixel = (r << 16) | (b << 8) | g; break;
2088 case BRG: pixel = (b << 16) | (r << 8) | g; break;
2089 case BGR: pixel = (b << 16) | (g << 8) | r; break;
2090 case GRB: pixel = (g << 16) | (r << 8) | b; break;
2091 case GBR: pixel = (g << 16) | (b << 8) | r; break;
2092 }
2093 XPutPixel( data_image, x, y, pixel );
2094 }
2095 default: break;
2096 }
b75867a6
RR
2097 } // for
2098 } // for
c7abc967 2099
b75867a6 2100 // Blit picture
c7abc967 2101
b75867a6
RR
2102 XGCValues gcvalues;
2103 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
2104 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
2105 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
c7abc967 2106
b75867a6
RR
2107 XDestroyImage( data_image );
2108 XFreeGC( dpy, gc );
c7abc967 2109
dbda9e86 2110 /*
b75867a6 2111 // Blit mask
c7abc967 2112
dbda9e86
JS
2113 if (HasMask())
2114 {
2115 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
c7abc967 2116
b75867a6 2117 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
c7abc967 2118
dbda9e86
JS
2119 gdk_image_destroy( mask_image );
2120 gdk_gc_unref( mask_gc );
2121 }
2122 */
c7abc967 2123
b75867a6 2124 return bitmap;
ee4c6942
JS
2125}
2126
2127wxImage::wxImage( const wxBitmap &bitmap )
2128{
223d09f6 2129 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
c7abc967 2130
38274997
RR
2131 Display *dpy = (Display*) wxGetDisplay();
2132 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2133 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
c7abc967 2134
38274997 2135 XImage *ximage = XGetImage( dpy,
dbda9e86
JS
2136 (Drawable)bitmap.GetPixmap(),
2137 0, 0,
2138 bitmap.GetWidth(), bitmap.GetHeight(),
2139 AllPlanes, ZPixmap );
c7abc967 2140
223d09f6 2141 wxCHECK_RET( ximage, wxT("couldn't create image") );
c7abc967 2142
38274997
RR
2143 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2144 char unsigned *data = GetData();
c7abc967 2145
38274997
RR
2146 if (!data)
2147 {
2148 XDestroyImage( ximage );
223d09f6 2149 wxFAIL_MSG( wxT("couldn't create image") );
38274997
RR
2150 return;
2151 }
c7abc967 2152
dbda9e86 2153 /*
38274997
RR
2154 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2155 if (bitmap.GetMask())
2156 {
dbda9e86
JS
2157 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2158 0, 0,
2159 bitmap.GetWidth(), bitmap.GetHeight() );
c7abc967 2160
dbda9e86
JS
2161 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2162 }
2163 */
c7abc967 2164
38274997 2165 // Retrieve depth info
c7abc967 2166
38274997
RR
2167 XVisualInfo vinfo_template;
2168 XVisualInfo *vi;
c7abc967 2169
38274997
RR
2170 vinfo_template.visual = vis;
2171 vinfo_template.visualid = XVisualIDFromVisual( vis );
2172 vinfo_template.depth = bpp;
2173 int nitem = 0;
c7abc967 2174
38274997 2175 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
c7abc967 2176
223d09f6 2177 wxCHECK_RET( vi, wxT("no visual") );
c7abc967 2178
38274997 2179 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
c7abc967 2180
38274997 2181 XFree( vi );
c7abc967 2182
38274997
RR
2183 XColor colors[256];
2184 if (bpp == 8)
2185 {
dbda9e86 2186 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
c7abc967 2187
38274997 2188 for (int i = 0; i < 256; i++) colors[i].pixel = i;
dbda9e86 2189 XQueryColors( dpy, cmap, colors, 256 );
38274997 2190 }
c7abc967 2191
38274997
RR
2192 long pos = 0;
2193 for (int j = 0; j < bitmap.GetHeight(); j++)
2194 {
2195 for (int i = 0; i < bitmap.GetWidth(); i++)
2196 {
dbda9e86 2197 int pixel = XGetPixel( ximage, i, j );
38274997
RR
2198 if (bpp <= 8)
2199 {
2200 data[pos] = colors[pixel].red >> 8;
2201 data[pos+1] = colors[pixel].green >> 8;
2202 data[pos+2] = colors[pixel].blue >> 8;
2203 } else if (bpp == 15)
2204 {
2205 data[pos] = (pixel >> 7) & 0xf8;
2206 data[pos+1] = (pixel >> 2) & 0xf8;
2207 data[pos+2] = (pixel << 3) & 0xf8;
2208 } else if (bpp == 16)
2209 {
2210 data[pos] = (pixel >> 8) & 0xf8;
2211 data[pos+1] = (pixel >> 3) & 0xfc;
2212 data[pos+2] = (pixel << 3) & 0xf8;
2213 } else
2214 {
2215 data[pos] = (pixel >> 16) & 0xff;
2216 data[pos+1] = (pixel >> 8) & 0xff;
2217 data[pos+2] = pixel & 0xff;
2218 }
c7abc967 2219
dbda9e86 2220 /*
38274997
RR
2221 if (gdk_image_mask)
2222 {
dbda9e86
JS
2223 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2224 if (mask_pixel == 0)
2225 {
2226 data[pos] = 16;
2227 data[pos+1] = 16;
2228 data[pos+2] = 16;
38274997 2229 }
dbda9e86
JS
2230 }
2231 */
c7abc967 2232
38274997
RR
2233 pos += 3;
2234 }
2235 }
c7abc967 2236
38274997 2237 XDestroyImage( ximage );
dbda9e86 2238 /*
38274997 2239 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
dbda9e86 2240 */
ee4c6942
JS
2241}
2242#endif
a91b47e8 2243
004fd0c8
DW
2244#ifdef __WXPM__
2245// OS/2 Presentation manager conversion routings
2246
2247wxBitmap wxImage::ConvertToBitmap() const
2248{
2249 if ( !Ok() )
2250 return wxNullBitmap;
2251 wxBitmap bitmap; // remove
2252// TODO:
2253/*
2254 int sizeLimit = 1024*768*3;
2255
2256 // width and height of the device-dependent bitmap
2257 int width = GetWidth();
2258 int bmpHeight = GetHeight();
2259
2260 // calc the number of bytes per scanline and padding
2261 int bytePerLine = width*3;
2262 int sizeDWORD = sizeof( DWORD );
2263 int lineBoundary = bytePerLine % sizeDWORD;
2264 int padding = 0;
2265 if( lineBoundary > 0 )
2266 {
2267 padding = sizeDWORD - lineBoundary;
2268 bytePerLine += padding;
2269 }
2270 // calc the number of DIBs and heights of DIBs
2271 int numDIB = 1;
2272 int hRemain = 0;
2273 int height = sizeLimit/bytePerLine;
2274 if( height >= bmpHeight )
2275 height = bmpHeight;
2276 else
2277 {
2278 numDIB = bmpHeight / height;
2279 hRemain = bmpHeight % height;
2280 if( hRemain >0 ) numDIB++;
2281 }
2282
2283 // set bitmap parameters
2284 wxBitmap bitmap;
2285 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2286 bitmap.SetWidth( width );
2287 bitmap.SetHeight( bmpHeight );
2288 bitmap.SetDepth( wxDisplayDepth() );
2289
2290 // create a DIB header
2291 int headersize = sizeof(BITMAPINFOHEADER);
2292 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2293 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2294 // Fill in the DIB header
2295 lpDIBh->bmiHeader.biSize = headersize;
2296 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2297 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2298 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2299 // the general formula for biSizeImage:
2300 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2301 lpDIBh->bmiHeader.biPlanes = 1;
2302 lpDIBh->bmiHeader.biBitCount = 24;
2303 lpDIBh->bmiHeader.biCompression = BI_RGB;
2304 lpDIBh->bmiHeader.biClrUsed = 0;
2305 // These seem not really needed for our purpose here.
2306 lpDIBh->bmiHeader.biClrImportant = 0;
2307 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2308 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2309 // memory for DIB data
2310 unsigned char *lpBits;
2311 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2312 if( !lpBits )
2313 {
2314 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2315 free( lpDIBh );
2316 return bitmap;
2317 }
2318
2319 // create and set the device-dependent bitmap
2320 HDC hdc = ::GetDC(NULL);
2321 HDC memdc = ::CreateCompatibleDC( hdc );
2322 HBITMAP hbitmap;
2323 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2324 ::SelectObject( memdc, hbitmap);
2325
2326 // copy image data into DIB data and then into DDB (in a loop)
2327 unsigned char *data = GetData();
2328 int i, j, n;
2329 int origin = 0;
2330 unsigned char *ptdata = data;
2331 unsigned char *ptbits;
2332
2333 for( n=0; n<numDIB; n++ )
2334 {
2335 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2336 {
2337 // redefine height and size of the (possibly) last smaller DIB
2338 // memory is not reallocated
2339 height = hRemain;
2340 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2341 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2342 }
2343 ptbits = lpBits;
2344
2345 for( j=0; j<height; j++ )
2346 {
2347 for( i=0; i<width; i++ )
2348 {
2349 *(ptbits++) = *(ptdata+2);
2350 *(ptbits++) = *(ptdata+1);
2351 *(ptbits++) = *(ptdata );
2352 ptdata += 3;
2353 }
2354 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2355 }
2356 ::StretchDIBits( memdc, 0, origin, width, height,\
2357 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2358 origin += height;
2359 // if numDIB = 1, lines below can also be used
2360 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2361 // The above line is equivalent to the following two lines.
2362 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2363 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2364 // or the following lines
2365 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2366 // HDC memdc = ::CreateCompatibleDC( hdc );
2367 // ::SelectObject( memdc, hbitmap);
2368 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2369 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2370 // ::SelectObject( memdc, 0 );
2371 // ::DeleteDC( memdc );
2372 }
2373 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2374
2375 // similarly, created an mono-bitmap for the possible mask
2376 if( HasMask() )
2377 {
2378 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2379 ::SelectObject( memdc, hbitmap);
2380 if( numDIB == 1 ) height = bmpHeight;
2381 else height = sizeLimit/bytePerLine;
2382 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2383 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2384 origin = 0;
2385 unsigned char r = GetMaskRed();
2386 unsigned char g = GetMaskGreen();
2387 unsigned char b = GetMaskBlue();
2388 unsigned char zero = 0, one = 255;
2389 ptdata = data;
2390 for( n=0; n<numDIB; n++ )
2391 {
2392 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2393 {
2394 // redefine height and size of the (possibly) last smaller DIB
2395 // memory is not reallocated
2396 height = hRemain;
2397 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2398 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2399 }
2400 ptbits = lpBits;
2401 for( int j=0; j<height; j++ )
2402 {
2403 for(i=0; i<width; i++ )
2404 {
2405 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2406 {
2407 *(ptbits++) = one;
2408 *(ptbits++) = one;
2409 *(ptbits++) = one;
2410 }
2411 else
2412 {
2413 *(ptbits++) = zero;
2414 *(ptbits++) = zero;
2415 *(ptbits++) = zero;
2416 }
2417 }
2418 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2419 }
2420 ::StretchDIBits( memdc, 0, origin, width, height,\
2421 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2422 origin += height;
2423 }
2424 // create a wxMask object
2425 wxMask *mask = new wxMask();
2426 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2427 bitmap.SetMask( mask );
2428 }
2429
2430 // free allocated resources
2431 ::SelectObject( memdc, 0 );
2432 ::DeleteDC( memdc );
2433 ::ReleaseDC(NULL, hdc);
2434 free(lpDIBh);
2435 free(lpBits);
2436
2437 // check the wxBitmap object
2438 if( bitmap.GetHBITMAP() )
2439 bitmap.SetOk( TRUE );
2440 else
2441 bitmap.SetOk( FALSE );
2442*/
2443 return bitmap;
2444}
2445
2446wxImage::wxImage( const wxBitmap &bitmap )
2447{
2448 // check the bitmap
2449 if( !bitmap.Ok() )
2450 {
2451 wxFAIL_MSG( wxT("invalid bitmap") );
2452 return;
2453 }
2454
2455 // create an wxImage object
2456 int width = bitmap.GetWidth();
2457 int height = bitmap.GetHeight();
2458 Create( width, height );
2459 unsigned char *data = GetData();
2460 if( !data )
2461 {
2462 wxFAIL_MSG( wxT("could not allocate data for image") );
2463 return;
2464 }
2465
2466 // calc the number of bytes per scanline and padding in the DIB
2467 int bytePerLine = width*3;
2468 int sizeDWORD = sizeof( DWORD );
2469 int lineBoundary = bytePerLine % sizeDWORD;
2470 int padding = 0;
2471 if( lineBoundary > 0 )
2472 {
2473 padding = sizeDWORD - lineBoundary;
2474 bytePerLine += padding;
2475 }
2476// TODO:
2477/*
2478 // create a DIB header
2479 int headersize = sizeof(BITMAPINFOHEADER);
2480 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2481 if( !lpDIBh )
2482 {
2483 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2484 free( data );
2485 return;
2486 }
2487 // Fill in the DIB header
2488 lpDIBh->bmiHeader.biSize = headersize;
2489 lpDIBh->bmiHeader.biWidth = width;
2490 lpDIBh->bmiHeader.biHeight = -height;
2491 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2492 lpDIBh->bmiHeader.biPlanes = 1;
2493 lpDIBh->bmiHeader.biBitCount = 24;
2494 lpDIBh->bmiHeader.biCompression = BI_RGB;
2495 lpDIBh->bmiHeader.biClrUsed = 0;
2496 // These seem not really needed for our purpose here.
2497 lpDIBh->bmiHeader.biClrImportant = 0;
2498 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2499 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2500 // memory for DIB data
2501 unsigned char *lpBits;
2502 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2503 if( !lpBits )
2504 {
2505 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2506 free( data );
2507 free( lpDIBh );
2508 return;
2509 }
2510
2511 // copy data from the device-dependent bitmap to the DIB
2512 HDC hdc = ::GetDC(NULL);
2513 HBITMAP hbitmap;
2514 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2515 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2516
2517 // copy DIB data into the wxImage object
2518 int i, j;
2519 unsigned char *ptdata = data;
2520 unsigned char *ptbits = lpBits;
2521 for( i=0; i<height; i++ )
2522 {
2523 for( j=0; j<width; j++ )
2524 {
2525 *(ptdata++) = *(ptbits+2);
2526 *(ptdata++) = *(ptbits+1);
2527 *(ptdata++) = *(ptbits );
2528 ptbits += 3;
2529 }
2530 ptbits += padding;
2531 }
2532
2533 // similarly, set data according to the possible mask bitmap
2534 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2535 {
2536 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2537 // memory DC created, color set, data copied, and memory DC deleted
2538 HDC memdc = ::CreateCompatibleDC( hdc );
2539 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2540 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2541 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2542 ::DeleteDC( memdc );
2543 // background color set to RGB(16,16,16) in consistent with wxGTK
2544 unsigned char r=16, g=16, b=16;
2545 ptdata = data;
2546 ptbits = lpBits;
2547 for( i=0; i<height; i++ )
2548 {
2549 for( j=0; j<width; j++ )
2550 {
2551 if( *ptbits != 0 )
2552 ptdata += 3;
2553 else
2554 {
2555 *(ptdata++) = r;
2556 *(ptdata++) = g;
2557 *(ptdata++) = b;
2558 }
2559 ptbits += 3;
2560 }
2561 ptbits += padding;
2562 }
2563 SetMaskColour( r, g, b );
2564 SetMask( TRUE );
2565 }
2566 else
2567 {
2568 SetMask( FALSE );
2569 }
2570 // free allocated resources
2571 ::ReleaseDC(NULL, hdc);
2572 free(lpDIBh);
2573 free(lpBits);
2574*/
2575}
2576
2577#endif
2578
a91b47e8
JS
2579// A module to allow wxImage initialization/cleanup
2580// without calling these functions from app.cpp or from
2581// the user's application.
2582
2583class wxImageModule: public wxModule
2584{
2585DECLARE_DYNAMIC_CLASS(wxImageModule)
2586public:
2587 wxImageModule() {}
2588 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2589 void OnExit() { wxImage::CleanUpHandlers(); };
2590};
2591
2592IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
c9d01afd
GRG
2593
2594
2595//-----------------------------------------------------------------------------
2596
89d00456
GRG
2597// GRG, Dic/99
2598// Counts and returns the number of different colours. Optionally stops
cc9f7d79
GRG
2599// when it exceeds 'stopafter' different colours. This is useful, for
2600// example, to see if the image can be saved as 8-bit (256 colour or
2601// less, in this case it would be invoked as CountColours(256)). Default
2602// value for stopafter is -1 (don't care).
89d00456 2603//
cc9f7d79 2604unsigned long wxImage::CountColours( unsigned long stopafter )
89d00456
GRG
2605{
2606 wxHashTable h;
2607 wxNode *node;
2608 wxHNode *hnode;
2609 unsigned char r, g, b, *p;
2610 unsigned long size, nentries, key;
2611
2612 p = GetData();
2613 size = GetWidth() * GetHeight();
2614 nentries = 0;
2615
cc9f7d79 2616 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
89d00456
GRG
2617 {
2618 r = *(p++);
2619 g = *(p++);
2620 b = *(p++);
2621 key = (r << 16) | (g << 8) | b;
2622
2623 hnode = (wxHNode *) h.Get(key);
2624
2625 if (!hnode)
2626 {
2627 h.Put(key, (wxObject *)(new wxHNode));
2628 nentries++;
2629 }
2630 }
2631
2632 // delete all HNodes
2633 h.BeginFind();
2634 while ((node = h.Next()) != NULL)
2635 delete (wxHNode *)node->GetData();
2636
2637 return nentries;
2638}
2639
2640
c9d01afd
GRG
2641// GRG, Dic/99
2642// Computes the histogram of the image and fills a hash table, indexed
2643// with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2644// wxHNode contains an 'index' (useful to build a palette with the image
2645// colours) and a 'value', which is the number of pixels in the image with
2646// that colour.
89d00456 2647//
c9d01afd
GRG
2648unsigned long wxImage::ComputeHistogram( wxHashTable &h )
2649{
2650 unsigned char r, g, b, *p;
2651 unsigned long size, nentries, key;
2652 wxHNode *hnode;
2653
2654 p = GetData();
2655 size = GetWidth() * GetHeight();
2656 nentries = 0;
2657
2658 for (unsigned long j = 0; j < size; j++)
2659 {
2660 r = *(p++);
2661 g = *(p++);
2662 b = *(p++);
2663 key = (r << 16) | (g << 8) | b;
2664
2665 hnode = (wxHNode *) h.Get(key);
2666
2667 if (hnode)
2668 hnode->value++;
2669 else
2670 {
2671 hnode = new wxHNode();
97fdfcc9 2672 hnode->index = nentries++;
c9d01afd
GRG
2673 hnode->value = 1;
2674
2675 h.Put(key, (wxObject *)hnode);
2676 }
2677 }
2678
2679 return nentries;
2680}
2681
2682