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