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