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