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