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