]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
d25fdd0f7fd950e8100c8e5d5690ab5392cb1cf5
[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 HPALETTE hOldPalette = 0;
1024 if (GetPalette().Ok())
1025 {
1026 hOldPalette = ::SelectPalette(memdc, (HPALETTE) GetPalette().GetHPALETTE(), FALSE);
1027 ::RealizePalette(memdc);
1028 }
1029
1030 // copy image data into DIB data and then into DDB (in a loop)
1031 unsigned char *data = GetData();
1032 int i, j, n;
1033 int origin = 0;
1034 unsigned char *ptdata = data;
1035 unsigned char *ptbits;
1036
1037 for( n=0; n<numDIB; n++ )
1038 {
1039 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
1040 {
1041 // redefine height and size of the (possibly) last smaller DIB
1042 // memory is not reallocated
1043 height = hRemain;
1044 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1045 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1046 }
1047 ptbits = lpBits;
1048
1049 for( j=0; j<height; j++ )
1050 {
1051 for( i=0; i<width; i++ )
1052 {
1053 *(ptbits++) = *(ptdata+2);
1054 *(ptbits++) = *(ptdata+1);
1055 *(ptbits++) = *(ptdata );
1056 ptdata += 3;
1057 }
1058 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
1059 }
1060 ::StretchDIBits( memdc, 0, origin, width, height,\
1061 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1062 origin += height;
1063 // if numDIB = 1, lines below can also be used
1064 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
1065 // The above line is equivalent to the following two lines.
1066 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1067 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
1068 // or the following lines
1069 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
1070 // HDC memdc = ::CreateCompatibleDC( hdc );
1071 // ::SelectObject( memdc, hbitmap);
1072 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
1073 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
1074 // ::SelectObject( memdc, 0 );
1075 // ::DeleteDC( memdc );
1076 }
1077 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
1078
1079 if (hOldPalette)
1080 SelectPalette(memdc, hOldPalette, FALSE);
1081
1082 // similarly, created an mono-bitmap for the possible mask
1083 if( HasMask() )
1084 {
1085 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
1086 HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap);
1087 if( numDIB == 1 ) height = bmpHeight;
1088 else height = sizeLimit/bytePerLine;
1089 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1090 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1091 origin = 0;
1092 unsigned char r = GetMaskRed();
1093 unsigned char g = GetMaskGreen();
1094 unsigned char b = GetMaskBlue();
1095 unsigned char zero = 0, one = 255;
1096 ptdata = data;
1097 for( n=0; n<numDIB; n++ )
1098 {
1099 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
1100 {
1101 // redefine height and size of the (possibly) last smaller DIB
1102 // memory is not reallocated
1103 height = hRemain;
1104 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
1105 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
1106 }
1107 ptbits = lpBits;
1108 for( int j=0; j<height; j++ )
1109 {
1110 for(i=0; i<width; i++ )
1111 {
1112 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
1113 unsigned char cr = (*(ptdata++)) ;
1114 unsigned char cg = (*(ptdata++)) ;
1115 unsigned char cb = (*(ptdata++)) ;
1116
1117 if( ( cr !=r) || (cg!=g) || (cb!=b) )
1118 {
1119 *(ptbits++) = one;
1120 *(ptbits++) = one;
1121 *(ptbits++) = one;
1122 }
1123 else
1124 {
1125 *(ptbits++) = zero;
1126 *(ptbits++) = zero;
1127 *(ptbits++) = zero;
1128 }
1129 }
1130 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
1131 }
1132 ::StretchDIBits( memdc, 0, origin, width, height,\
1133 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
1134 origin += height;
1135 }
1136 // create a wxMask object
1137 wxMask *mask = new wxMask();
1138 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
1139 bitmap.SetMask( mask );
1140 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
1141 /* The following can also be used but is slow to run
1142 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1143 wxMask *mask = new wxMask( bitmap, colour );
1144 bitmap.SetMask( mask );
1145 */
1146
1147 ::SelectObject( memdc, hbmpOld );
1148 }
1149
1150 // free allocated resources
1151 ::DeleteDC( memdc );
1152 ::ReleaseDC(NULL, hdc);
1153 free(lpDIBh);
1154 free(lpBits);
1155
1156 #if WXWIN_COMPATIBILITY_2
1157 // check the wxBitmap object
1158 bitmap.GetBitmapData()->SetOk();
1159 #endif // WXWIN_COMPATIBILITY_2
1160
1161 return bitmap;
1162 }
1163
1164 wxImage::wxImage( const wxBitmap &bitmap )
1165 {
1166 // check the bitmap
1167 if( !bitmap.Ok() )
1168 {
1169 wxFAIL_MSG( wxT("invalid bitmap") );
1170 return;
1171 }
1172
1173 // create an wxImage object
1174 int width = bitmap.GetWidth();
1175 int height = bitmap.GetHeight();
1176 Create( width, height );
1177 unsigned char *data = GetData();
1178 if( !data )
1179 {
1180 wxFAIL_MSG( wxT("could not allocate data for image") );
1181 return;
1182 }
1183
1184 // calc the number of bytes per scanline and padding in the DIB
1185 int bytePerLine = width*3;
1186 int sizeDWORD = sizeof( DWORD );
1187 int lineBoundary = bytePerLine % sizeDWORD;
1188 int padding = 0;
1189 if( lineBoundary > 0 )
1190 {
1191 padding = sizeDWORD - lineBoundary;
1192 bytePerLine += padding;
1193 }
1194
1195 // create a DIB header
1196 int headersize = sizeof(BITMAPINFOHEADER);
1197 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
1198 if( !lpDIBh )
1199 {
1200 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1201 free( data );
1202 return;
1203 }
1204 // Fill in the DIB header
1205 lpDIBh->bmiHeader.biSize = headersize;
1206 lpDIBh->bmiHeader.biWidth = width;
1207 lpDIBh->bmiHeader.biHeight = -height;
1208 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1209 lpDIBh->bmiHeader.biPlanes = 1;
1210 lpDIBh->bmiHeader.biBitCount = 24;
1211 lpDIBh->bmiHeader.biCompression = BI_RGB;
1212 lpDIBh->bmiHeader.biClrUsed = 0;
1213 // These seem not really needed for our purpose here.
1214 lpDIBh->bmiHeader.biClrImportant = 0;
1215 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1216 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1217 // memory for DIB data
1218 unsigned char *lpBits;
1219 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1220 if( !lpBits )
1221 {
1222 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1223 free( data );
1224 free( lpDIBh );
1225 return;
1226 }
1227
1228 // copy data from the device-dependent bitmap to the DIB
1229 HDC hdc = ::GetDC(NULL);
1230 HBITMAP hbitmap;
1231 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1232 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1233
1234 // copy DIB data into the wxImage object
1235 int i, j;
1236 unsigned char *ptdata = data;
1237 unsigned char *ptbits = lpBits;
1238 for( i=0; i<height; i++ )
1239 {
1240 for( j=0; j<width; j++ )
1241 {
1242 *(ptdata++) = *(ptbits+2);
1243 *(ptdata++) = *(ptbits+1);
1244 *(ptdata++) = *(ptbits );
1245 ptbits += 3;
1246 }
1247 ptbits += padding;
1248 }
1249
1250 // similarly, set data according to the possible mask bitmap
1251 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1252 {
1253 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1254 // memory DC created, color set, data copied, and memory DC deleted
1255 HDC memdc = ::CreateCompatibleDC( hdc );
1256 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1257 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1258 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1259 ::DeleteDC( memdc );
1260 // background color set to RGB(16,16,16) in consistent with wxGTK
1261 unsigned char r=16, g=16, b=16;
1262 ptdata = data;
1263 ptbits = lpBits;
1264 for( i=0; i<height; i++ )
1265 {
1266 for( j=0; j<width; j++ )
1267 {
1268 if( *ptbits != 0 )
1269 ptdata += 3;
1270 else
1271 {
1272 *(ptdata++) = r;
1273 *(ptdata++) = g;
1274 *(ptdata++) = b;
1275 }
1276 ptbits += 3;
1277 }
1278 ptbits += padding;
1279 }
1280 SetMaskColour( r, g, b );
1281 SetMask( TRUE );
1282 }
1283 else
1284 {
1285 SetMask( FALSE );
1286 }
1287 // free allocated resources
1288 ::ReleaseDC(NULL, hdc);
1289 free(lpDIBh);
1290 free(lpBits);
1291 }
1292
1293 #endif
1294
1295 #ifdef __WXMAC__
1296
1297 #include <PictUtils.h>
1298
1299 extern CTabHandle wxMacCreateColorTable( int numColors ) ;
1300 extern void wxMacDestroyColorTable( CTabHandle colors ) ;
1301 extern void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) ;
1302 extern GWorldPtr wxMacCreateGWorld( int height , int width , int depth ) ;
1303 extern void wxMacDestroyGWorld( GWorldPtr gw ) ;
1304
1305 wxBitmap wxImage::ConvertToBitmap() const
1306 {
1307 // width and height of the device-dependent bitmap
1308 int width = GetWidth();
1309 int height = GetHeight();
1310
1311 // Create picture
1312
1313 wxBitmap bitmap( width , height , wxDisplayDepth() ) ;
1314
1315 // Create mask
1316
1317 if (HasMask())
1318 {
1319 /*
1320 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1321
1322 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1323
1324 wxMask *mask = new wxMask();
1325 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1326
1327 bitmap.SetMask( mask );
1328 */
1329 }
1330
1331 // Render
1332
1333 int r_mask = GetMaskRed();
1334 int g_mask = GetMaskGreen();
1335 int b_mask = GetMaskBlue();
1336
1337 CGrafPtr origPort ;
1338 GDHandle origDevice ;
1339
1340 GetGWorld( &origPort , &origDevice ) ;
1341 SetGWorld( bitmap.GetHBITMAP() , NULL ) ;
1342
1343 register unsigned char* data = GetData();
1344
1345 int index = 0;
1346 for (int y = 0; y < height; y++)
1347 {
1348 for (int x = 0; x < width; x++)
1349 {
1350 unsigned char r = data[index++];
1351 unsigned char g = data[index++];
1352 unsigned char b = data[index++];
1353 RGBColor color ;
1354 color.red = ( r << 8 ) + r ;
1355 color.green = ( g << 8 ) + g ;
1356 color.blue = ( b << 8 ) + b ;
1357 SetCPixel( x , y , &color ) ;
1358 }
1359 } // for height
1360
1361 SetGWorld( origPort , origDevice ) ;
1362
1363 if ( HasMask() )
1364 {
1365 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1366 wxMask *mask = new wxMask( bitmap, colour );
1367 bitmap.SetMask( mask );
1368 }
1369 return bitmap;
1370
1371 }
1372
1373 wxImage::wxImage( const wxBitmap &bitmap )
1374 {
1375 // check the bitmap
1376 if( !bitmap.Ok() )
1377 {
1378 wxFAIL_MSG( "invalid bitmap" );
1379 return;
1380 }
1381
1382 // create an wxImage object
1383 int width = bitmap.GetWidth();
1384 int height = bitmap.GetHeight();
1385 Create( width, height );
1386 /*
1387 unsigned char *data = GetData();
1388 if( !data )
1389 {
1390 wxFAIL_MSG( "could not allocate data for image" );
1391 return;
1392 }
1393
1394 // calc the number of bytes per scanline and padding in the DIB
1395 int bytePerLine = width*3;
1396 int sizeDWORD = sizeof( DWORD );
1397 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1398 int padding = 0;
1399 if( lineBoundary.rem > 0 )
1400 {
1401 padding = sizeDWORD - lineBoundary.rem;
1402 bytePerLine += padding;
1403 }
1404
1405 // create a DIB header
1406 int headersize = sizeof(BITMAPINFOHEADER);
1407 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1408 if( !lpDIBh )
1409 {
1410 wxFAIL_MSG( "could not allocate data for DIB header" );
1411 free( data );
1412 return;
1413 }
1414 // Fill in the DIB header
1415 lpDIBh->bmiHeader.biSize = headersize;
1416 lpDIBh->bmiHeader.biWidth = width;
1417 lpDIBh->bmiHeader.biHeight = -height;
1418 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1419 lpDIBh->bmiHeader.biPlanes = 1;
1420 lpDIBh->bmiHeader.biBitCount = 24;
1421 lpDIBh->bmiHeader.biCompression = BI_RGB;
1422 lpDIBh->bmiHeader.biClrUsed = 0;
1423 // These seem not really needed for our purpose here.
1424 lpDIBh->bmiHeader.biClrImportant = 0;
1425 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1426 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1427 // memory for DIB data
1428 unsigned char *lpBits;
1429 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1430 if( !lpBits )
1431 {
1432 wxFAIL_MSG( "could not allocate data for DIB" );
1433 free( data );
1434 free( lpDIBh );
1435 return;
1436 }
1437
1438 // copy data from the device-dependent bitmap to the DIB
1439 HDC hdc = ::GetDC(NULL);
1440 HBITMAP hbitmap;
1441 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1442 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1443
1444 // copy DIB data into the wxImage object
1445 int i, j;
1446 unsigned char *ptdata = data;
1447 unsigned char *ptbits = lpBits;
1448 for( i=0; i<height; i++ )
1449 {
1450 for( j=0; j<width; j++ )
1451 {
1452 *(ptdata++) = *(ptbits+2);
1453 *(ptdata++) = *(ptbits+1);
1454 *(ptdata++) = *(ptbits );
1455 ptbits += 3;
1456 }
1457 ptbits += padding;
1458 }
1459
1460 // similarly, set data according to the possible mask bitmap
1461 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1462 {
1463 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1464 // memory DC created, color set, data copied, and memory DC deleted
1465 HDC memdc = ::CreateCompatibleDC( hdc );
1466 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1467 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1468 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1469 ::DeleteDC( memdc );
1470 // background color set to RGB(16,16,16) in consistent with wxGTK
1471 unsigned char r=16, g=16, b=16;
1472 ptdata = data;
1473 ptbits = lpBits;
1474 for( i=0; i<height; i++ )
1475 {
1476 for( j=0; j<width; j++ )
1477 {
1478 if( *ptbits != 0 )
1479 ptdata += 3;
1480 else
1481 {
1482 *(ptdata++) = r;
1483 *(ptdata++) = g;
1484 *(ptdata++) = b;
1485 }
1486 ptbits += 3;
1487 }
1488 ptbits += padding;
1489 }
1490 SetMaskColour( r, g, b );
1491 SetMask( TRUE );
1492 }
1493 else
1494 {
1495 SetMask( FALSE );
1496 }
1497 // free allocated resources
1498 ::ReleaseDC(NULL, hdc);
1499 free(lpDIBh);
1500 free(lpBits);
1501 */
1502 }
1503
1504 #endif
1505
1506 //-----------------------------------------------------------------------------
1507 // GTK conversion routines
1508 //-----------------------------------------------------------------------------
1509
1510 #ifdef __WXGTK__
1511
1512 #include <gtk/gtk.h>
1513 #include <gdk/gdk.h>
1514 #include <gdk/gdkx.h>
1515
1516 #if (GTK_MINOR_VERSION > 0)
1517 #include <gdk/gdkrgb.h>
1518 #endif
1519
1520 extern GtkWidget *wxRootWindow;
1521
1522 wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue )
1523 {
1524 wxBitmap bitmap;
1525
1526 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1527
1528 int width = GetWidth();
1529 int height = GetHeight();
1530
1531 bitmap.SetHeight( height );
1532 bitmap.SetWidth( width );
1533
1534 bitmap.SetBitmap( gdk_pixmap_new( wxRootWindow->window, width, height, 1 ) );
1535
1536 bitmap.SetDepth( 1 );
1537
1538 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1539 wxASSERT( visual );
1540
1541 // Create picture image
1542
1543 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1544
1545 GdkImage *data_image =
1546 gdk_image_new_bitmap( visual, data_data, width, height );
1547
1548 // Create mask image
1549
1550 GdkImage *mask_image = (GdkImage*) NULL;
1551
1552 if (HasMask())
1553 {
1554 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1555
1556 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
1557
1558 wxMask *mask = new wxMask();
1559 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
1560
1561 bitmap.SetMask( mask );
1562 }
1563
1564 int r_mask = GetMaskRed();
1565 int g_mask = GetMaskGreen();
1566 int b_mask = GetMaskBlue();
1567
1568 unsigned char* data = GetData();
1569
1570 int index = 0;
1571 for (int y = 0; y < height; y++)
1572 {
1573 for (int x = 0; x < width; x++)
1574 {
1575 int r = data[index];
1576 index++;
1577 int g = data[index];
1578 index++;
1579 int b = data[index];
1580 index++;
1581
1582 if (HasMask())
1583 {
1584 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1585 gdk_image_put_pixel( mask_image, x, y, 1 );
1586 else
1587 gdk_image_put_pixel( mask_image, x, y, 0 );
1588 }
1589
1590 if ((r == red) && (b == blue) && (g == green))
1591 gdk_image_put_pixel( data_image, x, y, 1 );
1592 else
1593 gdk_image_put_pixel( data_image, x, y, 0 );
1594
1595 } // for
1596 } // for
1597
1598 // Blit picture
1599
1600 GdkGC *data_gc = gdk_gc_new( bitmap.GetBitmap() );
1601
1602 gdk_draw_image( bitmap.GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1603
1604 gdk_image_destroy( data_image );
1605 gdk_gc_unref( data_gc );
1606
1607 // Blit mask
1608
1609 if (HasMask())
1610 {
1611 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1612
1613 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1614
1615 gdk_image_destroy( mask_image );
1616 gdk_gc_unref( mask_gc );
1617 }
1618
1619 return bitmap;
1620 }
1621
1622
1623 wxBitmap wxImage::ConvertToBitmap() const
1624 {
1625 wxBitmap bitmap;
1626
1627 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1628
1629 int width = GetWidth();
1630 int height = GetHeight();
1631
1632 bitmap.SetHeight( height );
1633 bitmap.SetWidth( width );
1634
1635 bitmap.SetPixmap( gdk_pixmap_new( wxRootWindow->window, width, height, -1 ) );
1636
1637 // Retrieve depth
1638
1639 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
1640 wxASSERT( visual );
1641
1642 int bpp = visual->depth;
1643
1644 bitmap.SetDepth( bpp );
1645
1646 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1647 if (bpp < 8) bpp = 8;
1648
1649 #if (GTK_MINOR_VERSION > 0)
1650
1651 if (!HasMask() && (bpp > 8))
1652 {
1653 static bool s_hasInitialized = FALSE;
1654
1655 if (!s_hasInitialized)
1656 {
1657 gdk_rgb_init();
1658 s_hasInitialized = TRUE;
1659 }
1660
1661 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
1662
1663 gdk_draw_rgb_image( bitmap.GetPixmap(),
1664 gc,
1665 0, 0,
1666 width, height,
1667 GDK_RGB_DITHER_NONE,
1668 GetData(),
1669 width*3 );
1670
1671 gdk_gc_unref( gc );
1672
1673 return bitmap;
1674 }
1675
1676 #endif
1677
1678 // Create picture image
1679
1680 GdkImage *data_image =
1681 gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
1682
1683 // Create mask image
1684
1685 GdkImage *mask_image = (GdkImage*) NULL;
1686
1687 if (HasMask())
1688 {
1689 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1690
1691 mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
1692
1693 wxMask *mask = new wxMask();
1694 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
1695
1696 bitmap.SetMask( mask );
1697 }
1698
1699 // Render
1700
1701 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1702 byte_order b_o = RGB;
1703
1704 if (bpp >= 24)
1705 {
1706 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1707 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1708 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1709 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1710 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1711 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1712 }
1713
1714 int r_mask = GetMaskRed();
1715 int g_mask = GetMaskGreen();
1716 int b_mask = GetMaskBlue();
1717
1718 unsigned char* data = GetData();
1719
1720 int index = 0;
1721 for (int y = 0; y < height; y++)
1722 {
1723 for (int x = 0; x < width; x++)
1724 {
1725 int r = data[index];
1726 index++;
1727 int g = data[index];
1728 index++;
1729 int b = data[index];
1730 index++;
1731
1732 if (HasMask())
1733 {
1734 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1735 gdk_image_put_pixel( mask_image, x, y, 1 );
1736 else
1737 gdk_image_put_pixel( mask_image, x, y, 0 );
1738 }
1739
1740 switch (bpp)
1741 {
1742 case 8:
1743 {
1744 int pixel = -1;
1745 if (wxTheApp->m_colorCube)
1746 {
1747 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1748 }
1749 else
1750 {
1751 GdkColormap *cmap = gtk_widget_get_default_colormap();
1752 GdkColor *colors = cmap->colors;
1753 int max = 3 * (65536);
1754
1755 for (int i = 0; i < cmap->size; i++)
1756 {
1757 int rdiff = (r << 8) - colors[i].red;
1758 int gdiff = (g << 8) - colors[i].green;
1759 int bdiff = (b << 8) - colors[i].blue;
1760 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1761 if (sum < max) { pixel = i; max = sum; }
1762 }
1763 }
1764
1765 gdk_image_put_pixel( data_image, x, y, pixel );
1766
1767 break;
1768 }
1769 case 15:
1770 {
1771 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1772 gdk_image_put_pixel( data_image, x, y, pixel );
1773 break;
1774 }
1775 case 16:
1776 {
1777 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1778 gdk_image_put_pixel( data_image, x, y, pixel );
1779 break;
1780 }
1781 case 32:
1782 case 24:
1783 {
1784 guint32 pixel = 0;
1785 switch (b_o)
1786 {
1787 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1788 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1789 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1790 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1791 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1792 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1793 }
1794 gdk_image_put_pixel( data_image, x, y, pixel );
1795 }
1796 default: break;
1797 }
1798 } // for
1799 } // for
1800
1801 // Blit picture
1802
1803 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1804
1805 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1806
1807 gdk_image_destroy( data_image );
1808 gdk_gc_unref( data_gc );
1809
1810 // Blit mask
1811
1812 if (HasMask())
1813 {
1814 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1815
1816 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1817
1818 gdk_image_destroy( mask_image );
1819 gdk_gc_unref( mask_gc );
1820 }
1821
1822 return bitmap;
1823 }
1824
1825 wxImage::wxImage( const wxBitmap &bitmap )
1826 {
1827 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
1828
1829 GdkImage *gdk_image = (GdkImage*) NULL;
1830 if (bitmap.GetPixmap())
1831 {
1832 gdk_image = gdk_image_get( bitmap.GetPixmap(),
1833 0, 0,
1834 bitmap.GetWidth(), bitmap.GetHeight() );
1835 } else
1836 if (bitmap.GetBitmap())
1837 {
1838 gdk_image = gdk_image_get( bitmap.GetBitmap(),
1839 0, 0,
1840 bitmap.GetWidth(), bitmap.GetHeight() );
1841 } else
1842 {
1843 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1844 }
1845
1846 wxCHECK_RET( gdk_image, wxT("couldn't create image") );
1847
1848 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1849 char unsigned *data = GetData();
1850
1851 if (!data)
1852 {
1853 gdk_image_destroy( gdk_image );
1854 wxFAIL_MSG( wxT("couldn't create image") );
1855 return;
1856 }
1857
1858 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1859 if (bitmap.GetMask())
1860 {
1861 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1862 0, 0,
1863 bitmap.GetWidth(), bitmap.GetHeight() );
1864
1865 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1866 }
1867
1868 int bpp = -1;
1869 int red_shift_right = 0;
1870 int green_shift_right = 0;
1871 int blue_shift_right = 0;
1872 int red_shift_left = 0;
1873 int green_shift_left = 0;
1874 int blue_shift_left = 0;
1875 bool use_shift = FALSE;
1876
1877 if (bitmap.GetPixmap())
1878 {
1879 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1880
1881 if (visual == NULL) visual = gdk_window_get_visual( wxRootWindow->window );
1882 bpp = visual->depth;
1883 if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1884 red_shift_right = visual->red_shift;
1885 red_shift_left = 8-visual->red_prec;
1886 green_shift_right = visual->green_shift;
1887 green_shift_left = 8-visual->green_prec;
1888 blue_shift_right = visual->blue_shift;
1889 blue_shift_left = 8-visual->blue_prec;
1890
1891 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
1892 }
1893 if (bitmap.GetBitmap())
1894 {
1895 bpp = 1;
1896 }
1897
1898
1899 GdkColormap *cmap = gtk_widget_get_default_colormap();
1900
1901 long pos = 0;
1902 for (int j = 0; j < bitmap.GetHeight(); j++)
1903 {
1904 for (int i = 0; i < bitmap.GetWidth(); i++)
1905 {
1906 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
1907 if (bpp == 1)
1908 {
1909 if (pixel == 0)
1910 {
1911 data[pos] = 0;
1912 data[pos+1] = 0;
1913 data[pos+2] = 0;
1914 }
1915 else
1916 {
1917 data[pos] = 255;
1918 data[pos+1] = 255;
1919 data[pos+2] = 255;
1920 }
1921 }
1922 else if (use_shift)
1923 {
1924 data[pos] = (pixel >> red_shift_right) << red_shift_left;
1925 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1926 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
1927 }
1928 else if (cmap->colors)
1929 {
1930 data[pos] = cmap->colors[pixel].red >> 8;
1931 data[pos+1] = cmap->colors[pixel].green >> 8;
1932 data[pos+2] = cmap->colors[pixel].blue >> 8;
1933 }
1934 else
1935 {
1936 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1937 }
1938
1939 if (gdk_image_mask)
1940 {
1941 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1942 if (mask_pixel == 0)
1943 {
1944 data[pos] = 16;
1945 data[pos+1] = 16;
1946 data[pos+2] = 16;
1947 }
1948 }
1949
1950 pos += 3;
1951 }
1952 }
1953
1954 gdk_image_destroy( gdk_image );
1955 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1956 }
1957
1958 #endif
1959
1960 //-----------------------------------------------------------------------------
1961 // Motif conversion routines
1962 //-----------------------------------------------------------------------------
1963
1964 #ifdef __WXMOTIF__
1965 #ifdef __VMS__
1966 #pragma message disable nosimpint
1967 #endif
1968 #include <Xm/Xm.h>
1969 #ifdef __VMS__
1970 #pragma message enable nosimpint
1971 #endif
1972 #include "wx/utils.h"
1973 #include <math.h>
1974
1975 /*
1976
1977 Date: Wed, 05 Jan 2000 11:45:40 +0100
1978 From: Frits Boel <boel@niob.knaw.nl>
1979 To: julian.smart@ukonline.co.uk
1980 Subject: Patch for Motif ConvertToBitmap
1981
1982 Hi Julian,
1983
1984 I've been working on a wxWin application for image processing. From the
1985 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1986 till I looked in the source code of image.cpp. I saw that converting a
1987 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1988 to the 256 colors of the palet. A very time-consuming piece of code!
1989
1990 Because I wanted a faster application, I've made a 'patch' for this. In
1991 short: every pixel of the image is compared to a sorted list with
1992 colors. If the color is found in the list, the palette entry is
1993 returned; if the color is not found, the color palette is searched and
1994 then the palette entry is returned and the color added to the sorted
1995 list.
1996
1997 Maybe there is another method for this, namely changing the palette
1998 itself (if the colors are known, as is the case with tiffs with a
1999 colormap). I did not look at this, maybe someone else did?
2000
2001 The code of the patch is attached, have a look on it, and maybe you will
2002 ship it with the next release of wxMotif?
2003
2004 Regards,
2005
2006 Frits Boel
2007 Software engineer at Hubrecht Laboratory, The Netherlands.
2008
2009 */
2010
2011 class wxSearchColor
2012 {
2013 public:
2014 wxSearchColor( void );
2015 wxSearchColor( int size, XColor *colors );
2016 ~wxSearchColor( void );
2017
2018 int SearchColor( int r, int g, int b );
2019 private:
2020 int AddColor( unsigned int value, int pos );
2021
2022 int size;
2023 XColor *colors;
2024 unsigned int *color;
2025 int *entry;
2026
2027 int bottom;
2028 int top;
2029 };
2030
2031 wxSearchColor::wxSearchColor( void )
2032 {
2033 size = 0;
2034 colors = (XColor*) NULL;
2035 color = (unsigned int *) NULL;
2036 entry = (int*) NULL;
2037
2038 bottom = 0;
2039 top = 0;
2040 }
2041
2042 wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
2043 {
2044 int i;
2045 size = size_;
2046 colors = colors_;
2047 color = new unsigned int[size];
2048 entry = new int [size];
2049
2050 for (i = 0; i < size; i++ ) {
2051 entry[i] = -1;
2052 }
2053
2054 bottom = top = ( size >> 1 );
2055 }
2056
2057 wxSearchColor::~wxSearchColor( void )
2058 {
2059 if ( color ) delete color;
2060 if ( entry ) delete entry;
2061 }
2062
2063 int wxSearchColor::SearchColor( int r, int g, int b )
2064 {
2065 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
2066 int begin = bottom;
2067 int end = top;
2068 int middle;
2069
2070 while ( begin <= end ) {
2071
2072 middle = ( begin + end ) >> 1;
2073
2074 if ( value == color[middle] ) {
2075 return( entry[middle] );
2076 } else if ( value < color[middle] ) {
2077 end = middle - 1;
2078 } else {
2079 begin = middle + 1;
2080 }
2081
2082 }
2083
2084 return AddColor( value, middle );
2085 }
2086
2087 int wxSearchColor::AddColor( unsigned int value, int pos )
2088 {
2089 int i;
2090 int pixel = -1;
2091 int max = 3 * (65536);
2092 for ( i = 0; i < 256; i++ ) {
2093 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
2094 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
2095 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
2096 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2097 if (sum < max) { pixel = i; max = sum; }
2098 }
2099
2100 if ( entry[pos] < 0 ) {
2101 color[pos] = value;
2102 entry[pos] = pixel;
2103 } else if ( value < color[pos] ) {
2104
2105 if ( bottom > 0 ) {
2106 for ( i = bottom; i < pos; i++ ) {
2107 color[i-1] = color[i];
2108 entry[i-1] = entry[i];
2109 }
2110 bottom--;
2111 color[pos-1] = value;
2112 entry[pos-1] = pixel;
2113 } else if ( top < size-1 ) {
2114 for ( i = top; i >= pos; i-- ) {
2115 color[i+1] = color[i];
2116 entry[i+1] = entry[i];
2117 }
2118 top++;
2119 color[pos] = value;
2120 entry[pos] = pixel;
2121 }
2122
2123 } else {
2124
2125 if ( top < size-1 ) {
2126 for ( i = top; i > pos; i-- ) {
2127 color[i+1] = color[i];
2128 entry[i+1] = entry[i];
2129 }
2130 top++;
2131 color[pos+1] = value;
2132 entry[pos+1] = pixel;
2133 } else if ( bottom > 0 ) {
2134 for ( i = bottom; i < pos; i++ ) {
2135 color[i-1] = color[i];
2136 entry[i-1] = entry[i];
2137 }
2138 bottom--;
2139 color[pos] = value;
2140 entry[pos] = pixel;
2141 }
2142
2143 }
2144
2145 return( pixel );
2146 }
2147
2148 wxBitmap wxImage::ConvertToBitmap() const
2149 {
2150 wxBitmap bitmap;
2151
2152 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2153
2154 int width = GetWidth();
2155 int height = GetHeight();
2156
2157 bitmap.SetHeight( height );
2158 bitmap.SetWidth( width );
2159
2160 Display *dpy = (Display*) wxGetDisplay();
2161 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2162 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
2163
2164 // Create image
2165
2166 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
2167 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
2168
2169 bitmap.Create( width, height, bpp );
2170
2171 // Create mask
2172
2173 XImage *mask_image = (XImage*) NULL;
2174 if (HasMask())
2175 {
2176 mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 );
2177 mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height );
2178 }
2179
2180 // Retrieve depth info
2181
2182 XVisualInfo vinfo_template;
2183 XVisualInfo *vi;
2184
2185 vinfo_template.visual = vis;
2186 vinfo_template.visualid = XVisualIDFromVisual( vis );
2187 vinfo_template.depth = bpp;
2188 int nitem = 0;
2189
2190 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
2191
2192 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
2193
2194 XFree( vi );
2195
2196 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2197 if (bpp < 8) bpp = 8;
2198
2199 // Render
2200
2201 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
2202 byte_order b_o = RGB;
2203
2204 if (bpp >= 24)
2205 {
2206 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
2207 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
2208 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
2209 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
2210 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
2211 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
2212 }
2213
2214 int r_mask = GetMaskRed();
2215 int g_mask = GetMaskGreen();
2216 int b_mask = GetMaskBlue();
2217
2218 XColor colors[256];
2219 if (bpp == 8)
2220 {
2221 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
2222
2223 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2224 XQueryColors( dpy, cmap, colors, 256 );
2225 }
2226
2227 wxSearchColor scolor( 256, colors );
2228 unsigned char* data = GetData();
2229
2230 bool hasMask = HasMask();
2231
2232 int index = 0;
2233 for (int y = 0; y < height; y++)
2234 {
2235 for (int x = 0; x < width; x++)
2236 {
2237 int r = data[index];
2238 index++;
2239 int g = data[index];
2240 index++;
2241 int b = data[index];
2242 index++;
2243
2244 if (hasMask)
2245 {
2246 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2247 XPutPixel( mask_image, x, y, 0 );
2248 else
2249 XPutPixel( mask_image, x, y, 1 );
2250 }
2251
2252 switch (bpp)
2253 {
2254 case 8:
2255 {
2256 #if 0 // Old, slower code
2257 int pixel = -1;
2258 /*
2259 if (wxTheApp->m_colorCube)
2260 {
2261 pixel = wxTheApp->m_colorCube
2262 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2263 }
2264 else
2265 {
2266 */
2267 int max = 3 * (65536);
2268 for (int i = 0; i < 256; i++)
2269 {
2270 int rdiff = (r << 8) - colors[i].red;
2271 int gdiff = (g << 8) - colors[i].green;
2272 int bdiff = (b << 8) - colors[i].blue;
2273 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2274 if (sum < max) { pixel = i; max = sum; }
2275 }
2276 /*
2277 }
2278 */
2279 #endif
2280
2281 // And this is all to get the 'right' color...
2282 int pixel = scolor.SearchColor( r, g, b );
2283 XPutPixel( data_image, x, y, pixel );
2284 break;
2285 }
2286 case 15:
2287 {
2288 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
2289 XPutPixel( data_image, x, y, pixel );
2290 break;
2291 }
2292 case 16:
2293 {
2294 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
2295 XPutPixel( data_image, x, y, pixel );
2296 break;
2297 }
2298 case 32:
2299 case 24:
2300 {
2301 int pixel = 0;
2302 switch (b_o)
2303 {
2304 case RGB: pixel = (r << 16) | (g << 8) | b; break;
2305 case RBG: pixel = (r << 16) | (b << 8) | g; break;
2306 case BRG: pixel = (b << 16) | (r << 8) | g; break;
2307 case BGR: pixel = (b << 16) | (g << 8) | r; break;
2308 case GRB: pixel = (g << 16) | (r << 8) | b; break;
2309 case GBR: pixel = (g << 16) | (b << 8) | r; break;
2310 }
2311 XPutPixel( data_image, x, y, pixel );
2312 }
2313 default: break;
2314 }
2315 } // for
2316 } // for
2317
2318 // Blit picture
2319
2320 XGCValues gcvalues;
2321 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
2322 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
2323 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
2324
2325 XDestroyImage( data_image );
2326 XFreeGC( dpy, gc );
2327
2328 // Blit mask
2329 if (HasMask())
2330 {
2331 wxBitmap maskBitmap(width, height, 1);
2332
2333 GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), (XtGCMask) 0, (XGCValues*)NULL );
2334 XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height );
2335
2336 XDestroyImage( mask_image );
2337 XFreeGC( dpy, gcMask );
2338
2339 wxMask* mask = new wxMask;
2340 mask->SetPixmap(maskBitmap.GetPixmap());
2341
2342 bitmap.SetMask(mask);
2343
2344 maskBitmap.SetPixmapNull();
2345 }
2346
2347 return bitmap;
2348 }
2349
2350 wxImage::wxImage( const wxBitmap &bitmap )
2351 {
2352 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
2353
2354 Display *dpy = (Display*) wxGetDisplay();
2355 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2356 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
2357
2358 XImage *ximage = XGetImage( dpy,
2359 (Drawable)bitmap.GetPixmap(),
2360 0, 0,
2361 bitmap.GetWidth(), bitmap.GetHeight(),
2362 AllPlanes, ZPixmap );
2363
2364 wxCHECK_RET( ximage, wxT("couldn't create image") );
2365
2366 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2367 char unsigned *data = GetData();
2368
2369 if (!data)
2370 {
2371 XDestroyImage( ximage );
2372 wxFAIL_MSG( wxT("couldn't create image") );
2373 return;
2374 }
2375
2376 /*
2377 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2378 if (bitmap.GetMask())
2379 {
2380 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2381 0, 0,
2382 bitmap.GetWidth(), bitmap.GetHeight() );
2383
2384 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2385 }
2386 */
2387
2388 // Retrieve depth info
2389
2390 XVisualInfo vinfo_template;
2391 XVisualInfo *vi;
2392
2393 vinfo_template.visual = vis;
2394 vinfo_template.visualid = XVisualIDFromVisual( vis );
2395 vinfo_template.depth = bpp;
2396 int nitem = 0;
2397
2398 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
2399
2400 wxCHECK_RET( vi, wxT("no visual") );
2401
2402 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2403
2404 XFree( vi );
2405
2406 XColor colors[256];
2407 if (bpp == 8)
2408 {
2409 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
2410
2411 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2412 XQueryColors( dpy, cmap, colors, 256 );
2413 }
2414
2415 long pos = 0;
2416 for (int j = 0; j < bitmap.GetHeight(); j++)
2417 {
2418 for (int i = 0; i < bitmap.GetWidth(); i++)
2419 {
2420 int pixel = XGetPixel( ximage, i, j );
2421 if (bpp <= 8)
2422 {
2423 data[pos] = colors[pixel].red >> 8;
2424 data[pos+1] = colors[pixel].green >> 8;
2425 data[pos+2] = colors[pixel].blue >> 8;
2426 } else if (bpp == 15)
2427 {
2428 data[pos] = (pixel >> 7) & 0xf8;
2429 data[pos+1] = (pixel >> 2) & 0xf8;
2430 data[pos+2] = (pixel << 3) & 0xf8;
2431 } else if (bpp == 16)
2432 {
2433 data[pos] = (pixel >> 8) & 0xf8;
2434 data[pos+1] = (pixel >> 3) & 0xfc;
2435 data[pos+2] = (pixel << 3) & 0xf8;
2436 } else
2437 {
2438 data[pos] = (pixel >> 16) & 0xff;
2439 data[pos+1] = (pixel >> 8) & 0xff;
2440 data[pos+2] = pixel & 0xff;
2441 }
2442
2443 /*
2444 if (gdk_image_mask)
2445 {
2446 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2447 if (mask_pixel == 0)
2448 {
2449 data[pos] = 16;
2450 data[pos+1] = 16;
2451 data[pos+2] = 16;
2452 }
2453 }
2454 */
2455
2456 pos += 3;
2457 }
2458 }
2459
2460 XDestroyImage( ximage );
2461 /*
2462 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2463 */
2464 }
2465 #endif
2466
2467 #ifdef __WXPM__
2468 // OS/2 Presentation manager conversion routings
2469
2470 wxBitmap wxImage::ConvertToBitmap() const
2471 {
2472 if ( !Ok() )
2473 return wxNullBitmap;
2474 wxBitmap bitmap; // remove
2475 // TODO:
2476 /*
2477 int sizeLimit = 1024*768*3;
2478
2479 // width and height of the device-dependent bitmap
2480 int width = GetWidth();
2481 int bmpHeight = GetHeight();
2482
2483 // calc the number of bytes per scanline and padding
2484 int bytePerLine = width*3;
2485 int sizeDWORD = sizeof( DWORD );
2486 int lineBoundary = bytePerLine % sizeDWORD;
2487 int padding = 0;
2488 if( lineBoundary > 0 )
2489 {
2490 padding = sizeDWORD - lineBoundary;
2491 bytePerLine += padding;
2492 }
2493 // calc the number of DIBs and heights of DIBs
2494 int numDIB = 1;
2495 int hRemain = 0;
2496 int height = sizeLimit/bytePerLine;
2497 if( height >= bmpHeight )
2498 height = bmpHeight;
2499 else
2500 {
2501 numDIB = bmpHeight / height;
2502 hRemain = bmpHeight % height;
2503 if( hRemain >0 ) numDIB++;
2504 }
2505
2506 // set bitmap parameters
2507 wxBitmap bitmap;
2508 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2509 bitmap.SetWidth( width );
2510 bitmap.SetHeight( bmpHeight );
2511 bitmap.SetDepth( wxDisplayDepth() );
2512
2513 // create a DIB header
2514 int headersize = sizeof(BITMAPINFOHEADER);
2515 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2516 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2517 // Fill in the DIB header
2518 lpDIBh->bmiHeader.biSize = headersize;
2519 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2520 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2521 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2522 // the general formula for biSizeImage:
2523 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2524 lpDIBh->bmiHeader.biPlanes = 1;
2525 lpDIBh->bmiHeader.biBitCount = 24;
2526 lpDIBh->bmiHeader.biCompression = BI_RGB;
2527 lpDIBh->bmiHeader.biClrUsed = 0;
2528 // These seem not really needed for our purpose here.
2529 lpDIBh->bmiHeader.biClrImportant = 0;
2530 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2531 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2532 // memory for DIB data
2533 unsigned char *lpBits;
2534 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2535 if( !lpBits )
2536 {
2537 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2538 free( lpDIBh );
2539 return bitmap;
2540 }
2541
2542 // create and set the device-dependent bitmap
2543 HDC hdc = ::GetDC(NULL);
2544 HDC memdc = ::CreateCompatibleDC( hdc );
2545 HBITMAP hbitmap;
2546 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2547 ::SelectObject( memdc, hbitmap);
2548
2549 // copy image data into DIB data and then into DDB (in a loop)
2550 unsigned char *data = GetData();
2551 int i, j, n;
2552 int origin = 0;
2553 unsigned char *ptdata = data;
2554 unsigned char *ptbits;
2555
2556 for( n=0; n<numDIB; n++ )
2557 {
2558 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2559 {
2560 // redefine height and size of the (possibly) last smaller DIB
2561 // memory is not reallocated
2562 height = hRemain;
2563 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2564 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2565 }
2566 ptbits = lpBits;
2567
2568 for( j=0; j<height; j++ )
2569 {
2570 for( i=0; i<width; i++ )
2571 {
2572 *(ptbits++) = *(ptdata+2);
2573 *(ptbits++) = *(ptdata+1);
2574 *(ptbits++) = *(ptdata );
2575 ptdata += 3;
2576 }
2577 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2578 }
2579 ::StretchDIBits( memdc, 0, origin, width, height,\
2580 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2581 origin += height;
2582 // if numDIB = 1, lines below can also be used
2583 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2584 // The above line is equivalent to the following two lines.
2585 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2586 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2587 // or the following lines
2588 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2589 // HDC memdc = ::CreateCompatibleDC( hdc );
2590 // ::SelectObject( memdc, hbitmap);
2591 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2592 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2593 // ::SelectObject( memdc, 0 );
2594 // ::DeleteDC( memdc );
2595 }
2596 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2597
2598 // similarly, created an mono-bitmap for the possible mask
2599 if( HasMask() )
2600 {
2601 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2602 ::SelectObject( memdc, hbitmap);
2603 if( numDIB == 1 ) height = bmpHeight;
2604 else height = sizeLimit/bytePerLine;
2605 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2606 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2607 origin = 0;
2608 unsigned char r = GetMaskRed();
2609 unsigned char g = GetMaskGreen();
2610 unsigned char b = GetMaskBlue();
2611 unsigned char zero = 0, one = 255;
2612 ptdata = data;
2613 for( n=0; n<numDIB; n++ )
2614 {
2615 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2616 {
2617 // redefine height and size of the (possibly) last smaller DIB
2618 // memory is not reallocated
2619 height = hRemain;
2620 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2621 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2622 }
2623 ptbits = lpBits;
2624 for( int j=0; j<height; j++ )
2625 {
2626 for(i=0; i<width; i++ )
2627 {
2628 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2629 {
2630 *(ptbits++) = one;
2631 *(ptbits++) = one;
2632 *(ptbits++) = one;
2633 }
2634 else
2635 {
2636 *(ptbits++) = zero;
2637 *(ptbits++) = zero;
2638 *(ptbits++) = zero;
2639 }
2640 }
2641 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2642 }
2643 ::StretchDIBits( memdc, 0, origin, width, height,\
2644 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2645 origin += height;
2646 }
2647 // create a wxMask object
2648 wxMask *mask = new wxMask();
2649 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2650 bitmap.SetMask( mask );
2651 }
2652
2653 // free allocated resources
2654 ::SelectObject( memdc, 0 );
2655 ::DeleteDC( memdc );
2656 ::ReleaseDC(NULL, hdc);
2657 free(lpDIBh);
2658 free(lpBits);
2659
2660 // check the wxBitmap object
2661 if( bitmap.GetHBITMAP() )
2662 bitmap.SetOk( TRUE );
2663 else
2664 bitmap.SetOk( FALSE );
2665 */
2666 return bitmap;
2667 }
2668
2669 wxImage::wxImage( const wxBitmap &bitmap )
2670 {
2671 // check the bitmap
2672 if( !bitmap.Ok() )
2673 {
2674 wxFAIL_MSG( wxT("invalid bitmap") );
2675 return;
2676 }
2677
2678 // create an wxImage object
2679 int width = bitmap.GetWidth();
2680 int height = bitmap.GetHeight();
2681 Create( width, height );
2682 unsigned char *data = GetData();
2683 if( !data )
2684 {
2685 wxFAIL_MSG( wxT("could not allocate data for image") );
2686 return;
2687 }
2688
2689 // calc the number of bytes per scanline and padding in the DIB
2690 int bytePerLine = width*3;
2691 int sizeDWORD = sizeof( DWORD );
2692 int lineBoundary = bytePerLine % sizeDWORD;
2693 int padding = 0;
2694 if( lineBoundary > 0 )
2695 {
2696 padding = sizeDWORD - lineBoundary;
2697 bytePerLine += padding;
2698 }
2699 // TODO:
2700 /*
2701 // create a DIB header
2702 int headersize = sizeof(BITMAPINFOHEADER);
2703 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2704 if( !lpDIBh )
2705 {
2706 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2707 free( data );
2708 return;
2709 }
2710 // Fill in the DIB header
2711 lpDIBh->bmiHeader.biSize = headersize;
2712 lpDIBh->bmiHeader.biWidth = width;
2713 lpDIBh->bmiHeader.biHeight = -height;
2714 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2715 lpDIBh->bmiHeader.biPlanes = 1;
2716 lpDIBh->bmiHeader.biBitCount = 24;
2717 lpDIBh->bmiHeader.biCompression = BI_RGB;
2718 lpDIBh->bmiHeader.biClrUsed = 0;
2719 // These seem not really needed for our purpose here.
2720 lpDIBh->bmiHeader.biClrImportant = 0;
2721 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2722 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2723 // memory for DIB data
2724 unsigned char *lpBits;
2725 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2726 if( !lpBits )
2727 {
2728 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2729 free( data );
2730 free( lpDIBh );
2731 return;
2732 }
2733
2734 // copy data from the device-dependent bitmap to the DIB
2735 HDC hdc = ::GetDC(NULL);
2736 HBITMAP hbitmap;
2737 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2738 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2739
2740 // copy DIB data into the wxImage object
2741 int i, j;
2742 unsigned char *ptdata = data;
2743 unsigned char *ptbits = lpBits;
2744 for( i=0; i<height; i++ )
2745 {
2746 for( j=0; j<width; j++ )
2747 {
2748 *(ptdata++) = *(ptbits+2);
2749 *(ptdata++) = *(ptbits+1);
2750 *(ptdata++) = *(ptbits );
2751 ptbits += 3;
2752 }
2753 ptbits += padding;
2754 }
2755
2756 // similarly, set data according to the possible mask bitmap
2757 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2758 {
2759 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2760 // memory DC created, color set, data copied, and memory DC deleted
2761 HDC memdc = ::CreateCompatibleDC( hdc );
2762 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2763 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2764 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2765 ::DeleteDC( memdc );
2766 // background color set to RGB(16,16,16) in consistent with wxGTK
2767 unsigned char r=16, g=16, b=16;
2768 ptdata = data;
2769 ptbits = lpBits;
2770 for( i=0; i<height; i++ )
2771 {
2772 for( j=0; j<width; j++ )
2773 {
2774 if( *ptbits != 0 )
2775 ptdata += 3;
2776 else
2777 {
2778 *(ptdata++) = r;
2779 *(ptdata++) = g;
2780 *(ptdata++) = b;
2781 }
2782 ptbits += 3;
2783 }
2784 ptbits += padding;
2785 }
2786 SetMaskColour( r, g, b );
2787 SetMask( TRUE );
2788 }
2789 else
2790 {
2791 SetMask( FALSE );
2792 }
2793 // free allocated resources
2794 ::ReleaseDC(NULL, hdc);
2795 free(lpDIBh);
2796 free(lpBits);
2797 */
2798 }
2799
2800 #endif
2801
2802 // A module to allow wxImage initialization/cleanup
2803 // without calling these functions from app.cpp or from
2804 // the user's application.
2805
2806 class wxImageModule: public wxModule
2807 {
2808 DECLARE_DYNAMIC_CLASS(wxImageModule)
2809 public:
2810 wxImageModule() {}
2811 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2812 void OnExit() { wxImage::CleanUpHandlers(); };
2813 };
2814
2815 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
2816
2817
2818 //-----------------------------------------------------------------------------
2819
2820 // GRG, Dic/99
2821 // Counts and returns the number of different colours. Optionally stops
2822 // when it exceeds 'stopafter' different colours. This is useful, for
2823 // example, to see if the image can be saved as 8-bit (256 colour or
2824 // less, in this case it would be invoked as CountColours(256)). Default
2825 // value for stopafter is -1 (don't care).
2826 //
2827 unsigned long wxImage::CountColours( unsigned long stopafter )
2828 {
2829 wxHashTable h;
2830 wxObject dummy;
2831 unsigned char r, g, b, *p;
2832 unsigned long size, nentries, key;
2833
2834 p = GetData();
2835 size = GetWidth() * GetHeight();
2836 nentries = 0;
2837
2838 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
2839 {
2840 r = *(p++);
2841 g = *(p++);
2842 b = *(p++);
2843 key = (r << 16) | (g << 8) | b;
2844
2845 if (h.Get(key) == NULL)
2846 {
2847 h.Put(key, &dummy);
2848 nentries++;
2849 }
2850 }
2851
2852 return nentries;
2853 }
2854
2855
2856 // GRG, Dic/99
2857 // Computes the histogram of the image and fills a hash table, indexed
2858 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2859 // wxHNode contains an 'index' (useful to build a palette with the image
2860 // colours) and a 'value', which is the number of pixels in the image with
2861 // that colour.
2862 //
2863 unsigned long wxImage::ComputeHistogram( wxHashTable &h )
2864 {
2865 unsigned char r, g, b, *p;
2866 unsigned long size, nentries, key;
2867 wxHNode *hnode;
2868
2869 p = GetData();
2870 size = GetWidth() * GetHeight();
2871 nentries = 0;
2872
2873 for (unsigned long j = 0; j < size; j++)
2874 {
2875 r = *(p++);
2876 g = *(p++);
2877 b = *(p++);
2878 key = (r << 16) | (g << 8) | b;
2879
2880 hnode = (wxHNode *) h.Get(key);
2881
2882 if (hnode)
2883 hnode->value++;
2884 else
2885 {
2886 hnode = new wxHNode();
2887 hnode->index = nentries++;
2888 hnode->value = 1;
2889
2890 h.Put(key, (wxObject *)hnode);
2891 }
2892 }
2893
2894 return nentries;
2895 }
2896
2897 /*
2898 * Rotation code by Carlos Moreno
2899 */
2900
2901 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2902 // does exactly the same thing. And I also got rid of wxRotationPixel
2903 // bacause of potential problems in architectures where alignment
2904 // is an issue, so I had to rewrite parts of the code.
2905
2906 static const double gs_Epsilon = 1e-10;
2907
2908 static inline int wxCint (double x)
2909 {
2910 return (x > 0) ? (int) (x + 0.5) : (int) (x - 0.5);
2911 }
2912
2913
2914 // Auxiliary function to rotate a point (x,y) with respect to point p0
2915 // make it inline and use a straight return to facilitate optimization
2916 // also, the function receives the sine and cosine of the angle to avoid
2917 // repeating the time-consuming calls to these functions -- sin/cos can
2918 // be computed and stored in the calling function.
2919
2920 inline wxRealPoint rotated_point (const wxRealPoint & p, double cos_angle, double sin_angle, const wxRealPoint & p0)
2921 {
2922 return wxRealPoint (p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle,
2923 p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle);
2924 }
2925
2926 inline wxRealPoint rotated_point (double x, double y, double cos_angle, double sin_angle, const wxRealPoint & p0)
2927 {
2928 return rotated_point (wxRealPoint(x,y), cos_angle, sin_angle, p0);
2929 }
2930
2931 wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const
2932 {
2933 int i;
2934 angle = -angle; // screen coordinates are a mirror image of "real" coordinates
2935
2936 // Create pointer-based array to accelerate access to wxImage's data
2937 unsigned char ** data = new unsigned char * [GetHeight()];
2938
2939 data[0] = GetData();
2940
2941 for (i = 1; i < GetHeight(); i++)
2942 data[i] = data[i - 1] + (3 * GetWidth());
2943
2944 // precompute coefficients for rotation formula
2945 // (sine and cosine of the angle)
2946 const double cos_angle = cos(angle);
2947 const double sin_angle = sin(angle);
2948
2949 // Create new Image to store the result
2950 // First, find rectangle that covers the rotated image; to do that,
2951 // rotate the four corners
2952
2953 const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y);
2954
2955 wxRealPoint p1 = rotated_point (0, 0, cos_angle, sin_angle, p0);
2956 wxRealPoint p2 = rotated_point (0, GetHeight(), cos_angle, sin_angle, p0);
2957 wxRealPoint p3 = rotated_point (GetWidth(), 0, cos_angle, sin_angle, p0);
2958 wxRealPoint p4 = rotated_point (GetWidth(), GetHeight(), cos_angle, sin_angle, p0);
2959
2960 int x1 = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x)));
2961 int y1 = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y)));
2962 int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
2963 int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
2964
2965 wxImage rotated (x2 - x1 + 1, y2 - y1 + 1);
2966
2967 if (offset_after_rotation != NULL)
2968 {
2969 *offset_after_rotation = wxPoint (x1, y1);
2970 }
2971
2972 // GRG: The rotated (destination) image is always accessed
2973 // sequentially, so there is no need for a pointer-based
2974 // array here (and in fact it would be slower).
2975 //
2976 unsigned char * dst = rotated.GetData();
2977
2978 // GRG: if the original image has a mask, use its RGB values
2979 // as the blank pixel, else, fall back to default (black).
2980 //
2981 unsigned char blank_r = 0;
2982 unsigned char blank_g = 0;
2983 unsigned char blank_b = 0;
2984
2985 if (HasMask())
2986 {
2987 blank_r = GetMaskRed();
2988 blank_g = GetMaskGreen();
2989 blank_b = GetMaskBlue();
2990 rotated.SetMaskColour( blank_r, blank_g, blank_b );
2991 }
2992
2993 // Now, for each point of the rotated image, find where it came from, by
2994 // performing an inverse rotation (a rotation of -angle) and getting the
2995 // pixel at those coordinates
2996
2997 // GRG: I've taken the (interpolating) test out of the loops, so that
2998 // it is done only once, instead of repeating it for each pixel.
2999
3000 int x;
3001 if (interpolating)
3002 {
3003 for (int y = 0; y < rotated.GetHeight(); y++)
3004 {
3005 for (x = 0; x < rotated.GetWidth(); x++)
3006 {
3007 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
3008
3009 if (-0.25 < src.x && src.x < GetWidth() - 0.75 &&
3010 -0.25 < src.y && src.y < GetHeight() - 0.75)
3011 {
3012 // interpolate using the 4 enclosing grid-points. Those
3013 // points can be obtained using floor and ceiling of the
3014 // exact coordinates of the point
3015 // C.M. 2000-02-17: when the point is near the border, special care is required.
3016
3017 int x1, y1, x2, y2;
3018
3019 if (0 < src.x && src.x < GetWidth() - 1)
3020 {
3021 x1 = wxCint(floor(src.x));
3022 x2 = wxCint(ceil(src.x));
3023 }
3024 else // else means that x is near one of the borders (0 or width-1)
3025 {
3026 x1 = x2 = wxCint (src.x);
3027 }
3028
3029 if (0 < src.y && src.y < GetHeight() - 1)
3030 {
3031 y1 = wxCint(floor(src.y));
3032 y2 = wxCint(ceil(src.y));
3033 }
3034 else
3035 {
3036 y1 = y2 = wxCint (src.y);
3037 }
3038
3039 // get four points and the distances (square of the distance,
3040 // for efficiency reasons) for the interpolation formula
3041
3042 // GRG: Do not calculate the points until they are
3043 // really needed -- this way we can calculate
3044 // just one, instead of four, if d1, d2, d3
3045 // or d4 are < gs_Epsilon
3046
3047 const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1);
3048 const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1);
3049 const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2);
3050 const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2);
3051
3052 // Now interpolate as a weighted average of the four surrounding
3053 // points, where the weights are the distances to each of those points
3054
3055 // If the point is exactly at one point of the grid of the source
3056 // image, then don't interpolate -- just assign the pixel
3057
3058 if (d1 < gs_Epsilon) // d1,d2,d3,d4 are positive -- no need for abs()
3059 {
3060 unsigned char *p = data[y1] + (3 * x1);
3061 *(dst++) = *(p++);
3062 *(dst++) = *(p++);
3063 *(dst++) = *(p++);
3064 }
3065 else if (d2 < gs_Epsilon)
3066 {
3067 unsigned char *p = data[y1] + (3 * x2);
3068 *(dst++) = *(p++);
3069 *(dst++) = *(p++);
3070 *(dst++) = *(p++);
3071 }
3072 else if (d3 < gs_Epsilon)
3073 {
3074 unsigned char *p = data[y2] + (3 * x2);
3075 *(dst++) = *(p++);
3076 *(dst++) = *(p++);
3077 *(dst++) = *(p++);
3078 }
3079 else if (d4 < gs_Epsilon)
3080 {
3081 unsigned char *p = data[y2] + (3 * x1);
3082 *(dst++) = *(p++);
3083 *(dst++) = *(p++);
3084 *(dst++) = *(p++);
3085 }
3086 else
3087 {
3088 // weights for the weighted average are proportional to the inverse of the distance
3089 unsigned char *v1 = data[y1] + (3 * x1);
3090 unsigned char *v2 = data[y1] + (3 * x2);
3091 unsigned char *v3 = data[y2] + (3 * x2);
3092 unsigned char *v4 = data[y2] + (3 * x1);
3093
3094 const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4;
3095
3096 // GRG: Unrolled.
3097
3098 *(dst++) = (unsigned char)
3099 ( (w1 * *(v1++) + w2 * *(v2++) +
3100 w3 * *(v3++) + w4 * *(v4++)) /
3101 (w1 + w2 + w3 + w4) );
3102 *(dst++) = (unsigned char)
3103 ( (w1 * *(v1++) + w2 * *(v2++) +
3104 w3 * *(v3++) + w4 * *(v4++)) /
3105 (w1 + w2 + w3 + w4) );
3106 *(dst++) = (unsigned char)
3107 ( (w1 * *(v1++) + w2 * *(v2++) +
3108 w3 * *(v3++) + w4 * *(v4++)) /
3109 (w1 + w2 + w3 + w4) );
3110 }
3111 }
3112 else
3113 {
3114 *(dst++) = blank_r;
3115 *(dst++) = blank_g;
3116 *(dst++) = blank_b;
3117 }
3118 }
3119 }
3120 }
3121 else // not interpolating
3122 {
3123 for (int y = 0; y < rotated.GetHeight(); y++)
3124 {
3125 for (x = 0; x < rotated.GetWidth(); x++)
3126 {
3127 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
3128
3129 const int xs = wxCint (src.x); // wxCint rounds to the
3130 const int ys = wxCint (src.y); // closest integer
3131
3132 if (0 <= xs && xs < GetWidth() &&
3133 0 <= ys && ys < GetHeight())
3134 {
3135 unsigned char *p = data[ys] + (3 * xs);
3136 *(dst++) = *(p++);
3137 *(dst++) = *(p++);
3138 *(dst++) = *(p++);
3139 }
3140 else
3141 {
3142 *(dst++) = blank_r;
3143 *(dst++) = blank_g;
3144 *(dst++) = blank_b;
3145 }
3146 }
3147 }
3148 }
3149
3150 delete [] data;
3151
3152 return rotated;
3153 }
3154