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