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