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