]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
I moved platform specific code from wxImage to wxBitmap
[wxWidgets.git] / src / common / image.cpp
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
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/image.h"
22 #include "wx/bitmap.h"
23 #include "wx/debug.h"
24 #include "wx/log.h"
25 #include "wx/app.h"
26 #include "wx/filefn.h"
27 #include "wx/wfstream.h"
28 #include "wx/intl.h"
29 #include "wx/module.h"
30
31 // For memcpy
32 #include <string.h>
33 #include <math.h>
34
35 #ifdef __SALFORDC__
36 #undef FAR
37 #endif
38
39 #ifdef __WXMSW__
40 #include "wx/msw/private.h"
41 #endif
42
43 //-----------------------------------------------------------------------------
44 // wxImage
45 //-----------------------------------------------------------------------------
46
47 class wxImageRefData: public wxObjectRefData
48 {
49 public:
50 wxImageRefData();
51 ~wxImageRefData();
52
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;
59 bool m_static;
60 wxPalette m_palette;
61 wxArrayString m_optionNames;
62 wxArrayString m_optionValues;
63 };
64
65 wxImageRefData::wxImageRefData()
66 {
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;
75 m_static = FALSE;
76 }
77
78 wxImageRefData::~wxImageRefData()
79 {
80 if (m_data && !m_static)
81 free( m_data );
82 }
83
84 wxList wxImage::sm_handlers;
85
86 //-----------------------------------------------------------------------------
87
88 #define M_IMGDATA ((wxImageRefData *)m_refData)
89
90 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
91
92 wxImage::wxImage()
93 {
94 }
95
96 wxImage::wxImage( int width, int height )
97 {
98 Create( width, height );
99 }
100
101 wxImage::wxImage( int width, int height, unsigned char* data, bool static_data )
102 {
103 Create( width, height, data, static_data );
104 }
105
106 wxImage::wxImage( const wxString& name, long type )
107 {
108 LoadFile( name, type );
109 }
110
111 wxImage::wxImage( const wxString& name, const wxString& mimetype )
112 {
113 LoadFile( name, mimetype );
114 }
115
116 #if wxUSE_STREAMS
117 wxImage::wxImage( wxInputStream& stream, long type )
118 {
119 LoadFile( stream, type );
120 }
121
122 wxImage::wxImage( wxInputStream& stream, const wxString& mimetype )
123 {
124 LoadFile( stream, mimetype );
125 }
126 #endif // wxUSE_STREAMS
127
128 wxImage::wxImage( const wxImage& image )
129 {
130 Ref(image);
131 }
132
133 wxImage::wxImage( const wxImage* image )
134 {
135 if (image) Ref(*image);
136 }
137
138 void wxImage::Create( int width, int height )
139 {
140 UnRef();
141
142 m_refData = new wxImageRefData();
143
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;
148
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 }
157 }
158
159 void 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
179 void wxImage::Destroy()
180 {
181 UnRef();
182 }
183
184 wxImage 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
204 wxImage wxImage::Scale( int width, int height ) const
205 {
206 wxImage image;
207
208 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
209
210 wxCHECK_MSG( (width > 0) && (height > 0), image, wxT("invalid image size") );
211
212 image.Create( width, height );
213
214 char unsigned *data = image.GetData();
215
216 wxCHECK_MSG( data, image, wxT("unable to create image") );
217
218 if (M_IMGDATA->m_hasMask)
219 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
220
221 long old_height = M_IMGDATA->m_height;
222 long old_width = M_IMGDATA->m_width;
223
224 char unsigned *source_data = M_IMGDATA->m_data;
225 char unsigned *target_data = data;
226
227 for (long j = 0; j < height; j++)
228 {
229 long y_offset = (j * old_height / height) * old_width;
230
231 for (long i = 0; i < width; i++)
232 {
233 memcpy( target_data,
234 source_data + 3*(y_offset + ((i * old_width )/ width)),
235 3 );
236 target_data += 3;
237 }
238 }
239
240 return image;
241 }
242
243 wxImage 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
280 wxImage 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);
320 memcpy( target_data, source_data, (size_t)3*width );
321 source_data += 3*width;
322 }
323 }
324
325 return image;
326 }
327
328 wxImage wxImage::GetSubImage( const wxRect &rect ) const
329 {
330 wxImage image;
331
332 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
333
334 wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()),
335 image, wxT("invalid subimage size") );
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
344 wxCHECK_MSG( subdata, image, wxT("unable to create image") );
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;
352
353 data+=rect.GetTop()*width+subleft;
354
355 for (long j = 0; j < subheight; ++j)
356 {
357 memcpy( subdata, data, subwidth);
358 subdata+=subwidth;
359 data+=width;
360 }
361
362 return image;
363 }
364
365 void wxImage::Paste( const wxImage &image, int x, int y )
366 {
367 wxCHECK_RET( Ok(), wxT("invalid image") );
368 wxCHECK_RET( image.Ok(), wxT("invalid image") );
369
370 int xx = 0;
371 int yy = 0;
372 int width = image.GetWidth();
373 int height = image.GetHeight();
374
375 if (x < 0)
376 {
377 xx = -x;
378 width += x;
379 }
380 if (y < 0)
381 {
382 yy = -y;
383 height += y;
384 }
385
386 if ((x+xx)+width > M_IMGDATA->m_width)
387 width = M_IMGDATA->m_width - (x+xx);
388 if ((y+yy)+height > M_IMGDATA->m_height)
389 height = M_IMGDATA->m_height - (y+yy);
390
391 if (width < 1) return;
392 if (height < 1) return;
393
394 if ((!HasMask() && !image.HasMask()) ||
395 ((HasMask() && image.HasMask() &&
396 (GetMaskRed()==image.GetMaskRed()) &&
397 (GetMaskGreen()==image.GetMaskGreen()) &&
398 (GetMaskBlue()==image.GetMaskBlue()))))
399 {
400 width *= 3;
401 unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth();
402 int source_step = image.GetWidth()*3;
403
404 unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width;
405 int target_step = M_IMGDATA->m_width*3;
406 for (int j = 0; j < height; j++)
407 {
408 memcpy( target_data, source_data, width );
409 source_data += source_step;
410 target_data += target_step;
411 }
412 return;
413 }
414
415 if (!HasMask() && image.HasMask())
416 {
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 }
442 }
443 }
444
445 void 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();
451
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++)
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 }
466 }
467
468 void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
469 {
470 wxCHECK_RET( Ok(), wxT("invalid image") );
471
472 int w = M_IMGDATA->m_width;
473 int h = M_IMGDATA->m_height;
474
475 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
476
477 long pos = (y * w + x) * 3;
478
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
484 unsigned char wxImage::GetRed( int x, int y ) const
485 {
486 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
487
488 int w = M_IMGDATA->m_width;
489 int h = M_IMGDATA->m_height;
490
491 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
492
493 long pos = (y * w + x) * 3;
494
495 return M_IMGDATA->m_data[pos];
496 }
497
498 unsigned char wxImage::GetGreen( int x, int y ) const
499 {
500 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
501
502 int w = M_IMGDATA->m_width;
503 int h = M_IMGDATA->m_height;
504
505 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
506
507 long pos = (y * w + x) * 3;
508
509 return M_IMGDATA->m_data[pos+1];
510 }
511
512 unsigned char wxImage::GetBlue( int x, int y ) const
513 {
514 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
515
516 int w = M_IMGDATA->m_width;
517 int h = M_IMGDATA->m_height;
518
519 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
520
521 long pos = (y * w + x) * 3;
522
523 return M_IMGDATA->m_data[pos+2];
524 }
525
526 bool wxImage::Ok() const
527 {
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;
532 }
533
534 char unsigned *wxImage::GetData() const
535 {
536 wxCHECK_MSG( Ok(), (char unsigned *)NULL, wxT("invalid image") );
537
538 return M_IMGDATA->m_data;
539 }
540
541 void wxImage::SetData( char unsigned *data )
542 {
543 wxCHECK_RET( Ok(), wxT("invalid image") );
544
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;
555
556 UnRef();
557
558 m_refData = newRefData;
559 }
560
561 void 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
589 void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
590 {
591 wxCHECK_RET( Ok(), wxT("invalid image") );
592
593 M_IMGDATA->m_maskRed = r;
594 M_IMGDATA->m_maskGreen = g;
595 M_IMGDATA->m_maskBlue = b;
596 M_IMGDATA->m_hasMask = TRUE;
597 }
598
599 unsigned char wxImage::GetMaskRed() const
600 {
601 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
602
603 return M_IMGDATA->m_maskRed;
604 }
605
606 unsigned char wxImage::GetMaskGreen() const
607 {
608 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
609
610 return M_IMGDATA->m_maskGreen;
611 }
612
613 unsigned char wxImage::GetMaskBlue() const
614 {
615 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
616
617 return M_IMGDATA->m_maskBlue;
618 }
619
620 void wxImage::SetMask( bool mask )
621 {
622 wxCHECK_RET( Ok(), wxT("invalid image") );
623
624 M_IMGDATA->m_hasMask = mask;
625 }
626
627 bool wxImage::HasMask() const
628 {
629 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
630
631 return M_IMGDATA->m_hasMask;
632 }
633
634 int wxImage::GetWidth() const
635 {
636 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
637
638 return M_IMGDATA->m_width;
639 }
640
641 int wxImage::GetHeight() const
642 {
643 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
644
645 return M_IMGDATA->m_height;
646 }
647
648 // Palette functions
649
650 bool wxImage::HasPalette() const
651 {
652 if (!Ok())
653 return FALSE;
654
655 return M_IMGDATA->m_palette.Ok();
656 }
657
658 const wxPalette& wxImage::GetPalette() const
659 {
660 wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") );
661
662 return M_IMGDATA->m_palette;
663 }
664
665 void 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)
673 void 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
690 void wxImage::SetOption(const wxString& name, int value)
691 {
692 wxString valStr;
693 valStr.Printf(wxT("%d"), value);
694 SetOption(name, valStr);
695 }
696
697 wxString 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
708 int wxImage::GetOptionInt(const wxString& name) const
709 {
710 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
711
712 return wxAtoi(GetOption(name));
713 }
714
715 bool 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
722 bool wxImage::LoadFile( const wxString& filename, long type )
723 {
724 #if wxUSE_STREAMS
725 if (wxFileExists(filename))
726 {
727 wxFileInputStream stream(filename);
728 wxBufferedInputStream bstream( stream );
729 return LoadFile(bstream, type);
730 }
731 else
732 {
733 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
734
735 return FALSE;
736 }
737 #else // !wxUSE_STREAMS
738 return FALSE;
739 #endif // wxUSE_STREAMS
740 }
741
742 bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype )
743 {
744 #if wxUSE_STREAMS
745 if (wxFileExists(filename))
746 {
747 wxFileInputStream stream(filename);
748 wxBufferedInputStream bstream( stream );
749 return LoadFile(bstream, mimetype);
750 }
751 else
752 {
753 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
754
755 return FALSE;
756 }
757 #else // !wxUSE_STREAMS
758 return FALSE;
759 #endif // wxUSE_STREAMS
760 }
761
762 bool wxImage::SaveFile( const wxString& filename, int type )
763 {
764 #if wxUSE_STREAMS
765 wxFileOutputStream stream(filename);
766
767 if ( stream.LastError() == wxStream_NOERROR )
768 {
769 wxBufferedOutputStream bstream( stream );
770 return SaveFile(bstream, type);
771 }
772 #endif // wxUSE_STREAMS
773
774 return FALSE;
775 }
776
777 bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype )
778 {
779 #if wxUSE_STREAMS
780 wxFileOutputStream stream(filename);
781
782 if ( stream.LastError() == wxStream_NOERROR )
783 {
784 wxBufferedOutputStream bstream( stream );
785 return SaveFile(bstream, mimetype);
786 }
787 #endif // wxUSE_STREAMS
788
789 return FALSE;
790 }
791
792 bool 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
802 #if wxUSE_STREAMS
803
804 bool wxImage::CanRead( wxInputStream &stream )
805 {
806 wxList &list=GetHandlers();
807
808 for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
809 {
810 wxImageHandler *handler=(wxImageHandler*)node->GetData();
811 if (handler->CanRead( stream ))
812 return TRUE;
813 }
814
815 return FALSE;
816 }
817
818 bool wxImage::LoadFile( wxInputStream& stream, long type )
819 {
820 UnRef();
821
822 m_refData = new wxImageRefData;
823
824 wxImageHandler *handler;
825
826 if (type==wxBITMAP_TYPE_ANY)
827 {
828 wxList &list=GetHandlers();
829
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 );
835
836 }
837
838 wxLogWarning( _("No handler found for image type.") );
839 return FALSE;
840 }
841
842 handler = FindHandler(type);
843
844 if (handler == NULL)
845 {
846 wxLogWarning( _("No image handler for type %d defined."), type );
847
848 return FALSE;
849 }
850
851 return handler->LoadFile( this, stream );
852 }
853
854 bool 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 {
864 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
865
866 return FALSE;
867 }
868
869 return handler->LoadFile( this, stream );
870 }
871
872 bool wxImage::SaveFile( wxOutputStream& stream, int type )
873 {
874 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
875
876 wxImageHandler *handler = FindHandler(type);
877
878 if (handler == NULL)
879 {
880 wxLogWarning( _("No image handler for type %d defined."), type );
881
882 return FALSE;
883 }
884
885 return handler->SaveFile( this, stream );
886 }
887
888 bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype )
889 {
890 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
891
892 wxImageHandler *handler = FindHandlerMime(mimetype);
893
894 if (handler == NULL)
895 {
896 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
897
898 return FALSE;
899 }
900
901 return handler->SaveFile( this, stream );
902 }
903 #endif // wxUSE_STREAMS
904
905 void wxImage::AddHandler( wxImageHandler *handler )
906 {
907 // make sure that the memory will be freed at the program end
908 sm_handlers.DeleteContents(TRUE);
909
910 sm_handlers.Append( handler );
911 }
912
913 void wxImage::InsertHandler( wxImageHandler *handler )
914 {
915 // make sure that the memory will be freed at the program end
916 sm_handlers.DeleteContents(TRUE);
917
918 sm_handlers.Insert( handler );
919 }
920
921 bool wxImage::RemoveHandler( const wxString& name )
922 {
923 wxImageHandler *handler = FindHandler(name);
924 if (handler)
925 {
926 sm_handlers.DeleteObject(handler);
927 return TRUE;
928 }
929 else
930 return FALSE;
931 }
932
933 wxImageHandler *wxImage::FindHandler( const wxString& name )
934 {
935 wxNode *node = sm_handlers.First();
936 while (node)
937 {
938 wxImageHandler *handler = (wxImageHandler*)node->Data();
939 if (handler->GetName().Cmp(name) == 0) return handler;
940
941 node = node->Next();
942 }
943 return (wxImageHandler *)NULL;
944 }
945
946 wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
947 {
948 wxNode *node = sm_handlers.First();
949 while (node)
950 {
951 wxImageHandler *handler = (wxImageHandler*)node->Data();
952 if ( (handler->GetExtension().Cmp(extension) == 0) &&
953 (bitmapType == -1 || handler->GetType() == bitmapType) )
954 return handler;
955 node = node->Next();
956 }
957 return (wxImageHandler*)NULL;
958 }
959
960 wxImageHandler *wxImage::FindHandler( long bitmapType )
961 {
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
972 wxImageHandler *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
984 void wxImage::InitStandardHandlers()
985 {
986 AddHandler( new wxBMPHandler );
987 }
988
989 void wxImage::CleanUpHandlers()
990 {
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 }
1000 }
1001
1002 //-----------------------------------------------------------------------------
1003 // wxImageHandler
1004 //-----------------------------------------------------------------------------
1005
1006 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject)
1007
1008 #if wxUSE_STREAMS
1009 bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
1010 {
1011 return FALSE;
1012 }
1013
1014 bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) )
1015 {
1016 return FALSE;
1017 }
1018
1019 int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
1020 {
1021 return 1;
1022 }
1023
1024 bool wxImageHandler::CanRead( const wxString& name )
1025 {
1026 if (wxFileExists(name))
1027 {
1028 wxFileInputStream stream(name);
1029 return CanRead(stream);
1030 }
1031
1032 else {
1033 wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() );
1034
1035 return FALSE;
1036 }
1037 // return FALSE;
1038 }
1039
1040 #endif // wxUSE_STREAMS
1041
1042 //-----------------------------------------------------------------------------
1043 // MSW conversion routines
1044 //-----------------------------------------------------------------------------
1045
1046 #ifdef __WXMSW__
1047
1048 wxBitmap wxImage::ConvertToBitmap() const
1049 {
1050 if ( !Ok() )
1051 return wxNullBitmap;
1052
1053 // sizeLimit is the MS upper limit for the DIB size
1054 #ifdef WIN32
1055 int sizeLimit = 1024*768*3;
1056 #else
1057 int sizeLimit = 0x7fff ;
1058 #endif
1059
1060 // width and height of the device-dependent bitmap
1061 int width = GetWidth();
1062 int bmpHeight = GetHeight();
1063
1064 // calc the number of bytes per scanline and padding
1065 int bytePerLine = width*3;
1066 int sizeDWORD = sizeof( DWORD );
1067 int lineBoundary = bytePerLine % sizeDWORD;
1068 int padding = 0;
1069 if( lineBoundary > 0 )
1070 {
1071 padding = sizeDWORD - lineBoundary;
1072 bytePerLine += padding;
1073 }
1074 // calc the number of DIBs and heights of DIBs
1075 int numDIB = 1;
1076 int hRemain = 0;
1077 int height = sizeLimit/bytePerLine;
1078 if( height >= bmpHeight )
1079 height = bmpHeight;
1080 else
1081 {
1082 numDIB = bmpHeight / height;
1083 hRemain = bmpHeight % height;
1084 if( hRemain >0 ) numDIB++;
1085 }
1086
1087 // set bitmap parameters
1088 wxBitmap bitmap;
1089 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1090 bitmap.SetWidth( width );
1091 bitmap.SetHeight( bmpHeight );
1092 bitmap.SetDepth( wxDisplayDepth() );
1093
1094 // create a DIB header
1095 int headersize = sizeof(BITMAPINFOHEADER);
1096 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
1097 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
1098 // Fill in the DIB header
1099 lpDIBh->bmiHeader.biSize = headersize;
1100 lpDIBh->bmiHeader.biWidth = (DWORD)width;
1101 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1102 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1103 // the general formula for biSizeImage:
1104 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
1105 lpDIBh->bmiHeader.biPlanes = 1;
1106 lpDIBh->bmiHeader.biBitCount = 24;
1107 lpDIBh->bmiHeader.biCompression = BI_RGB;
1108 lpDIBh->bmiHeader.biClrUsed = 0;
1109 // These seem not really needed for our purpose here.
1110 lpDIBh->bmiHeader.biClrImportant = 0;
1111 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1112 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1113 // memory for DIB data
1114 unsigned char *lpBits;
1115 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
1116 if( !lpBits )
1117 {
1118 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
1119 free( lpDIBh );
1120 return bitmap;
1121 }
1122
1123 // create and set the device-dependent bitmap
1124 HDC hdc = ::GetDC(NULL);
1125 HDC memdc = ::CreateCompatibleDC( hdc );
1126 HBITMAP hbitmap;
1127 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
1128 ::SelectObject( memdc, hbitmap);
1129
1130 HPALETTE hOldPalette = 0;
1131 if (GetPalette().Ok())
1132 {
1133 hOldPalette = ::SelectPalette(memdc, (HPALETTE) GetPalette().GetHPALETTE(), FALSE);
1134 ::RealizePalette(memdc);
1135 }
1136
1137 // copy image data into DIB data and then into DDB (in a loop)
1138 unsigned char *data = GetData();
1139 int i, j, n;
1140 int origin = 0;
1141 unsigned char *ptdata = data;
1142 unsigned char *ptbits;
1143
1144 for( n=0; n<numDIB; n++ )
1145 {
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
1150 height = hRemain;
1151 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1152 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1153 }
1154 ptbits = lpBits;
1155
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;
1164 }
1165 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
1166 }
1167 ::StretchDIBits( memdc, 0, origin, width, height,\
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 );
1178 // ::SelectObject( memdc, hbitmap);
1179 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1180 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1181 // ::SelectObject( memdc, 0 );
1182 // ::DeleteDC( memdc );
1183 }
1184 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
1185
1186 if (hOldPalette)
1187 SelectPalette(memdc, hOldPalette, FALSE);
1188
1189 // similarly, created an mono-bitmap for the possible mask
1190 if( HasMask() )
1191 {
1192 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
1193 HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap);
1194 if( numDIB == 1 ) height = bmpHeight;
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 {
1208 // redefine height and size of the (possibly) last smaller DIB
1209 // memory is not reallocated
1210 height = hRemain;
1211 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1212 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1213 }
1214 ptbits = lpBits;
1215 for( int j=0; j<height; j++ )
1216 {
1217 for(i=0; i<width; i++ )
1218 {
1219 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
1220 unsigned char cr = (*(ptdata++)) ;
1221 unsigned char cg = (*(ptdata++)) ;
1222 unsigned char cb = (*(ptdata++)) ;
1223
1224 if( ( cr !=r) || (cg!=g) || (cb!=b) )
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 }
1237 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
1238 }
1239 ::StretchDIBits( memdc, 0, origin, width, height,\
1240 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1241 origin += height;
1242 }
1243 // create a wxMask object
1244 wxMask *mask = new wxMask();
1245 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
1246 bitmap.SetMask( mask );
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
1249 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1250 wxMask *mask = new wxMask( bitmap, colour );
1251 bitmap.SetMask( mask );
1252 */
1253
1254 ::SelectObject( memdc, hbmpOld );
1255 }
1256
1257 // free allocated resources
1258 ::DeleteDC( memdc );
1259 ::ReleaseDC(NULL, hdc);
1260 free(lpDIBh);
1261 free(lpBits);
1262
1263 #if WXWIN_COMPATIBILITY_2
1264 // check the wxBitmap object
1265 bitmap.GetBitmapData()->SetOk();
1266 #endif // WXWIN_COMPATIBILITY_2
1267
1268 return bitmap;
1269 }
1270
1271 wxImage::wxImage( const wxBitmap &bitmap )
1272 {
1273 // check the bitmap
1274 if( !bitmap.Ok() )
1275 {
1276 wxFAIL_MSG( wxT("invalid bitmap") );
1277 return;
1278 }
1279
1280 // create an wxImage object
1281 int width = bitmap.GetWidth();
1282 int height = bitmap.GetHeight();
1283 Create( width, height );
1284 unsigned char *data = GetData();
1285 if( !data )
1286 {
1287 wxFAIL_MSG( wxT("could not allocate data for image") );
1288 return;
1289 }
1290
1291 // calc the number of bytes per scanline and padding in the DIB
1292 int bytePerLine = width*3;
1293 int sizeDWORD = sizeof( DWORD );
1294 int lineBoundary = bytePerLine % sizeDWORD;
1295 int padding = 0;
1296 if( lineBoundary > 0 )
1297 {
1298 padding = sizeDWORD - lineBoundary;
1299 bytePerLine += padding;
1300 }
1301
1302 // create a DIB header
1303 int headersize = sizeof(BITMAPINFOHEADER);
1304 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
1305 if( !lpDIBh )
1306 {
1307 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1308 free( data );
1309 return;
1310 }
1311 // Fill in the DIB header
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;
1320 // These seem not really needed for our purpose here.
1321 lpDIBh->bmiHeader.biClrImportant = 0;
1322 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1323 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1324 // memory for DIB data
1325 unsigned char *lpBits;
1326 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1327 if( !lpBits )
1328 {
1329 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1330 free( data );
1331 free( lpDIBh );
1332 return;
1333 }
1334
1335 // copy data from the device-dependent bitmap to the DIB
1336 HDC hdc = ::GetDC(NULL);
1337 HBITMAP hbitmap;
1338 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1339 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1340
1341 // copy DIB data into the wxImage object
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;
1353 }
1354 ptbits += padding;
1355 }
1356
1357 // similarly, set data according to the possible mask bitmap
1358 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1359 {
1360 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1361 // memory DC created, color set, data copied, and memory DC deleted
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 );
1366 ::DeleteDC( memdc );
1367 // background color set to RGB(16,16,16) in consistent with wxGTK
1368 unsigned char r=16, g=16, b=16;
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 )
1376 ptdata += 3;
1377 else
1378 {
1379 *(ptdata++) = r;
1380 *(ptdata++) = g;
1381 *(ptdata++) = b;
1382 }
1383 ptbits += 3;
1384 }
1385 ptbits += padding;
1386 }
1387 SetMaskColour( r, g, b );
1388 SetMask( TRUE );
1389 }
1390 else
1391 {
1392 SetMask( FALSE );
1393 }
1394 // free allocated resources
1395 ::ReleaseDC(NULL, hdc);
1396 free(lpDIBh);
1397 free(lpBits);
1398 }
1399
1400 #endif
1401
1402 #ifdef __WXMAC__
1403
1404 #ifdef __UNIX__
1405 #include <ApplicationServices/ApplicationServices.h>
1406 #else
1407 #include <PictUtils.h>
1408 #endif
1409
1410 wxBitmap 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
1417
1418 wxBitmap bitmap;
1419
1420 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1421
1422 bitmap.Create( width , height , wxDisplayDepth() ) ;
1423 wxBitmap maskBitmap( width, height, 1);
1424
1425 CGrafPtr origPort ;
1426 GDHandle origDevice ;
1427
1428 LockPixels( GetGWorldPixMap(bitmap.GetHBITMAP()) );
1429 LockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
1430
1431 GetGWorld( &origPort , &origDevice ) ;
1432 SetGWorld( bitmap.GetHBITMAP() , NULL ) ;
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 };
1439
1440 register unsigned char* data = GetData();
1441
1442 int index = 0;
1443 for (int y = 0; y < height; y++)
1444 {
1445 for (int x = 0; x < width; x++)
1446 {
1447 rgb.Set(data[index++], data[index++], data[index++]);
1448 color = rgb.GetPixel();
1449 SetCPixel( x , y , &color ) ;
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 }
1461 }
1462 } // for height
1463
1464 // Create mask
1465 if ( HasMask() ) {
1466 wxMask *mask = new wxMask( maskBitmap );
1467 }
1468
1469 UnlockPixels( GetGWorldPixMap(bitmap.GetHBITMAP()) );
1470 UnlockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
1471 SetGWorld( origPort, origDevice );
1472
1473 return bitmap;
1474 }
1475
1476 wxImage::wxImage( const wxBitmap &bitmap )
1477 {
1478 // check the bitmap
1479 wxCHECK_RET( bitmap.Ok(), wxT("Invalid bitmap") );
1480
1481 // create an wxImage object
1482 int width = bitmap.GetWidth();
1483 int height = bitmap.GetHeight();
1484 Create( width, height );
1485
1486 unsigned char *data = GetData();
1487
1488 wxCHECK_RET( data, wxT("Could not allocate data for image") );
1489
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();
1498
1499 GetGWorld( &origPort, &origDevice );
1500 LockPixels(GetGWorldPixMap(bitmap.GetHBITMAP()));
1501 SetGWorld( bitmap.GetHBITMAP(), NULL);
1502
1503 // Copy data into image
1504 index = 0;
1505 for (int yy = 0; yy < height; yy++)
1506 {
1507 for (int xx = 0; xx < width; xx++)
1508 {
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)
1517 {
1518 if (mask->PointMasked(xx,yy))
1519 {
1520 data[index ] = mask_r;
1521 data[index + 1] = mask_g;
1522 data[index + 2] = mask_b;
1523 }
1524 }
1525 index += 3;
1526 }
1527 }
1528 if (mask)
1529 {
1530 SetMaskColour( mask_r, mask_g, mask_b );
1531 SetMask( true );
1532 }
1533
1534 // Free resources
1535 UnlockPixels(GetGWorldPixMap(bitmap.GetHBITMAP()));
1536 SetGWorld(origPort, origDevice);
1537 }
1538
1539 #endif
1540
1541 //-----------------------------------------------------------------------------
1542 // GTK conversion routines
1543 //-----------------------------------------------------------------------------
1544
1545 #ifdef __WXGTK__
1546
1547 #include <gtk/gtk.h>
1548 #include <gdk/gdk.h>
1549 #include <gdk/gdkx.h>
1550
1551 #if (GTK_MINOR_VERSION > 0)
1552 #include <gdk/gdkrgb.h>
1553 #endif
1554
1555 extern GtkWidget *wxRootWindow;
1556
1557 wxBitmap 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
1569 bitmap.SetBitmap( gdk_pixmap_new( wxRootWindow->window, width, height, 1 ) );
1570
1571 bitmap.SetDepth( 1 );
1572
1573 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1574 wxASSERT( visual );
1575
1576 // Create picture image
1577
1578 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1579
1580 GdkImage *data_image =
1581 gdk_image_new_bitmap( visual, data_data, width, height );
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
1591 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
1592
1593 wxMask *mask = new wxMask();
1594 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
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 }
1624
1625 if ((r == red) && (b == blue) && (g == green))
1626 gdk_image_put_pixel( data_image, x, y, 1 );
1627 else
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
1658 wxBitmap wxImage::ConvertToBitmap() const
1659 {
1660 wxBitmap bitmap;
1661
1662 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1663
1664 int width = GetWidth();
1665 int height = GetHeight();
1666
1667 bitmap.SetHeight( height );
1668 bitmap.SetWidth( width );
1669
1670 bitmap.SetPixmap( gdk_pixmap_new( wxRootWindow->window, width, height, -1 ) );
1671
1672 // Retrieve depth
1673
1674 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1675 wxASSERT( visual );
1676
1677 int bpp = visual->depth;
1678
1679 bitmap.SetDepth( bpp );
1680
1681 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1682 if (bpp < 8) bpp = 8;
1683
1684 #if (GTK_MINOR_VERSION > 0)
1685
1686 if (!HasMask() && (bpp > 8))
1687 {
1688 static bool s_hasInitialized = FALSE;
1689
1690 if (!s_hasInitialized)
1691 {
1692 gdk_rgb_init();
1693 s_hasInitialized = TRUE;
1694 }
1695
1696 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
1697
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 );
1705
1706 gdk_gc_unref( gc );
1707
1708 return bitmap;
1709 }
1710
1711 #endif
1712
1713 // Create picture image
1714
1715 GdkImage *data_image =
1716 gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
1717
1718 // Create mask image
1719
1720 GdkImage *mask_image = (GdkImage*) NULL;
1721
1722 if (HasMask())
1723 {
1724 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1725
1726 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
1727
1728 wxMask *mask = new wxMask();
1729 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
1730
1731 bitmap.SetMask( mask );
1732 }
1733
1734 // Render
1735
1736 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1737 byte_order b_o = RGB;
1738
1739 if (bpp >= 24)
1740 {
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 }
1748
1749 int r_mask = GetMaskRed();
1750 int g_mask = GetMaskGreen();
1751 int b_mask = GetMaskBlue();
1752
1753 unsigned char* data = GetData();
1754
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];
1761 index++;
1762 int g = data[index];
1763 index++;
1764 int b = data[index];
1765 index++;
1766
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 }
1774
1775 switch (bpp)
1776 {
1777 case 8:
1778 {
1779 int pixel = -1;
1780 if (wxTheApp->m_colorCube)
1781 {
1782 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1783 }
1784 else
1785 {
1786 GdkColormap *cmap = gtk_widget_get_default_colormap();
1787 GdkColor *colors = cmap->colors;
1788 int max = 3 * (65536);
1789
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; }
1797 }
1798 }
1799
1800 gdk_image_put_pixel( data_image, x, y, pixel );
1801
1802 break;
1803 }
1804 case 15:
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 }
1810 case 16:
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 }
1816 case 32:
1817 case 24:
1818 {
1819 guint32 pixel = 0;
1820 switch (b_o)
1821 {
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;
1828 }
1829 gdk_image_put_pixel( data_image, x, y, pixel );
1830 }
1831 default: break;
1832 }
1833 } // for
1834 } // for
1835
1836 // Blit picture
1837
1838 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1839
1840 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1841
1842 gdk_image_destroy( data_image );
1843 gdk_gc_unref( data_gc );
1844
1845 // Blit mask
1846
1847 if (HasMask())
1848 {
1849 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1850
1851 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1852
1853 gdk_image_destroy( mask_image );
1854 gdk_gc_unref( mask_gc );
1855 }
1856
1857 return bitmap;
1858 }
1859
1860 wxImage::wxImage( const wxBitmap &bitmap )
1861 {
1862 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
1863
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 }
1880
1881 wxCHECK_RET( gdk_image, wxT("couldn't create image") );
1882
1883 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1884 char unsigned *data = GetData();
1885
1886 if (!data)
1887 {
1888 gdk_image_destroy( gdk_image );
1889 wxFAIL_MSG( wxT("couldn't create image") );
1890 return;
1891 }
1892
1893 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1894 if (bitmap.GetMask())
1895 {
1896 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1897 0, 0,
1898 bitmap.GetWidth(), bitmap.GetHeight() );
1899
1900 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1901 }
1902
1903 int bpp = -1;
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;
1911
1912 if (bitmap.GetPixmap())
1913 {
1914 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1915
1916 if (visual == NULL) visual = gdk_window_get_visual( wxRootWindow->window );
1917 bpp = visual->depth;
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;
1925
1926 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
1927 }
1928 if (bitmap.GetBitmap())
1929 {
1930 bpp = 1;
1931 }
1932
1933
1934 GdkColormap *cmap = gtk_widget_get_default_colormap();
1935
1936 long pos = 0;
1937 for (int j = 0; j < bitmap.GetHeight(); j++)
1938 {
1939 for (int i = 0; i < bitmap.GetWidth(); i++)
1940 {
1941 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
1942 if (bpp == 1)
1943 {
1944 if (pixel == 0)
1945 {
1946 data[pos] = 0;
1947 data[pos+1] = 0;
1948 data[pos+2] = 0;
1949 }
1950 else
1951 {
1952 data[pos] = 255;
1953 data[pos+1] = 255;
1954 data[pos+2] = 255;
1955 }
1956 }
1957 else if (use_shift)
1958 {
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;
1962 }
1963 else if (cmap->colors)
1964 {
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;
1968 }
1969 else
1970 {
1971 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1972 }
1973
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 {
1979 data[pos] = 16;
1980 data[pos+1] = 16;
1981 data[pos+2] = 16;
1982 }
1983 }
1984
1985 pos += 3;
1986 }
1987 }
1988
1989 gdk_image_destroy( gdk_image );
1990 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1991 }
1992
1993 #endif
1994
1995 //-----------------------------------------------------------------------------
1996 // Motif conversion routines
1997 //-----------------------------------------------------------------------------
1998
1999 #ifdef __WXMOTIF__
2000 #ifdef __VMS__
2001 #pragma message disable nosimpint
2002 #endif
2003 #include <Xm/Xm.h>
2004 #ifdef __VMS__
2005 #pragma message enable nosimpint
2006 #endif
2007 #include "wx/utils.h"
2008 #include <math.h>
2009
2010 /*
2011
2012 Date: Wed, 05 Jan 2000 11:45:40 +0100
2013 From: Frits Boel <boel@niob.knaw.nl>
2014 To: julian.smart@ukonline.co.uk
2015 Subject: Patch for Motif ConvertToBitmap
2016
2017 Hi Julian,
2018
2019 I've been working on a wxWin application for image processing. From the
2020 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
2021 till I looked in the source code of image.cpp. I saw that converting a
2022 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
2023 to the 256 colors of the palet. A very time-consuming piece of code!
2024
2025 Because I wanted a faster application, I've made a 'patch' for this. In
2026 short: every pixel of the image is compared to a sorted list with
2027 colors. If the color is found in the list, the palette entry is
2028 returned; if the color is not found, the color palette is searched and
2029 then the palette entry is returned and the color added to the sorted
2030 list.
2031
2032 Maybe there is another method for this, namely changing the palette
2033 itself (if the colors are known, as is the case with tiffs with a
2034 colormap). I did not look at this, maybe someone else did?
2035
2036 The code of the patch is attached, have a look on it, and maybe you will
2037 ship it with the next release of wxMotif?
2038
2039 Regards,
2040
2041 Frits Boel
2042 Software engineer at Hubrecht Laboratory, The Netherlands.
2043
2044 */
2045
2046 class wxSearchColor
2047 {
2048 public:
2049 wxSearchColor( void );
2050 wxSearchColor( int size, XColor *colors );
2051 ~wxSearchColor( void );
2052
2053 int SearchColor( int r, int g, int b );
2054 private:
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
2066 wxSearchColor::wxSearchColor( void )
2067 {
2068 size = 0;
2069 colors = (XColor*) NULL;
2070 color = (unsigned int *) NULL;
2071 entry = (int*) NULL;
2072
2073 bottom = 0;
2074 top = 0;
2075 }
2076
2077 wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
2078 {
2079 int i;
2080 size = size_;
2081 colors = colors_;
2082 color = new unsigned int[size];
2083 entry = new int [size];
2084
2085 for (i = 0; i < size; i++ ) {
2086 entry[i] = -1;
2087 }
2088
2089 bottom = top = ( size >> 1 );
2090 }
2091
2092 wxSearchColor::~wxSearchColor( void )
2093 {
2094 if ( color ) delete color;
2095 if ( entry ) delete entry;
2096 }
2097
2098 int wxSearchColor::SearchColor( int r, int g, int b )
2099 {
2100 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
2101 int begin = bottom;
2102 int end = top;
2103 int middle;
2104
2105 while ( begin <= end ) {
2106
2107 middle = ( begin + end ) >> 1;
2108
2109 if ( value == color[middle] ) {
2110 return( entry[middle] );
2111 } else if ( value < color[middle] ) {
2112 end = middle - 1;
2113 } else {
2114 begin = middle + 1;
2115 }
2116
2117 }
2118
2119 return AddColor( value, middle );
2120 }
2121
2122 int 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
2135 if ( entry[pos] < 0 ) {
2136 color[pos] = value;
2137 entry[pos] = pixel;
2138 } else if ( value < color[pos] ) {
2139
2140 if ( bottom > 0 ) {
2141 for ( i = bottom; i < pos; i++ ) {
2142 color[i-1] = color[i];
2143 entry[i-1] = entry[i];
2144 }
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];
2152 }
2153 top++;
2154 color[pos] = value;
2155 entry[pos] = pixel;
2156 }
2157
2158 } else {
2159
2160 if ( top < size-1 ) {
2161 for ( i = top; i > pos; i-- ) {
2162 color[i+1] = color[i];
2163 entry[i+1] = entry[i];
2164 }
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];
2172 }
2173 bottom--;
2174 color[pos] = value;
2175 entry[pos] = pixel;
2176 }
2177
2178 }
2179
2180 return( pixel );
2181 }
2182
2183 wxBitmap wxImage::ConvertToBitmap() const
2184 {
2185 wxBitmap bitmap;
2186
2187 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2188
2189 int width = GetWidth();
2190 int height = GetHeight();
2191
2192 bitmap.SetHeight( height );
2193 bitmap.SetWidth( width );
2194
2195 Display *dpy = (Display*) wxGetDisplay();
2196 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2197 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
2198
2199 // Create image
2200
2201 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
2202 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
2203
2204 bitmap.Create( width, height, bpp );
2205
2206 // Create mask
2207
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 }
2214
2215 // Retrieve depth info
2216
2217 XVisualInfo vinfo_template;
2218 XVisualInfo *vi;
2219
2220 vinfo_template.visual = vis;
2221 vinfo_template.visualid = XVisualIDFromVisual( vis );
2222 vinfo_template.depth = bpp;
2223 int nitem = 0;
2224
2225 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
2226
2227 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
2228
2229 XFree( vi );
2230
2231 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2232 if (bpp < 8) bpp = 8;
2233
2234 // Render
2235
2236 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
2237 byte_order b_o = RGB;
2238
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 }
2248
2249 int r_mask = GetMaskRed();
2250 int g_mask = GetMaskGreen();
2251 int b_mask = GetMaskBlue();
2252
2253 XColor colors[256];
2254 if (bpp == 8)
2255 {
2256 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
2257
2258 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2259 XQueryColors( dpy, cmap, colors, 256 );
2260 }
2261
2262 wxSearchColor scolor( 256, colors );
2263 unsigned char* data = GetData();
2264
2265 bool hasMask = HasMask();
2266
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];
2273 index++;
2274 int g = data[index];
2275 index++;
2276 int b = data[index];
2277 index++;
2278
2279 if (hasMask)
2280 {
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 );
2285 }
2286
2287 switch (bpp)
2288 {
2289 case 8:
2290 {
2291 #if 0 // Old, slower code
2292 int pixel = -1;
2293 /*
2294 if (wxTheApp->m_colorCube)
2295 {
2296 pixel = wxTheApp->m_colorCube
2297 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2298 }
2299 else
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 */
2314 #endif
2315
2316 // And this is all to get the 'right' color...
2317 int pixel = scolor.SearchColor( r, g, b );
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 }
2350 } // for
2351 } // for
2352
2353 // Blit picture
2354
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 );
2359
2360 XDestroyImage( data_image );
2361 XFreeGC( dpy, gc );
2362
2363 // Blit mask
2364 if (HasMask())
2365 {
2366 wxBitmap maskBitmap(width, height, 1);
2367
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 );
2370
2371 XDestroyImage( mask_image );
2372 XFreeGC( dpy, gcMask );
2373
2374 wxMask* mask = new wxMask;
2375 mask->SetPixmap(maskBitmap.GetPixmap());
2376
2377 bitmap.SetMask(mask);
2378
2379 maskBitmap.SetPixmapNull();
2380 }
2381
2382 return bitmap;
2383 }
2384
2385 wxImage::wxImage( const wxBitmap &bitmap )
2386 {
2387 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
2388
2389 Display *dpy = (Display*) wxGetDisplay();
2390 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2391 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
2392
2393 XImage *ximage = XGetImage( dpy,
2394 (Drawable)bitmap.GetPixmap(),
2395 0, 0,
2396 bitmap.GetWidth(), bitmap.GetHeight(),
2397 AllPlanes, ZPixmap );
2398
2399 wxCHECK_RET( ximage, wxT("couldn't create image") );
2400
2401 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2402 char unsigned *data = GetData();
2403
2404 if (!data)
2405 {
2406 XDestroyImage( ximage );
2407 wxFAIL_MSG( wxT("couldn't create image") );
2408 return;
2409 }
2410
2411 /*
2412 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2413 if (bitmap.GetMask())
2414 {
2415 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2416 0, 0,
2417 bitmap.GetWidth(), bitmap.GetHeight() );
2418
2419 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2420 }
2421 */
2422
2423 // Retrieve depth info
2424
2425 XVisualInfo vinfo_template;
2426 XVisualInfo *vi;
2427
2428 vinfo_template.visual = vis;
2429 vinfo_template.visualid = XVisualIDFromVisual( vis );
2430 vinfo_template.depth = bpp;
2431 int nitem = 0;
2432
2433 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
2434
2435 wxCHECK_RET( vi, wxT("no visual") );
2436
2437 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2438
2439 XFree( vi );
2440
2441 XColor colors[256];
2442 if (bpp == 8)
2443 {
2444 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
2445
2446 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2447 XQueryColors( dpy, cmap, colors, 256 );
2448 }
2449
2450 long pos = 0;
2451 for (int j = 0; j < bitmap.GetHeight(); j++)
2452 {
2453 for (int i = 0; i < bitmap.GetWidth(); i++)
2454 {
2455 int pixel = XGetPixel( ximage, i, j );
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 }
2477
2478 /*
2479 if (gdk_image_mask)
2480 {
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;
2487 }
2488 }
2489 */
2490
2491 pos += 3;
2492 }
2493 }
2494
2495 XDestroyImage( ximage );
2496 /*
2497 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2498 */
2499 }
2500 #endif
2501
2502 #ifdef __WXPM__
2503 // OS/2 Presentation manager conversion routings
2504
2505 wxBitmap 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
2704 wxImage::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
2837 // A module to allow wxImage initialization/cleanup
2838 // without calling these functions from app.cpp or from
2839 // the user's application.
2840
2841 class wxImageModule: public wxModule
2842 {
2843 DECLARE_DYNAMIC_CLASS(wxImageModule)
2844 public:
2845 wxImageModule() {}
2846 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2847 void OnExit() { wxImage::CleanUpHandlers(); };
2848 };
2849
2850 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
2851
2852
2853 //-----------------------------------------------------------------------------
2854
2855 // GRG, Dic/99
2856 // Counts and returns the number of different colours. Optionally stops
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).
2861 //
2862 unsigned long wxImage::CountColours( unsigned long stopafter )
2863 {
2864 wxHashTable h;
2865 wxObject dummy;
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
2873 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
2874 {
2875 r = *(p++);
2876 g = *(p++);
2877 b = *(p++);
2878 key = (r << 16) | (g << 8) | b;
2879
2880 if (h.Get(key) == NULL)
2881 {
2882 h.Put(key, &dummy);
2883 nentries++;
2884 }
2885 }
2886
2887 return nentries;
2888 }
2889
2890
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.
2897 //
2898 unsigned 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();
2922 hnode->index = nentries++;
2923 hnode->value = 1;
2924
2925 h.Put(key, (wxObject *)hnode);
2926 }
2927 }
2928
2929 return nentries;
2930 }
2931
2932 /*
2933 * Rotation code by Carlos Moreno
2934 */
2935
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.
2940
2941 static const double gs_Epsilon = 1e-10;
2942
2943 static 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
2955 inline wxRealPoint rotated_point (const wxRealPoint & p, double cos_angle, double sin_angle, const wxRealPoint & p0)
2956 {
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);
2959 }
2960
2961 inline wxRealPoint rotated_point (double x, double y, double cos_angle, double sin_angle, const wxRealPoint & p0)
2962 {
2963 return rotated_point (wxRealPoint(x,y), cos_angle, sin_angle, p0);
2964 }
2965
2966 wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const
2967 {
2968 int i;
2969 angle = -angle; // screen coordinates are a mirror image of "real" coordinates
2970
2971 // Create pointer-based array to accelerate access to wxImage's data
2972 unsigned char ** data = new unsigned char * [GetHeight()];
2973
2974 data[0] = GetData();
2975
2976 for (i = 1; i < GetHeight(); i++)
2977 data[i] = data[i - 1] + (3 * GetWidth());
2978
2979 // precompute coefficients for rotation formula
2980 // (sine and cosine of the angle)
2981 const double cos_angle = cos(angle);
2982 const double sin_angle = sin(angle);
2983
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
2987
2988 const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y);
2989
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);
2994
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)));
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)));
2999
3000 wxImage rotated (x2 - x1 + 1, y2 - y1 + 1);
3001
3002 if (offset_after_rotation != NULL)
3003 {
3004 *offset_after_rotation = wxPoint (x1, y1);
3005 }
3006
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();
3012
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 //
3016 unsigned char blank_r = 0;
3017 unsigned char blank_g = 0;
3018 unsigned char blank_b = 0;
3019
3020 if (HasMask())
3021 {
3022 blank_r = GetMaskRed();
3023 blank_g = GetMaskGreen();
3024 blank_b = GetMaskBlue();
3025 rotated.SetMaskColour( blank_r, blank_g, blank_b );
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
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.
3034
3035 int x;
3036 if (interpolating)
3037 {
3038 for (int y = 0; y < rotated.GetHeight(); y++)
3039 {
3040 for (x = 0; x < rotated.GetWidth(); x++)
3041 {
3042 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
3043
3044 if (-0.25 < src.x && src.x < GetWidth() - 0.75 &&
3045 -0.25 < src.y && src.y < GetHeight() - 0.75)
3046 {
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
3050 // C.M. 2000-02-17: when the point is near the border, special care is required.
3051
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 }
3073
3074 // get four points and the distances (square of the distance,
3075 // for efficiency reasons) for the interpolation formula
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
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
3087 // Now interpolate as a weighted average of the four surrounding
3088 // points, where the weights are the distances to each of those points
3089
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
3092
3093 if (d1 < gs_Epsilon) // d1,d2,d3,d4 are positive -- no need for abs()
3094 {
3095 unsigned char *p = data[y1] + (3 * x1);
3096 *(dst++) = *(p++);
3097 *(dst++) = *(p++);
3098 *(dst++) = *(p++);
3099 }
3100 else if (d2 < gs_Epsilon)
3101 {
3102 unsigned char *p = data[y1] + (3 * x2);
3103 *(dst++) = *(p++);
3104 *(dst++) = *(p++);
3105 *(dst++) = *(p++);
3106 }
3107 else if (d3 < gs_Epsilon)
3108 {
3109 unsigned char *p = data[y2] + (3 * x2);
3110 *(dst++) = *(p++);
3111 *(dst++) = *(p++);
3112 *(dst++) = *(p++);
3113 }
3114 else if (d4 < gs_Epsilon)
3115 {
3116 unsigned char *p = data[y2] + (3 * x1);
3117 *(dst++) = *(p++);
3118 *(dst++) = *(p++);
3119 *(dst++) = *(p++);
3120 }
3121 else
3122 {
3123 // weights for the weighted average are proportional to the inverse of the distance
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
3129 const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4;
3130
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) );
3145 }
3146 }
3147 else
3148 {
3149 *(dst++) = blank_r;
3150 *(dst++) = blank_g;
3151 *(dst++) = blank_b;
3152 }
3153 }
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++)
3161 {
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
3165 const int ys = wxCint (src.y); // closest integer
3166
3167 if (0 <= xs && xs < GetWidth() &&
3168 0 <= ys && ys < GetHeight())
3169 {
3170 unsigned char *p = data[ys] + (3 * xs);
3171 *(dst++) = *(p++);
3172 *(dst++) = *(p++);
3173 *(dst++) = *(p++);
3174 }
3175 else
3176 {
3177 *(dst++) = blank_r;
3178 *(dst++) = blank_g;
3179 *(dst++) = blank_b;
3180 }
3181 }
3182 }
3183 }
3184
3185 delete [] data;
3186
3187 return rotated;
3188 }
3189