]> git.saurik.com Git - wxWidgets.git/blame - src/common/image.cpp
Prepare wxToolBarSimple for event type change.
[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
1401#include <PictUtils.h>
1402
1403extern CTabHandle wxMacCreateColorTable( int numColors ) ;
1404extern void wxMacDestroyColorTable( CTabHandle colors ) ;
1405extern void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) ;
1406extern GWorldPtr wxMacCreateGWorld( int height , int width , int depth ) ;
1407extern void wxMacDestroyGWorld( GWorldPtr gw ) ;
1408
1409wxBitmap wxImage::ConvertToBitmap() const
1410{
1411 // width and height of the device-dependent bitmap
1412 int width = GetWidth();
1413 int height = GetHeight();
1414
1415 // Create picture
97fdfcc9 1416
7c74e7fe 1417 wxBitmap bitmap( width , height , wxDisplayDepth() ) ;
97fdfcc9 1418
7c74e7fe 1419 // Create mask
97fdfcc9 1420
7c74e7fe
SC
1421 if (HasMask())
1422 {
069d0f27 1423 /*
7c74e7fe 1424 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
97fdfcc9 1425
7c74e7fe 1426 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
97fdfcc9 1427
7c74e7fe
SC
1428 wxMask *mask = new wxMask();
1429 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
97fdfcc9 1430
7c74e7fe
SC
1431 bitmap.SetMask( mask );
1432 */
1433 }
97fdfcc9 1434
7c74e7fe 1435 // Render
97fdfcc9 1436
7c74e7fe
SC
1437 int r_mask = GetMaskRed();
1438 int g_mask = GetMaskGreen();
1439 int b_mask = GetMaskBlue();
97fdfcc9 1440
ad30de59
GRG
1441 CGrafPtr origPort ;
1442 GDHandle origDevice ;
06b466c7 1443
ad30de59
GRG
1444 GetGWorld( &origPort , &origDevice ) ;
1445 SetGWorld( bitmap.GetHBITMAP() , NULL ) ;
7c74e7fe
SC
1446
1447 register unsigned char* data = GetData();
97fdfcc9 1448
7c74e7fe
SC
1449 int index = 0;
1450 for (int y = 0; y < height; y++)
1451 {
7c74e7fe
SC
1452 for (int x = 0; x < width; x++)
1453 {
ad30de59
GRG
1454 unsigned char r = data[index++];
1455 unsigned char g = data[index++];
1456 unsigned char b = data[index++];
1457 RGBColor color ;
1458 color.red = ( r << 8 ) + r ;
1459 color.green = ( g << 8 ) + g ;
1460 color.blue = ( b << 8 ) + b ;
1461 SetCPixel( x , y , &color ) ;
1462 }
7c74e7fe
SC
1463 } // for height
1464
069d0f27 1465 SetGWorld( origPort , origDevice ) ;
97fdfcc9 1466
8208e181
SC
1467 if ( HasMask() )
1468 {
1469 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1470 wxMask *mask = new wxMask( bitmap, colour );
1471 bitmap.SetMask( mask );
1472 }
7c74e7fe 1473 return bitmap;
97fdfcc9 1474
7c74e7fe
SC
1475}
1476
1477wxImage::wxImage( const wxBitmap &bitmap )
1478{
1479 // check the bitmap
1480 if( !bitmap.Ok() )
1481 {
1482 wxFAIL_MSG( "invalid bitmap" );
1483 return;
1484 }
97fdfcc9 1485
7c74e7fe
SC
1486 // create an wxImage object
1487 int width = bitmap.GetWidth();
1488 int height = bitmap.GetHeight();
97fdfcc9 1489 Create( width, height );
7c74e7fe
SC
1490 /*
1491 unsigned char *data = GetData();
1492 if( !data )
1493 {
1494 wxFAIL_MSG( "could not allocate data for image" );
1495 return;
1496 }
97fdfcc9 1497
7c74e7fe
SC
1498 // calc the number of bytes per scanline and padding in the DIB
1499 int bytePerLine = width*3;
1500 int sizeDWORD = sizeof( DWORD );
1501 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1502 int padding = 0;
97fdfcc9 1503 if( lineBoundary.rem > 0 )
7c74e7fe
SC
1504 {
1505 padding = sizeDWORD - lineBoundary.rem;
1506 bytePerLine += padding;
1507 }
97fdfcc9 1508
7c74e7fe
SC
1509 // create a DIB header
1510 int headersize = sizeof(BITMAPINFOHEADER);
1511 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1512 if( !lpDIBh )
1513 {
1514 wxFAIL_MSG( "could not allocate data for DIB header" );
1515 free( data );
1516 return;
1517 }
1518 // Fill in the DIB header
1519 lpDIBh->bmiHeader.biSize = headersize;
1520 lpDIBh->bmiHeader.biWidth = width;
1521 lpDIBh->bmiHeader.biHeight = -height;
1522 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1523 lpDIBh->bmiHeader.biPlanes = 1;
1524 lpDIBh->bmiHeader.biBitCount = 24;
1525 lpDIBh->bmiHeader.biCompression = BI_RGB;
1526 lpDIBh->bmiHeader.biClrUsed = 0;
1527 // These seem not really needed for our purpose here.
1528 lpDIBh->bmiHeader.biClrImportant = 0;
1529 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1530 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1531 // memory for DIB data
1532 unsigned char *lpBits;
1533 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1534 if( !lpBits )
1535 {
1536 wxFAIL_MSG( "could not allocate data for DIB" );
1537 free( data );
1538 free( lpDIBh );
1539 return;
1540 }
97fdfcc9 1541
7c74e7fe
SC
1542 // copy data from the device-dependent bitmap to the DIB
1543 HDC hdc = ::GetDC(NULL);
1544 HBITMAP hbitmap;
1545 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1546 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
97fdfcc9 1547
7c74e7fe
SC
1548 // copy DIB data into the wxImage object
1549 int i, j;
1550 unsigned char *ptdata = data;
1551 unsigned char *ptbits = lpBits;
1552 for( i=0; i<height; i++ )
1553 {
1554 for( j=0; j<width; j++ )
1555 {
1556 *(ptdata++) = *(ptbits+2);
1557 *(ptdata++) = *(ptbits+1);
1558 *(ptdata++) = *(ptbits );
1559 ptbits += 3;
1560 }
1561 ptbits += padding;
06b466c7 1562 }
97fdfcc9 1563
7c74e7fe
SC
1564 // similarly, set data according to the possible mask bitmap
1565 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1566 {
1567 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1568 // memory DC created, color set, data copied, and memory DC deleted
1569 HDC memdc = ::CreateCompatibleDC( hdc );
1570 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1571 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1572 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
97fdfcc9 1573 ::DeleteDC( memdc );
7c74e7fe 1574 // background color set to RGB(16,16,16) in consistent with wxGTK
97fdfcc9 1575 unsigned char r=16, g=16, b=16;
7c74e7fe
SC
1576 ptdata = data;
1577 ptbits = lpBits;
1578 for( i=0; i<height; i++ )
1579 {
1580 for( j=0; j<width; j++ )
1581 {
1582 if( *ptbits != 0 )
1583 ptdata += 3;
1584 else
1585 {
1586 *(ptdata++) = r;
1587 *(ptdata++) = g;
1588 *(ptdata++) = b;
1589 }
1590 ptbits += 3;
1591 }
1592 ptbits += padding;
97fdfcc9 1593 }
7c74e7fe
SC
1594 SetMaskColour( r, g, b );
1595 SetMask( TRUE );
8f177c8e 1596 }
7c74e7fe
SC
1597 else
1598 {
1599 SetMask( FALSE );
8f177c8e 1600 }
97fdfcc9
DW
1601 // free allocated resources
1602 ::ReleaseDC(NULL, hdc);
7c74e7fe
SC
1603 free(lpDIBh);
1604 free(lpBits);
1605 */
1606}
1607
1608#endif
1609
ce4169a4
RR
1610//-----------------------------------------------------------------------------
1611// GTK conversion routines
1612//-----------------------------------------------------------------------------
1613
99c67c77
RR
1614#ifdef __WXGTK__
1615
20e05ffb
RR
1616#include <gtk/gtk.h>
1617#include <gdk/gdk.h>
1618#include <gdk/gdkx.h>
83624f79 1619
ba0730de 1620#if (GTK_MINOR_VERSION > 0)
20e05ffb 1621#include <gdk/gdkrgb.h>
ba0730de
RR
1622#endif
1623
d76fe38b
RR
1624extern GtkWidget *wxRootWindow;
1625
82ea63e6
RR
1626wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue )
1627{
1628 wxBitmap bitmap;
1629
1630 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1631
1632 int width = GetWidth();
1633 int height = GetHeight();
1634
1635 bitmap.SetHeight( height );
1636 bitmap.SetWidth( width );
1637
d76fe38b 1638 bitmap.SetBitmap( gdk_pixmap_new( wxRootWindow->window, width, height, 1 ) );
06b466c7 1639
82ea63e6
RR
1640 bitmap.SetDepth( 1 );
1641
103aab26
RR
1642 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1643 wxASSERT( visual );
06b466c7 1644
82ea63e6
RR
1645 // Create picture image
1646
1647 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
06b466c7 1648
82ea63e6 1649 GdkImage *data_image =
103aab26 1650 gdk_image_new_bitmap( visual, data_data, width, height );
82ea63e6
RR
1651
1652 // Create mask image
1653
1654 GdkImage *mask_image = (GdkImage*) NULL;
1655
1656 if (HasMask())
1657 {
1658 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1659
103aab26 1660 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
82ea63e6
RR
1661
1662 wxMask *mask = new wxMask();
d76fe38b 1663 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
82ea63e6
RR
1664
1665 bitmap.SetMask( mask );
1666 }
1667
1668 int r_mask = GetMaskRed();
1669 int g_mask = GetMaskGreen();
1670 int b_mask = GetMaskBlue();
1671
1672 unsigned char* data = GetData();
1673
1674 int index = 0;
1675 for (int y = 0; y < height; y++)
1676 {
1677 for (int x = 0; x < width; x++)
1678 {
1679 int r = data[index];
1680 index++;
1681 int g = data[index];
1682 index++;
1683 int b = data[index];
1684 index++;
1685
1686 if (HasMask())
1687 {
1688 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1689 gdk_image_put_pixel( mask_image, x, y, 1 );
1690 else
1691 gdk_image_put_pixel( mask_image, x, y, 0 );
1692 }
06b466c7 1693
82ea63e6
RR
1694 if ((r == red) && (b == blue) && (g == green))
1695 gdk_image_put_pixel( data_image, x, y, 1 );
06b466c7 1696 else
82ea63e6
RR
1697 gdk_image_put_pixel( data_image, x, y, 0 );
1698
1699 } // for
1700 } // for
1701
1702 // Blit picture
1703
1704 GdkGC *data_gc = gdk_gc_new( bitmap.GetBitmap() );
1705
1706 gdk_draw_image( bitmap.GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1707
1708 gdk_image_destroy( data_image );
1709 gdk_gc_unref( data_gc );
1710
1711 // Blit mask
1712
1713 if (HasMask())
1714 {
1715 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1716
1717 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1718
1719 gdk_image_destroy( mask_image );
1720 gdk_gc_unref( mask_gc );
1721 }
1722
1723 return bitmap;
1724}
1725
1726
99c67c77
RR
1727wxBitmap wxImage::ConvertToBitmap() const
1728{
1729 wxBitmap bitmap;
c7abc967 1730
223d09f6 1731 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
c7abc967 1732
99c67c77
RR
1733 int width = GetWidth();
1734 int height = GetHeight();
c7abc967 1735
99c67c77
RR
1736 bitmap.SetHeight( height );
1737 bitmap.SetWidth( width );
c7abc967 1738
d76fe38b 1739 bitmap.SetPixmap( gdk_pixmap_new( wxRootWindow->window, width, height, -1 ) );
ba0730de 1740
103aab26 1741 // Retrieve depth
c7abc967 1742
103aab26
RR
1743 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1744 wxASSERT( visual );
06b466c7 1745
ba0730de 1746 int bpp = visual->depth;
c7abc967 1747
ba0730de 1748 bitmap.SetDepth( bpp );
c7abc967 1749
ba0730de
RR
1750 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1751 if (bpp < 8) bpp = 8;
c7abc967 1752
ba0730de
RR
1753#if (GTK_MINOR_VERSION > 0)
1754
1755 if (!HasMask() && (bpp > 8))
1756 {
1757 static bool s_hasInitialized = FALSE;
c7abc967 1758
995612e2
VZ
1759 if (!s_hasInitialized)
1760 {
1761 gdk_rgb_init();
1762 s_hasInitialized = TRUE;
1763 }
c7abc967 1764
ba0730de 1765 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
c7abc967 1766
995612e2
VZ
1767 gdk_draw_rgb_image( bitmap.GetPixmap(),
1768 gc,
1769 0, 0,
1770 width, height,
1771 GDK_RGB_DITHER_NONE,
1772 GetData(),
1773 width*3 );
c7abc967 1774
ba0730de 1775 gdk_gc_unref( gc );
c7abc967 1776
995612e2 1777 return bitmap;
ba0730de 1778 }
c7abc967 1779
ba0730de 1780#endif
c7abc967 1781
ba0730de 1782 // Create picture image
c7abc967 1783
99c67c77 1784 GdkImage *data_image =
103aab26 1785 gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
c7abc967 1786
ba0730de 1787 // Create mask image
c7abc967 1788
99c67c77 1789 GdkImage *mask_image = (GdkImage*) NULL;
c7abc967 1790
99c67c77
RR
1791 if (HasMask())
1792 {
1793 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
c7abc967 1794
103aab26 1795 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
c7abc967 1796
4698648f 1797 wxMask *mask = new wxMask();
d76fe38b 1798 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
c7abc967 1799
4698648f 1800 bitmap.SetMask( mask );
99c67c77 1801 }
c7abc967 1802
99c67c77 1803 // Render
c7abc967 1804
99c67c77
RR
1805 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1806 byte_order b_o = RGB;
c7abc967 1807
99c67c77
RR
1808 if (bpp >= 24)
1809 {
99c67c77
RR
1810 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1811 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1812 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1813 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1814 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1815 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1816 }
c7abc967 1817
99c67c77
RR
1818 int r_mask = GetMaskRed();
1819 int g_mask = GetMaskGreen();
1820 int b_mask = GetMaskBlue();
c7abc967 1821
99c67c77 1822 unsigned char* data = GetData();
c7abc967 1823
99c67c77
RR
1824 int index = 0;
1825 for (int y = 0; y < height; y++)
1826 {
1827 for (int x = 0; x < width; x++)
1828 {
1829 int r = data[index];
4698648f 1830 index++;
99c67c77 1831 int g = data[index];
4698648f 1832 index++;
99c67c77 1833 int b = data[index];
4698648f 1834 index++;
c7abc967 1835
4698648f
VZ
1836 if (HasMask())
1837 {
1838 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1839 gdk_image_put_pixel( mask_image, x, y, 1 );
1840 else
1841 gdk_image_put_pixel( mask_image, x, y, 0 );
1842 }
c7abc967 1843
4698648f
VZ
1844 switch (bpp)
1845 {
dbda9e86 1846 case 8:
4698648f 1847 {
f6fcbb63 1848 int pixel = -1;
4698648f
VZ
1849 if (wxTheApp->m_colorCube)
1850 {
38274997 1851 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
4698648f 1852 }
f6fcbb63 1853 else
4698648f
VZ
1854 {
1855 GdkColormap *cmap = gtk_widget_get_default_colormap();
f6fcbb63
RR
1856 GdkColor *colors = cmap->colors;
1857 int max = 3 * (65536);
c7abc967 1858
f6fcbb63
RR
1859 for (int i = 0; i < cmap->size; i++)
1860 {
1861 int rdiff = (r << 8) - colors[i].red;
1862 int gdiff = (g << 8) - colors[i].green;
1863 int bdiff = (b << 8) - colors[i].blue;
1864 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1865 if (sum < max) { pixel = i; max = sum; }
4698648f 1866 }
99c67c77 1867 }
c7abc967 1868
4698648f 1869 gdk_image_put_pixel( data_image, x, y, pixel );
c7abc967 1870
4698648f
VZ
1871 break;
1872 }
dbda9e86 1873 case 15:
4698648f
VZ
1874 {
1875 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1876 gdk_image_put_pixel( data_image, x, y, pixel );
1877 break;
1878 }
dbda9e86 1879 case 16:
4698648f
VZ
1880 {
1881 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1882 gdk_image_put_pixel( data_image, x, y, pixel );
1883 break;
1884 }
dbda9e86
JS
1885 case 32:
1886 case 24:
4698648f
VZ
1887 {
1888 guint32 pixel = 0;
1889 switch (b_o)
1890 {
dbda9e86
JS
1891 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1892 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1893 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1894 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1895 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1896 case GBR: pixel = (g << 16) | (b << 8) | r; break;
4698648f
VZ
1897 }
1898 gdk_image_put_pixel( data_image, x, y, pixel );
1899 }
dbda9e86 1900 default: break;
4698648f 1901 }
99c67c77
RR
1902 } // for
1903 } // for
c7abc967 1904
99c67c77 1905 // Blit picture
c7abc967 1906
99c67c77 1907 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
c7abc967 1908
99c67c77 1909 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
c7abc967 1910
99c67c77
RR
1911 gdk_image_destroy( data_image );
1912 gdk_gc_unref( data_gc );
c7abc967 1913
99c67c77 1914 // Blit mask
c7abc967 1915
99c67c77
RR
1916 if (HasMask())
1917 {
1918 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
c7abc967 1919
99c67c77 1920 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
c7abc967 1921
99c67c77
RR
1922 gdk_image_destroy( mask_image );
1923 gdk_gc_unref( mask_gc );
1924 }
c7abc967 1925
99c67c77
RR
1926 return bitmap;
1927}
1928
1929wxImage::wxImage( const wxBitmap &bitmap )
1930{
223d09f6 1931 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
c7abc967 1932
c6d73ef6
RR
1933 GdkImage *gdk_image = (GdkImage*) NULL;
1934 if (bitmap.GetPixmap())
1935 {
1936 gdk_image = gdk_image_get( bitmap.GetPixmap(),
1937 0, 0,
1938 bitmap.GetWidth(), bitmap.GetHeight() );
1939 } else
1940 if (bitmap.GetBitmap())
1941 {
1942 gdk_image = gdk_image_get( bitmap.GetBitmap(),
1943 0, 0,
1944 bitmap.GetWidth(), bitmap.GetHeight() );
1945 } else
1946 {
1947 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1948 }
c7abc967 1949
223d09f6 1950 wxCHECK_RET( gdk_image, wxT("couldn't create image") );
0a07a7d8 1951
99c67c77
RR
1952 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1953 char unsigned *data = GetData();
c7abc967 1954
99c67c77
RR
1955 if (!data)
1956 {
1957 gdk_image_destroy( gdk_image );
223d09f6 1958 wxFAIL_MSG( wxT("couldn't create image") );
4698648f 1959 return;
99c67c77 1960 }
c7abc967 1961
99c67c77
RR
1962 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1963 if (bitmap.GetMask())
1964 {
1965 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
dbda9e86
JS
1966 0, 0,
1967 bitmap.GetWidth(), bitmap.GetHeight() );
c7abc967 1968
4698648f 1969 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
99c67c77 1970 }
c7abc967 1971
be25e480 1972 int bpp = -1;
cf3da716
RR
1973 int red_shift_right = 0;
1974 int green_shift_right = 0;
1975 int blue_shift_right = 0;
1976 int red_shift_left = 0;
1977 int green_shift_left = 0;
1978 int blue_shift_left = 0;
1979 bool use_shift = FALSE;
06b466c7 1980
c6d73ef6 1981 if (bitmap.GetPixmap())
be25e480
RR
1982 {
1983 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
c6d73ef6 1984
d76fe38b 1985 if (visual == NULL) visual = gdk_window_get_visual( wxRootWindow->window );
be25e480 1986 bpp = visual->depth;
cf3da716
RR
1987 if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1988 red_shift_right = visual->red_shift;
1989 red_shift_left = 8-visual->red_prec;
1990 green_shift_right = visual->green_shift;
1991 green_shift_left = 8-visual->green_prec;
1992 blue_shift_right = visual->blue_shift;
1993 blue_shift_left = 8-visual->blue_prec;
06b466c7 1994
cf3da716 1995 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
be25e480
RR
1996 }
1997 if (bitmap.GetBitmap())
1998 {
1999 bpp = 1;
2000 }
c7abc967 2001
06b466c7 2002
99c67c77 2003 GdkColormap *cmap = gtk_widget_get_default_colormap();
c7abc967 2004
99c67c77
RR
2005 long pos = 0;
2006 for (int j = 0; j < bitmap.GetHeight(); j++)
2007 {
2008 for (int i = 0; i < bitmap.GetWidth(); i++)
2009 {
cf3da716 2010 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
069d0f27
VZ
2011 if (bpp == 1)
2012 {
2013 if (pixel == 0)
2014 {
cf3da716 2015 data[pos] = 0;
be25e480
RR
2016 data[pos+1] = 0;
2017 data[pos+2] = 0;
069d0f27
VZ
2018 }
2019 else
2020 {
cf3da716 2021 data[pos] = 255;
be25e480
RR
2022 data[pos+1] = 255;
2023 data[pos+2] = 255;
069d0f27 2024 }
cf3da716
RR
2025 }
2026 else if (use_shift)
99c67c77 2027 {
cf3da716
RR
2028 data[pos] = (pixel >> red_shift_right) << red_shift_left;
2029 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
2030 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
06b466c7 2031 }
cf3da716 2032 else if (cmap->colors)
99c67c77 2033 {
cf3da716
RR
2034 data[pos] = cmap->colors[pixel].red >> 8;
2035 data[pos+1] = cmap->colors[pixel].green >> 8;
2036 data[pos+2] = cmap->colors[pixel].blue >> 8;
06b466c7 2037 }
cf3da716 2038 else
99c67c77 2039 {
cf3da716 2040 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
06b466c7 2041 }
c7abc967 2042
4698648f
VZ
2043 if (gdk_image_mask)
2044 {
2045 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2046 if (mask_pixel == 0)
2047 {
99c67c77
RR
2048 data[pos] = 16;
2049 data[pos+1] = 16;
2050 data[pos+2] = 16;
dbda9e86 2051 }
4698648f 2052 }
c7abc967 2053
99c67c77
RR
2054 pos += 3;
2055 }
2056 }
c7abc967 2057
99c67c77
RR
2058 gdk_image_destroy( gdk_image );
2059 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2060}
2061
2062#endif
ee4c6942 2063
ce4169a4
RR
2064//-----------------------------------------------------------------------------
2065// Motif conversion routines
2066//-----------------------------------------------------------------------------
2067
ee4c6942 2068#ifdef __WXMOTIF__
338dd992
JJ
2069#ifdef __VMS__
2070#pragma message disable nosimpint
2071#endif
b75867a6 2072#include <Xm/Xm.h>
338dd992
JJ
2073#ifdef __VMS__
2074#pragma message enable nosimpint
2075#endif
b75867a6 2076#include "wx/utils.h"
38274997 2077#include <math.h>
b75867a6 2078
88195b2b
JS
2079/*
2080
2081Date: Wed, 05 Jan 2000 11:45:40 +0100
2082From: Frits Boel <boel@niob.knaw.nl>
2083To: julian.smart@ukonline.co.uk
2084Subject: Patch for Motif ConvertToBitmap
2085
2086Hi Julian,
2087
2088I've been working on a wxWin application for image processing. From the
2089beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
2090till I looked in the source code of image.cpp. I saw that converting a
2091wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
2092to the 256 colors of the palet. A very time-consuming piece of code!
2093
2094Because I wanted a faster application, I've made a 'patch' for this. In
2095short: every pixel of the image is compared to a sorted list with
2096colors. If the color is found in the list, the palette entry is
2097returned; if the color is not found, the color palette is searched and
2098then the palette entry is returned and the color added to the sorted
2099list.
2100
2101Maybe there is another method for this, namely changing the palette
2102itself (if the colors are known, as is the case with tiffs with a
2103colormap). I did not look at this, maybe someone else did?
2104
2105The code of the patch is attached, have a look on it, and maybe you will
2106ship it with the next release of wxMotif?
2107
2108Regards,
2109
2110Frits Boel
2111Software engineer at Hubrecht Laboratory, The Netherlands.
2112
2113*/
2114
2115class wxSearchColor
2116{
2117public:
2118 wxSearchColor( void );
2119 wxSearchColor( int size, XColor *colors );
2120 ~wxSearchColor( void );
2121
2122 int SearchColor( int r, int g, int b );
2123private:
2124 int AddColor( unsigned int value, int pos );
2125
2126 int size;
2127 XColor *colors;
2128 unsigned int *color;
2129 int *entry;
2130
2131 int bottom;
2132 int top;
2133};
2134
2135wxSearchColor::wxSearchColor( void )
2136{
069d0f27
VZ
2137 size = 0;
2138 colors = (XColor*) NULL;
2139 color = (unsigned int *) NULL;
2140 entry = (int*) NULL;
88195b2b 2141
069d0f27
VZ
2142 bottom = 0;
2143 top = 0;
88195b2b
JS
2144}
2145
069d0f27 2146wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
88195b2b
JS
2147{
2148 int i;
069d0f27
VZ
2149 size = size_;
2150 colors = colors_;
2151 color = new unsigned int[size];
2152 entry = new int [size];
88195b2b 2153
069d0f27
VZ
2154 for (i = 0; i < size; i++ ) {
2155 entry[i] = -1;
2156 }
88195b2b 2157
069d0f27 2158 bottom = top = ( size >> 1 );
88195b2b
JS
2159}
2160
2161wxSearchColor::~wxSearchColor( void )
2162{
069d0f27
VZ
2163 if ( color ) delete color;
2164 if ( entry ) delete entry;
88195b2b
JS
2165}
2166
2167int wxSearchColor::SearchColor( int r, int g, int b )
2168{
2169 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
069d0f27
VZ
2170 int begin = bottom;
2171 int end = top;
88195b2b
JS
2172 int middle;
2173
2174 while ( begin <= end ) {
2175
2176 middle = ( begin + end ) >> 1;
2177
069d0f27
VZ
2178 if ( value == color[middle] ) {
2179 return( entry[middle] );
2180 } else if ( value < color[middle] ) {
88195b2b
JS
2181 end = middle - 1;
2182 } else {
2183 begin = middle + 1;
2184 }
2185
2186 }
2187
2188 return AddColor( value, middle );
2189}
2190
2191int wxSearchColor::AddColor( unsigned int value, int pos )
2192{
2193 int i;
2194 int pixel = -1;
2195 int max = 3 * (65536);
2196 for ( i = 0; i < 256; i++ ) {
2197 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
2198 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
2199 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
2200 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2201 if (sum < max) { pixel = i; max = sum; }
2202 }
2203
069d0f27
VZ
2204 if ( entry[pos] < 0 ) {
2205 color[pos] = value;
2206 entry[pos] = pixel;
2207 } else if ( value < color[pos] ) {
88195b2b 2208
069d0f27
VZ
2209 if ( bottom > 0 ) {
2210 for ( i = bottom; i < pos; i++ ) {
2211 color[i-1] = color[i];
2212 entry[i-1] = entry[i];
88195b2b 2213 }
069d0f27
VZ
2214 bottom--;
2215 color[pos-1] = value;
2216 entry[pos-1] = pixel;
2217 } else if ( top < size-1 ) {
2218 for ( i = top; i >= pos; i-- ) {
2219 color[i+1] = color[i];
2220 entry[i+1] = entry[i];
88195b2b 2221 }
069d0f27
VZ
2222 top++;
2223 color[pos] = value;
2224 entry[pos] = pixel;
88195b2b
JS
2225 }
2226
2227 } else {
2228
069d0f27
VZ
2229 if ( top < size-1 ) {
2230 for ( i = top; i > pos; i-- ) {
2231 color[i+1] = color[i];
2232 entry[i+1] = entry[i];
88195b2b 2233 }
069d0f27
VZ
2234 top++;
2235 color[pos+1] = value;
2236 entry[pos+1] = pixel;
2237 } else if ( bottom > 0 ) {
2238 for ( i = bottom; i < pos; i++ ) {
2239 color[i-1] = color[i];
2240 entry[i-1] = entry[i];
88195b2b 2241 }
069d0f27
VZ
2242 bottom--;
2243 color[pos] = value;
2244 entry[pos] = pixel;
88195b2b
JS
2245 }
2246
2247 }
2248
2249 return( pixel );
2250}
2251
ee4c6942
JS
2252wxBitmap wxImage::ConvertToBitmap() const
2253{
b75867a6 2254 wxBitmap bitmap;
c7abc967 2255
223d09f6 2256 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
a91b47e8 2257
b75867a6
RR
2258 int width = GetWidth();
2259 int height = GetHeight();
c7abc967 2260
b75867a6
RR
2261 bitmap.SetHeight( height );
2262 bitmap.SetWidth( width );
c7abc967 2263
b75867a6
RR
2264 Display *dpy = (Display*) wxGetDisplay();
2265 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2266 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
c7abc967 2267
b75867a6 2268 // Create image
c7abc967 2269
b75867a6 2270 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
a91b47e8 2271 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
c7abc967 2272
b75867a6 2273 bitmap.Create( width, height, bpp );
a91b47e8 2274
b75867a6 2275 // Create mask
c7abc967 2276
68be9f09
JS
2277 XImage *mask_image = (XImage*) NULL;
2278 if (HasMask())
2279 {
2280 mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 );
2281 mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height );
2282 }
c7abc967 2283
b75867a6 2284 // Retrieve depth info
c7abc967 2285
b75867a6
RR
2286 XVisualInfo vinfo_template;
2287 XVisualInfo *vi;
c7abc967 2288
b75867a6
RR
2289 vinfo_template.visual = vis;
2290 vinfo_template.visualid = XVisualIDFromVisual( vis );
2291 vinfo_template.depth = bpp;
2292 int nitem = 0;
c7abc967 2293
b75867a6 2294 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
c7abc967 2295
223d09f6 2296 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
c7abc967 2297
38274997 2298 XFree( vi );
a91b47e8 2299
b75867a6
RR
2300 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2301 if (bpp < 8) bpp = 8;
c7abc967 2302
b75867a6 2303 // Render
c7abc967 2304
b75867a6
RR
2305 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
2306 byte_order b_o = RGB;
c7abc967 2307
b75867a6
RR
2308 if (bpp >= 24)
2309 {
2310 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
2311 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
2312 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
2313 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
2314 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
2315 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
2316 }
c7abc967 2317
b75867a6
RR
2318 int r_mask = GetMaskRed();
2319 int g_mask = GetMaskGreen();
2320 int b_mask = GetMaskBlue();
c7abc967 2321
38274997
RR
2322 XColor colors[256];
2323 if (bpp == 8)
2324 {
dbda9e86 2325 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
c7abc967 2326
38274997 2327 for (int i = 0; i < 256; i++) colors[i].pixel = i;
dbda9e86 2328 XQueryColors( dpy, cmap, colors, 256 );
38274997 2329 }
c7abc967 2330
88195b2b 2331 wxSearchColor scolor( 256, colors );
b75867a6 2332 unsigned char* data = GetData();
c7abc967 2333
68be9f09
JS
2334 bool hasMask = HasMask();
2335
b75867a6
RR
2336 int index = 0;
2337 for (int y = 0; y < height; y++)
2338 {
2339 for (int x = 0; x < width; x++)
2340 {
2341 int r = data[index];
dbda9e86 2342 index++;
b75867a6 2343 int g = data[index];
dbda9e86 2344 index++;
b75867a6 2345 int b = data[index];
dbda9e86 2346 index++;
c7abc967 2347
68be9f09 2348 if (hasMask)
dbda9e86 2349 {
68be9f09
JS
2350 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2351 XPutPixel( mask_image, x, y, 0 );
2352 else
2353 XPutPixel( mask_image, x, y, 1 );
dbda9e86 2354 }
c7abc967 2355
dbda9e86
JS
2356 switch (bpp)
2357 {
2358 case 8:
2359 {
88195b2b 2360#if 0 // Old, slower code
b75867a6 2361 int pixel = -1;
dbda9e86
JS
2362 /*
2363 if (wxTheApp->m_colorCube)
2364 {
2365 pixel = wxTheApp->m_colorCube
c7abc967
VZ
2366 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2367 }
b75867a6 2368 else
dbda9e86
JS
2369 {
2370 */
2371 int max = 3 * (65536);
2372 for (int i = 0; i < 256; i++)
2373 {
2374 int rdiff = (r << 8) - colors[i].red;
2375 int gdiff = (g << 8) - colors[i].green;
2376 int bdiff = (b << 8) - colors[i].blue;
2377 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2378 if (sum < max) { pixel = i; max = sum; }
2379 }
2380 /*
2381 }
2382 */
88195b2b
JS
2383#endif
2384
069d0f27
VZ
2385 // And this is all to get the 'right' color...
2386 int pixel = scolor.SearchColor( r, g, b );
dbda9e86
JS
2387 XPutPixel( data_image, x, y, pixel );
2388 break;
2389 }
2390 case 15:
2391 {
2392 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
2393 XPutPixel( data_image, x, y, pixel );
2394 break;
2395 }
2396 case 16:
2397 {
2398 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
2399 XPutPixel( data_image, x, y, pixel );
2400 break;
2401 }
2402 case 32:
2403 case 24:
2404 {
2405 int pixel = 0;
2406 switch (b_o)
2407 {
2408 case RGB: pixel = (r << 16) | (g << 8) | b; break;
2409 case RBG: pixel = (r << 16) | (b << 8) | g; break;
2410 case BRG: pixel = (b << 16) | (r << 8) | g; break;
2411 case BGR: pixel = (b << 16) | (g << 8) | r; break;
2412 case GRB: pixel = (g << 16) | (r << 8) | b; break;
2413 case GBR: pixel = (g << 16) | (b << 8) | r; break;
2414 }
2415 XPutPixel( data_image, x, y, pixel );
2416 }
2417 default: break;
2418 }
b75867a6
RR
2419 } // for
2420 } // for
c7abc967 2421
b75867a6 2422 // Blit picture
c7abc967 2423
b75867a6
RR
2424 XGCValues gcvalues;
2425 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
2426 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
2427 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
c7abc967 2428
b75867a6
RR
2429 XDestroyImage( data_image );
2430 XFreeGC( dpy, gc );
c7abc967 2431
b75867a6 2432 // Blit mask
68be9f09
JS
2433 if (HasMask())
2434 {
2435 wxBitmap maskBitmap(width, height, 1);
c7abc967 2436
68be9f09
JS
2437 GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), (XtGCMask) 0, (XGCValues*)NULL );
2438 XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height );
c7abc967 2439
68be9f09
JS
2440 XDestroyImage( mask_image );
2441 XFreeGC( dpy, gcMask );
c7abc967 2442
68be9f09
JS
2443 wxMask* mask = new wxMask;
2444 mask->SetPixmap(maskBitmap.GetPixmap());
2445
2446 bitmap.SetMask(mask);
2447
2448 maskBitmap.SetPixmapNull();
2449 }
c7abc967 2450
b75867a6 2451 return bitmap;
ee4c6942
JS
2452}
2453
2454wxImage::wxImage( const wxBitmap &bitmap )
2455{
223d09f6 2456 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
c7abc967 2457
38274997
RR
2458 Display *dpy = (Display*) wxGetDisplay();
2459 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2460 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
c7abc967 2461
38274997 2462 XImage *ximage = XGetImage( dpy,
dbda9e86
JS
2463 (Drawable)bitmap.GetPixmap(),
2464 0, 0,
2465 bitmap.GetWidth(), bitmap.GetHeight(),
2466 AllPlanes, ZPixmap );
c7abc967 2467
223d09f6 2468 wxCHECK_RET( ximage, wxT("couldn't create image") );
c7abc967 2469
38274997
RR
2470 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2471 char unsigned *data = GetData();
c7abc967 2472
38274997
RR
2473 if (!data)
2474 {
2475 XDestroyImage( ximage );
223d09f6 2476 wxFAIL_MSG( wxT("couldn't create image") );
38274997
RR
2477 return;
2478 }
c7abc967 2479
dbda9e86 2480 /*
38274997
RR
2481 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2482 if (bitmap.GetMask())
2483 {
dbda9e86
JS
2484 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2485 0, 0,
2486 bitmap.GetWidth(), bitmap.GetHeight() );
c7abc967 2487
dbda9e86
JS
2488 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2489 }
2490 */
c7abc967 2491
38274997 2492 // Retrieve depth info
c7abc967 2493
38274997
RR
2494 XVisualInfo vinfo_template;
2495 XVisualInfo *vi;
c7abc967 2496
38274997
RR
2497 vinfo_template.visual = vis;
2498 vinfo_template.visualid = XVisualIDFromVisual( vis );
2499 vinfo_template.depth = bpp;
2500 int nitem = 0;
c7abc967 2501
38274997 2502 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
c7abc967 2503
223d09f6 2504 wxCHECK_RET( vi, wxT("no visual") );
c7abc967 2505
38274997 2506 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
c7abc967 2507
38274997 2508 XFree( vi );
c7abc967 2509
38274997
RR
2510 XColor colors[256];
2511 if (bpp == 8)
2512 {
dbda9e86 2513 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
c7abc967 2514
38274997 2515 for (int i = 0; i < 256; i++) colors[i].pixel = i;
dbda9e86 2516 XQueryColors( dpy, cmap, colors, 256 );
38274997 2517 }
c7abc967 2518
38274997
RR
2519 long pos = 0;
2520 for (int j = 0; j < bitmap.GetHeight(); j++)
2521 {
2522 for (int i = 0; i < bitmap.GetWidth(); i++)
2523 {
dbda9e86 2524 int pixel = XGetPixel( ximage, i, j );
38274997
RR
2525 if (bpp <= 8)
2526 {
2527 data[pos] = colors[pixel].red >> 8;
2528 data[pos+1] = colors[pixel].green >> 8;
2529 data[pos+2] = colors[pixel].blue >> 8;
2530 } else if (bpp == 15)
2531 {
2532 data[pos] = (pixel >> 7) & 0xf8;
2533 data[pos+1] = (pixel >> 2) & 0xf8;
2534 data[pos+2] = (pixel << 3) & 0xf8;
2535 } else if (bpp == 16)
2536 {
2537 data[pos] = (pixel >> 8) & 0xf8;
2538 data[pos+1] = (pixel >> 3) & 0xfc;
2539 data[pos+2] = (pixel << 3) & 0xf8;
2540 } else
2541 {
2542 data[pos] = (pixel >> 16) & 0xff;
2543 data[pos+1] = (pixel >> 8) & 0xff;
2544 data[pos+2] = pixel & 0xff;
2545 }
c7abc967 2546
dbda9e86 2547 /*
38274997
RR
2548 if (gdk_image_mask)
2549 {
dbda9e86
JS
2550 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2551 if (mask_pixel == 0)
2552 {
2553 data[pos] = 16;
2554 data[pos+1] = 16;
2555 data[pos+2] = 16;
38274997 2556 }
dbda9e86
JS
2557 }
2558 */
c7abc967 2559
38274997
RR
2560 pos += 3;
2561 }
2562 }
c7abc967 2563
38274997 2564 XDestroyImage( ximage );
dbda9e86 2565 /*
38274997 2566 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
dbda9e86 2567 */
ee4c6942
JS
2568}
2569#endif
a91b47e8 2570
004fd0c8
DW
2571#ifdef __WXPM__
2572// OS/2 Presentation manager conversion routings
2573
2574wxBitmap wxImage::ConvertToBitmap() const
2575{
2576 if ( !Ok() )
2577 return wxNullBitmap;
2578 wxBitmap bitmap; // remove
2579// TODO:
2580/*
2581 int sizeLimit = 1024*768*3;
2582
2583 // width and height of the device-dependent bitmap
2584 int width = GetWidth();
2585 int bmpHeight = GetHeight();
2586
2587 // calc the number of bytes per scanline and padding
2588 int bytePerLine = width*3;
2589 int sizeDWORD = sizeof( DWORD );
2590 int lineBoundary = bytePerLine % sizeDWORD;
2591 int padding = 0;
2592 if( lineBoundary > 0 )
2593 {
2594 padding = sizeDWORD - lineBoundary;
2595 bytePerLine += padding;
2596 }
2597 // calc the number of DIBs and heights of DIBs
2598 int numDIB = 1;
2599 int hRemain = 0;
2600 int height = sizeLimit/bytePerLine;
2601 if( height >= bmpHeight )
2602 height = bmpHeight;
2603 else
2604 {
2605 numDIB = bmpHeight / height;
2606 hRemain = bmpHeight % height;
2607 if( hRemain >0 ) numDIB++;
2608 }
2609
2610 // set bitmap parameters
2611 wxBitmap bitmap;
2612 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2613 bitmap.SetWidth( width );
2614 bitmap.SetHeight( bmpHeight );
2615 bitmap.SetDepth( wxDisplayDepth() );
2616
2617 // create a DIB header
2618 int headersize = sizeof(BITMAPINFOHEADER);
2619 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2620 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2621 // Fill in the DIB header
2622 lpDIBh->bmiHeader.biSize = headersize;
2623 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2624 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2625 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2626 // the general formula for biSizeImage:
2627 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2628 lpDIBh->bmiHeader.biPlanes = 1;
2629 lpDIBh->bmiHeader.biBitCount = 24;
2630 lpDIBh->bmiHeader.biCompression = BI_RGB;
2631 lpDIBh->bmiHeader.biClrUsed = 0;
2632 // These seem not really needed for our purpose here.
2633 lpDIBh->bmiHeader.biClrImportant = 0;
2634 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2635 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2636 // memory for DIB data
2637 unsigned char *lpBits;
2638 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2639 if( !lpBits )
2640 {
2641 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2642 free( lpDIBh );
2643 return bitmap;
2644 }
2645
2646 // create and set the device-dependent bitmap
2647 HDC hdc = ::GetDC(NULL);
2648 HDC memdc = ::CreateCompatibleDC( hdc );
2649 HBITMAP hbitmap;
2650 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2651 ::SelectObject( memdc, hbitmap);
2652
2653 // copy image data into DIB data and then into DDB (in a loop)
2654 unsigned char *data = GetData();
2655 int i, j, n;
2656 int origin = 0;
2657 unsigned char *ptdata = data;
2658 unsigned char *ptbits;
2659
2660 for( n=0; n<numDIB; n++ )
2661 {
2662 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2663 {
2664 // redefine height and size of the (possibly) last smaller DIB
2665 // memory is not reallocated
2666 height = hRemain;
2667 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2668 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2669 }
2670 ptbits = lpBits;
2671
2672 for( j=0; j<height; j++ )
2673 {
2674 for( i=0; i<width; i++ )
2675 {
2676 *(ptbits++) = *(ptdata+2);
2677 *(ptbits++) = *(ptdata+1);
2678 *(ptbits++) = *(ptdata );
2679 ptdata += 3;
2680 }
2681 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2682 }
2683 ::StretchDIBits( memdc, 0, origin, width, height,\
2684 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2685 origin += height;
2686 // if numDIB = 1, lines below can also be used
2687 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2688 // The above line is equivalent to the following two lines.
2689 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2690 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2691 // or the following lines
2692 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2693 // HDC memdc = ::CreateCompatibleDC( hdc );
2694 // ::SelectObject( memdc, hbitmap);
2695 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2696 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2697 // ::SelectObject( memdc, 0 );
2698 // ::DeleteDC( memdc );
2699 }
2700 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2701
2702 // similarly, created an mono-bitmap for the possible mask
2703 if( HasMask() )
2704 {
2705 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2706 ::SelectObject( memdc, hbitmap);
2707 if( numDIB == 1 ) height = bmpHeight;
2708 else height = sizeLimit/bytePerLine;
2709 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2710 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2711 origin = 0;
2712 unsigned char r = GetMaskRed();
2713 unsigned char g = GetMaskGreen();
2714 unsigned char b = GetMaskBlue();
2715 unsigned char zero = 0, one = 255;
2716 ptdata = data;
2717 for( n=0; n<numDIB; n++ )
2718 {
2719 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2720 {
2721 // redefine height and size of the (possibly) last smaller DIB
2722 // memory is not reallocated
2723 height = hRemain;
2724 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2725 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2726 }
2727 ptbits = lpBits;
2728 for( int j=0; j<height; j++ )
2729 {
2730 for(i=0; i<width; i++ )
2731 {
2732 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2733 {
2734 *(ptbits++) = one;
2735 *(ptbits++) = one;
2736 *(ptbits++) = one;
2737 }
2738 else
2739 {
2740 *(ptbits++) = zero;
2741 *(ptbits++) = zero;
2742 *(ptbits++) = zero;
2743 }
2744 }
2745 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2746 }
2747 ::StretchDIBits( memdc, 0, origin, width, height,\
2748 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2749 origin += height;
2750 }
2751 // create a wxMask object
2752 wxMask *mask = new wxMask();
2753 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2754 bitmap.SetMask( mask );
2755 }
2756
2757 // free allocated resources
2758 ::SelectObject( memdc, 0 );
2759 ::DeleteDC( memdc );
2760 ::ReleaseDC(NULL, hdc);
2761 free(lpDIBh);
2762 free(lpBits);
2763
2764 // check the wxBitmap object
2765 if( bitmap.GetHBITMAP() )
2766 bitmap.SetOk( TRUE );
2767 else
2768 bitmap.SetOk( FALSE );
2769*/
2770 return bitmap;
2771}
2772
2773wxImage::wxImage( const wxBitmap &bitmap )
2774{
2775 // check the bitmap
2776 if( !bitmap.Ok() )
2777 {
2778 wxFAIL_MSG( wxT("invalid bitmap") );
2779 return;
2780 }
2781
2782 // create an wxImage object
2783 int width = bitmap.GetWidth();
2784 int height = bitmap.GetHeight();
2785 Create( width, height );
2786 unsigned char *data = GetData();
2787 if( !data )
2788 {
2789 wxFAIL_MSG( wxT("could not allocate data for image") );
2790 return;
2791 }
2792
2793 // calc the number of bytes per scanline and padding in the DIB
2794 int bytePerLine = width*3;
2795 int sizeDWORD = sizeof( DWORD );
2796 int lineBoundary = bytePerLine % sizeDWORD;
2797 int padding = 0;
2798 if( lineBoundary > 0 )
2799 {
2800 padding = sizeDWORD - lineBoundary;
2801 bytePerLine += padding;
2802 }
2803// TODO:
2804/*
2805 // create a DIB header
2806 int headersize = sizeof(BITMAPINFOHEADER);
2807 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2808 if( !lpDIBh )
2809 {
2810 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2811 free( data );
2812 return;
2813 }
2814 // Fill in the DIB header
2815 lpDIBh->bmiHeader.biSize = headersize;
2816 lpDIBh->bmiHeader.biWidth = width;
2817 lpDIBh->bmiHeader.biHeight = -height;
2818 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2819 lpDIBh->bmiHeader.biPlanes = 1;
2820 lpDIBh->bmiHeader.biBitCount = 24;
2821 lpDIBh->bmiHeader.biCompression = BI_RGB;
2822 lpDIBh->bmiHeader.biClrUsed = 0;
2823 // These seem not really needed for our purpose here.
2824 lpDIBh->bmiHeader.biClrImportant = 0;
2825 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2826 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2827 // memory for DIB data
2828 unsigned char *lpBits;
2829 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2830 if( !lpBits )
2831 {
2832 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2833 free( data );
2834 free( lpDIBh );
2835 return;
2836 }
2837
2838 // copy data from the device-dependent bitmap to the DIB
2839 HDC hdc = ::GetDC(NULL);
2840 HBITMAP hbitmap;
2841 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2842 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2843
2844 // copy DIB data into the wxImage object
2845 int i, j;
2846 unsigned char *ptdata = data;
2847 unsigned char *ptbits = lpBits;
2848 for( i=0; i<height; i++ )
2849 {
2850 for( j=0; j<width; j++ )
2851 {
2852 *(ptdata++) = *(ptbits+2);
2853 *(ptdata++) = *(ptbits+1);
2854 *(ptdata++) = *(ptbits );
2855 ptbits += 3;
2856 }
2857 ptbits += padding;
2858 }
2859
2860 // similarly, set data according to the possible mask bitmap
2861 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2862 {
2863 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2864 // memory DC created, color set, data copied, and memory DC deleted
2865 HDC memdc = ::CreateCompatibleDC( hdc );
2866 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2867 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2868 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2869 ::DeleteDC( memdc );
2870 // background color set to RGB(16,16,16) in consistent with wxGTK
2871 unsigned char r=16, g=16, b=16;
2872 ptdata = data;
2873 ptbits = lpBits;
2874 for( i=0; i<height; i++ )
2875 {
2876 for( j=0; j<width; j++ )
2877 {
2878 if( *ptbits != 0 )
2879 ptdata += 3;
2880 else
2881 {
2882 *(ptdata++) = r;
2883 *(ptdata++) = g;
2884 *(ptdata++) = b;
2885 }
2886 ptbits += 3;
2887 }
2888 ptbits += padding;
2889 }
2890 SetMaskColour( r, g, b );
2891 SetMask( TRUE );
2892 }
2893 else
2894 {
2895 SetMask( FALSE );
2896 }
2897 // free allocated resources
2898 ::ReleaseDC(NULL, hdc);
2899 free(lpDIBh);
2900 free(lpBits);
2901*/
2902}
2903
2904#endif
2905
a91b47e8
JS
2906// A module to allow wxImage initialization/cleanup
2907// without calling these functions from app.cpp or from
2908// the user's application.
2909
2910class wxImageModule: public wxModule
2911{
2912DECLARE_DYNAMIC_CLASS(wxImageModule)
2913public:
2914 wxImageModule() {}
2915 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2916 void OnExit() { wxImage::CleanUpHandlers(); };
2917};
2918
2919IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
c9d01afd
GRG
2920
2921
2922//-----------------------------------------------------------------------------
2923
89d00456
GRG
2924// GRG, Dic/99
2925// Counts and returns the number of different colours. Optionally stops
cc9f7d79
GRG
2926// when it exceeds 'stopafter' different colours. This is useful, for
2927// example, to see if the image can be saved as 8-bit (256 colour or
2928// less, in this case it would be invoked as CountColours(256)). Default
2929// value for stopafter is -1 (don't care).
89d00456 2930//
cc9f7d79 2931unsigned long wxImage::CountColours( unsigned long stopafter )
89d00456
GRG
2932{
2933 wxHashTable h;
ad30de59 2934 wxObject dummy;
89d00456
GRG
2935 unsigned char r, g, b, *p;
2936 unsigned long size, nentries, key;
2937
2938 p = GetData();
2939 size = GetWidth() * GetHeight();
2940 nentries = 0;
2941
cc9f7d79 2942 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
89d00456
GRG
2943 {
2944 r = *(p++);
2945 g = *(p++);
2946 b = *(p++);
2947 key = (r << 16) | (g << 8) | b;
2948
ad30de59 2949 if (h.Get(key) == NULL)
89d00456 2950 {
ad30de59 2951 h.Put(key, &dummy);
89d00456
GRG
2952 nentries++;
2953 }
2954 }
2955
89d00456
GRG
2956 return nentries;
2957}
2958
2959
c9d01afd
GRG
2960// GRG, Dic/99
2961// Computes the histogram of the image and fills a hash table, indexed
2962// with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2963// wxHNode contains an 'index' (useful to build a palette with the image
2964// colours) and a 'value', which is the number of pixels in the image with
2965// that colour.
89d00456 2966//
c9d01afd
GRG
2967unsigned long wxImage::ComputeHistogram( wxHashTable &h )
2968{
2969 unsigned char r, g, b, *p;
2970 unsigned long size, nentries, key;
2971 wxHNode *hnode;
2972
2973 p = GetData();
2974 size = GetWidth() * GetHeight();
2975 nentries = 0;
2976
2977 for (unsigned long j = 0; j < size; j++)
2978 {
2979 r = *(p++);
2980 g = *(p++);
2981 b = *(p++);
2982 key = (r << 16) | (g << 8) | b;
2983
2984 hnode = (wxHNode *) h.Get(key);
2985
2986 if (hnode)
2987 hnode->value++;
2988 else
2989 {
2990 hnode = new wxHNode();
97fdfcc9 2991 hnode->index = nentries++;
c9d01afd
GRG
2992 hnode->value = 1;
2993
2994 h.Put(key, (wxObject *)hnode);
2995 }
2996 }
2997
2998 return nentries;
2999}
3000
7a632f10
JS
3001/*
3002 * Rotation code by Carlos Moreno
3003 */
3004
b5c91ac6
GRG
3005// GRG: I've removed wxRotationPoint - we already have wxRealPoint which
3006// does exactly the same thing. And I also got rid of wxRotationPixel
3007// bacause of potential problems in architectures where alignment
3008// is an issue, so I had to rewrite parts of the code.
7a632f10 3009
7a632f10
JS
3010static const double gs_Epsilon = 1e-10;
3011
3012static inline int wxCint (double x)
3013{
3014 return (x > 0) ? (int) (x + 0.5) : (int) (x - 0.5);
3015}
3016
3017
3018// Auxiliary function to rotate a point (x,y) with respect to point p0
3019// make it inline and use a straight return to facilitate optimization
3020// also, the function receives the sine and cosine of the angle to avoid
3021// repeating the time-consuming calls to these functions -- sin/cos can
3022// be computed and stored in the calling function.
3023
b5c91ac6 3024inline wxRealPoint rotated_point (const wxRealPoint & p, double cos_angle, double sin_angle, const wxRealPoint & p0)
7a632f10 3025{
b5c91ac6
GRG
3026 return wxRealPoint (p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle,
3027 p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle);
7a632f10
JS
3028}
3029
b5c91ac6 3030inline wxRealPoint rotated_point (double x, double y, double cos_angle, double sin_angle, const wxRealPoint & p0)
7a632f10 3031{
b5c91ac6 3032 return rotated_point (wxRealPoint(x,y), cos_angle, sin_angle, p0);
7a632f10
JS
3033}
3034
3035wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const
3036{
7a632f10
JS
3037 int i;
3038 angle = -angle; // screen coordinates are a mirror image of "real" coordinates
3039
ad30de59 3040 // Create pointer-based array to accelerate access to wxImage's data
b5c91ac6 3041 unsigned char ** data = new unsigned char * [GetHeight()];
7a632f10 3042
b5c91ac6 3043 data[0] = GetData();
7a632f10 3044
b5c91ac6
GRG
3045 for (i = 1; i < GetHeight(); i++)
3046 data[i] = data[i - 1] + (3 * GetWidth());
7a632f10 3047
b5c91ac6 3048 // precompute coefficients for rotation formula
ad30de59 3049 // (sine and cosine of the angle)
7a632f10
JS
3050 const double cos_angle = cos(angle);
3051 const double sin_angle = sin(angle);
3052
ad30de59
GRG
3053 // Create new Image to store the result
3054 // First, find rectangle that covers the rotated image; to do that,
3055 // rotate the four corners
7a632f10 3056
b5c91ac6 3057 const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y);
7a632f10 3058
b5c91ac6
GRG
3059 wxRealPoint p1 = rotated_point (0, 0, cos_angle, sin_angle, p0);
3060 wxRealPoint p2 = rotated_point (0, GetHeight(), cos_angle, sin_angle, p0);
3061 wxRealPoint p3 = rotated_point (GetWidth(), 0, cos_angle, sin_angle, p0);
3062 wxRealPoint p4 = rotated_point (GetWidth(), GetHeight(), cos_angle, sin_angle, p0);
7a632f10 3063
57c1c6cb
BJ
3064 int x1 = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x)));
3065 int y1 = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y)));
57c1c6cb
BJ
3066 int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
3067 int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
7a632f10
JS
3068
3069 wxImage rotated (x2 - x1 + 1, y2 - y1 + 1);
3070
3071 if (offset_after_rotation != NULL)
3072 {
06b466c7 3073 *offset_after_rotation = wxPoint (x1, y1);
7a632f10
JS
3074 }
3075
b5c91ac6
GRG
3076 // GRG: The rotated (destination) image is always accessed
3077 // sequentially, so there is no need for a pointer-based
3078 // array here (and in fact it would be slower).
3079 //
3080 unsigned char * dst = rotated.GetData();
7a632f10 3081
ad30de59
GRG
3082 // GRG: if the original image has a mask, use its RGB values
3083 // as the blank pixel, else, fall back to default (black).
3084 //
b5c91ac6
GRG
3085 unsigned char blank_r = 0;
3086 unsigned char blank_g = 0;
3087 unsigned char blank_b = 0;
ad30de59
GRG
3088
3089 if (HasMask())
3090 {
b5c91ac6
GRG
3091 blank_r = GetMaskRed();
3092 blank_g = GetMaskGreen();
3093 blank_b = GetMaskBlue();
3094 rotated.SetMaskColour( blank_r, blank_g, blank_b );
ad30de59
GRG
3095 }
3096
3097 // Now, for each point of the rotated image, find where it came from, by
3098 // performing an inverse rotation (a rotation of -angle) and getting the
3099 // pixel at those coordinates
3100
b5c91ac6
GRG
3101 // GRG: I've taken the (interpolating) test out of the loops, so that
3102 // it is done only once, instead of repeating it for each pixel.
7a632f10
JS
3103
3104 int x;
b5c91ac6 3105 if (interpolating)
7a632f10
JS
3106 {
3107 for (int y = 0; y < rotated.GetHeight(); y++)
3108 {
b5c91ac6 3109 for (x = 0; x < rotated.GetWidth(); x++)
7a632f10 3110 {
b5c91ac6
GRG
3111 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
3112
f2506310
JS
3113 if (-0.25 < src.x && src.x < GetWidth() - 0.75 &&
3114 -0.25 < src.y && src.y < GetHeight() - 0.75)
7a632f10 3115 {
ad30de59
GRG
3116 // interpolate using the 4 enclosing grid-points. Those
3117 // points can be obtained using floor and ceiling of the
3118 // exact coordinates of the point
f2506310 3119 // C.M. 2000-02-17: when the point is near the border, special care is required.
7a632f10 3120
f2506310
JS
3121 int x1, y1, x2, y2;
3122
3123 if (0 < src.x && src.x < GetWidth() - 1)
3124 {
3125 x1 = wxCint(floor(src.x));
3126 x2 = wxCint(ceil(src.x));
3127 }
3128 else // else means that x is near one of the borders (0 or width-1)
3129 {
3130 x1 = x2 = wxCint (src.x);
3131 }
3132
3133 if (0 < src.y && src.y < GetHeight() - 1)
3134 {
3135 y1 = wxCint(floor(src.y));
3136 y2 = wxCint(ceil(src.y));
3137 }
3138 else
3139 {
3140 y1 = y2 = wxCint (src.y);
3141 }
7a632f10 3142
ad30de59
GRG
3143 // get four points and the distances (square of the distance,
3144 // for efficiency reasons) for the interpolation formula
b5c91ac6
GRG
3145
3146 // GRG: Do not calculate the points until they are
3147 // really needed -- this way we can calculate
3148 // just one, instead of four, if d1, d2, d3
3149 // or d4 are < gs_Epsilon
7a632f10
JS
3150
3151 const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1);
3152 const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1);
3153 const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2);
3154 const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2);
3155
ad30de59
GRG
3156 // Now interpolate as a weighted average of the four surrounding
3157 // points, where the weights are the distances to each of those points
7a632f10 3158
ad30de59
GRG
3159 // If the point is exactly at one point of the grid of the source
3160 // image, then don't interpolate -- just assign the pixel
7a632f10 3161
06b466c7 3162 if (d1 < gs_Epsilon) // d1,d2,d3,d4 are positive -- no need for abs()
7a632f10 3163 {
b5c91ac6
GRG
3164 unsigned char *p = data[y1] + (3 * x1);
3165 *(dst++) = *(p++);
3166 *(dst++) = *(p++);
3167 *(dst++) = *(p++);
7a632f10
JS
3168 }
3169 else if (d2 < gs_Epsilon)
3170 {
b5c91ac6
GRG
3171 unsigned char *p = data[y1] + (3 * x2);
3172 *(dst++) = *(p++);
3173 *(dst++) = *(p++);
3174 *(dst++) = *(p++);
7a632f10
JS
3175 }
3176 else if (d3 < gs_Epsilon)
3177 {
b5c91ac6
GRG
3178 unsigned char *p = data[y2] + (3 * x2);
3179 *(dst++) = *(p++);
3180 *(dst++) = *(p++);
3181 *(dst++) = *(p++);
7a632f10
JS
3182 }
3183 else if (d4 < gs_Epsilon)
3184 {
b5c91ac6
GRG
3185 unsigned char *p = data[y2] + (3 * x1);
3186 *(dst++) = *(p++);
3187 *(dst++) = *(p++);
3188 *(dst++) = *(p++);
7a632f10
JS
3189 }
3190 else
3191 {
06b466c7 3192 // weights for the weighted average are proportional to the inverse of the distance
b5c91ac6
GRG
3193 unsigned char *v1 = data[y1] + (3 * x1);
3194 unsigned char *v2 = data[y1] + (3 * x2);
3195 unsigned char *v3 = data[y2] + (3 * x2);
3196 unsigned char *v4 = data[y2] + (3 * x1);
3197
06b466c7
VZ
3198 const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4;
3199
b5c91ac6
GRG
3200 // GRG: Unrolled.
3201
3202 *(dst++) = (unsigned char)
3203 ( (w1 * *(v1++) + w2 * *(v2++) +
3204 w3 * *(v3++) + w4 * *(v4++)) /
3205 (w1 + w2 + w3 + w4) );
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) );
7a632f10
JS
3214 }
3215 }
3216 else
3217 {
b5c91ac6
GRG
3218 *(dst++) = blank_r;
3219 *(dst++) = blank_g;
3220 *(dst++) = blank_b;
7a632f10
JS
3221 }
3222 }
b5c91ac6
GRG
3223 }
3224 }
3225 else // not interpolating
3226 {
3227 for (int y = 0; y < rotated.GetHeight(); y++)
3228 {
3229 for (x = 0; x < rotated.GetWidth(); x++)
7a632f10 3230 {
b5c91ac6
GRG
3231 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
3232
3233 const int xs = wxCint (src.x); // wxCint rounds to the
457e6c54 3234 const int ys = wxCint (src.y); // closest integer
7a632f10 3235
b5c91ac6
GRG
3236 if (0 <= xs && xs < GetWidth() &&
3237 0 <= ys && ys < GetHeight())
7a632f10 3238 {
b5c91ac6
GRG
3239 unsigned char *p = data[ys] + (3 * xs);
3240 *(dst++) = *(p++);
3241 *(dst++) = *(p++);
3242 *(dst++) = *(p++);
7a632f10
JS
3243 }
3244 else
3245 {
b5c91ac6
GRG
3246 *(dst++) = blank_r;
3247 *(dst++) = blank_g;
3248 *(dst++) = blank_b;
7a632f10
JS
3249 }
3250 }
3251 }
3252 }
3253
4aff28fc 3254 delete [] data;
4aff28fc 3255
7a632f10
JS
3256 return rotated;
3257}
c9d01afd 3258