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