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