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