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