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