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