]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/image.cpp
Added wxFileName::GetModificationTime()
[wxWidgets.git] / src / common / image.cpp
... / ...
CommitLineData
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
40//-----------------------------------------------------------------------------
41// wxImage
42//-----------------------------------------------------------------------------
43
44class wxImageRefData: public wxObjectRefData
45{
46public:
47 wxImageRefData();
48 ~wxImageRefData();
49
50 int m_width;
51 int m_height;
52 unsigned char *m_data;
53 bool m_hasMask;
54 unsigned char m_maskRed,m_maskGreen,m_maskBlue;
55 bool m_ok;
56 bool m_static;
57 wxPalette m_palette;
58 wxArrayString m_optionNames;
59 wxArrayString m_optionValues;
60};
61
62wxImageRefData::wxImageRefData()
63{
64 m_width = 0;
65 m_height = 0;
66 m_data = (unsigned char*) NULL;
67 m_ok = FALSE;
68 m_maskRed = 0;
69 m_maskGreen = 0;
70 m_maskBlue = 0;
71 m_hasMask = FALSE;
72 m_static = FALSE;
73}
74
75wxImageRefData::~wxImageRefData()
76{
77 if (m_data && !m_static)
78 free( m_data );
79}
80
81wxList wxImage::sm_handlers;
82
83wxImage wxNullImage;
84
85//-----------------------------------------------------------------------------
86
87#define M_IMGDATA ((wxImageRefData *)m_refData)
88
89IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
90
91wxImage::wxImage()
92{
93}
94
95wxImage::wxImage( int width, int height )
96{
97 Create( width, height );
98}
99
100wxImage::wxImage( int width, int height, unsigned char* data, bool static_data )
101{
102 Create( width, height, data, static_data );
103}
104
105wxImage::wxImage( const wxString& name, long type )
106{
107 LoadFile( name, type );
108}
109
110wxImage::wxImage( const wxString& name, const wxString& mimetype )
111{
112 LoadFile( name, mimetype );
113}
114
115#if wxUSE_STREAMS
116wxImage::wxImage( wxInputStream& stream, long type )
117{
118 LoadFile( stream, type );
119}
120
121wxImage::wxImage( wxInputStream& stream, const wxString& mimetype )
122{
123 LoadFile( stream, mimetype );
124}
125#endif // wxUSE_STREAMS
126
127wxImage::wxImage( const wxImage& image )
128{
129 Ref(image);
130}
131
132wxImage::wxImage( const wxImage* image )
133{
134 if (image) Ref(*image);
135}
136
137void wxImage::Create( int width, int height )
138{
139 UnRef();
140
141 m_refData = new wxImageRefData();
142
143 M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
144 if (M_IMGDATA->m_data)
145 {
146 for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
147
148 M_IMGDATA->m_width = width;
149 M_IMGDATA->m_height = height;
150 M_IMGDATA->m_ok = TRUE;
151 }
152 else
153 {
154 UnRef();
155 }
156}
157
158void wxImage::Create( int width, int height, unsigned char* data, bool static_data )
159{
160 UnRef();
161
162 m_refData = new wxImageRefData();
163
164 M_IMGDATA->m_data = data;
165 if (M_IMGDATA->m_data)
166 {
167 M_IMGDATA->m_width = width;
168 M_IMGDATA->m_height = height;
169 M_IMGDATA->m_ok = TRUE;
170 M_IMGDATA->m_static = static_data;
171 }
172 else
173 {
174 UnRef();
175 }
176}
177
178void wxImage::Destroy()
179{
180 UnRef();
181}
182
183wxImage wxImage::Copy() const
184{
185 wxImage image;
186
187 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
188
189 image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
190
191 char unsigned *data = image.GetData();
192
193 wxCHECK_MSG( data, image, wxT("unable to create image") );
194
195 if (M_IMGDATA->m_hasMask)
196 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
197
198 memcpy( data, GetData(), M_IMGDATA->m_width*M_IMGDATA->m_height*3 );
199
200 return image;
201}
202
203wxImage wxImage::Scale( int width, int height ) const
204{
205 wxImage image;
206
207 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
208
209 wxCHECK_MSG( (width > 0) && (height > 0), image, wxT("invalid image size") );
210
211 image.Create( width, height );
212
213 char unsigned *data = image.GetData();
214
215 wxCHECK_MSG( data, image, wxT("unable to create image") );
216
217 if (M_IMGDATA->m_hasMask)
218 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
219
220 long old_height = M_IMGDATA->m_height;
221 long old_width = M_IMGDATA->m_width;
222
223 char unsigned *source_data = M_IMGDATA->m_data;
224 char unsigned *target_data = data;
225
226 for (long j = 0; j < height; j++)
227 {
228 long y_offset = (j * old_height / height) * old_width;
229
230 for (long i = 0; i < width; i++)
231 {
232 memcpy( target_data,
233 source_data + 3*(y_offset + ((i * old_width )/ width)),
234 3 );
235 target_data += 3;
236 }
237 }
238
239 return image;
240}
241
242wxImage wxImage::Rotate90( bool clockwise ) const
243{
244 wxImage image;
245
246 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
247
248 image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width );
249
250 char unsigned *data = image.GetData();
251
252 wxCHECK_MSG( data, image, wxT("unable to create image") );
253
254 if (M_IMGDATA->m_hasMask)
255 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
256
257 long height = M_IMGDATA->m_height;
258 long width = M_IMGDATA->m_width;
259
260 char unsigned *source_data = M_IMGDATA->m_data;
261 char unsigned *target_data;
262
263 for (long j = 0; j < height; j++)
264 {
265 for (long i = 0; i < width; i++)
266 {
267 if (clockwise)
268 target_data = data + (((i+1)*height) - j - 1)*3;
269 else
270 target_data = data + ((height*(width-1)) + j - (i*height))*3;
271 memcpy( target_data, source_data, 3 );
272 source_data += 3;
273 }
274 }
275
276 return image;
277}
278
279wxImage wxImage::Mirror( bool horizontally ) const
280{
281 wxImage image;
282
283 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
284
285 image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
286
287 char unsigned *data = image.GetData();
288
289 wxCHECK_MSG( data, image, wxT("unable to create image") );
290
291 if (M_IMGDATA->m_hasMask)
292 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
293
294 long height = M_IMGDATA->m_height;
295 long width = M_IMGDATA->m_width;
296
297 char unsigned *source_data = M_IMGDATA->m_data;
298 char unsigned *target_data;
299
300 if (horizontally)
301 {
302 for (long j = 0; j < height; j++)
303 {
304 data += width*3;
305 target_data = data-3;
306 for (long i = 0; i < width; i++)
307 {
308 memcpy( target_data, source_data, 3 );
309 source_data += 3;
310 target_data -= 3;
311 }
312 }
313 }
314 else
315 {
316 for (long i = 0; i < height; i++)
317 {
318 target_data = data + 3*width*(height-1-i);
319 memcpy( target_data, source_data, (size_t)3*width );
320 source_data += 3*width;
321 }
322 }
323
324 return image;
325}
326
327wxImage wxImage::GetSubImage( const wxRect &rect ) const
328{
329 wxImage image;
330
331 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
332
333 wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()),
334 image, wxT("invalid subimage size") );
335
336 int subwidth=rect.GetWidth();
337 const int subheight=rect.GetHeight();
338
339 image.Create( subwidth, subheight );
340
341 char unsigned *subdata = image.GetData(), *data=GetData();
342
343 wxCHECK_MSG( subdata, image, wxT("unable to create image") );
344
345 if (M_IMGDATA->m_hasMask)
346 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
347
348 const int subleft=3*rect.GetLeft();
349 const int width=3*GetWidth();
350 subwidth*=3;
351
352 data+=rect.GetTop()*width+subleft;
353
354 for (long j = 0; j < subheight; ++j)
355 {
356 memcpy( subdata, data, subwidth);
357 subdata+=subwidth;
358 data+=width;
359 }
360
361 return image;
362}
363
364void wxImage::Paste( const wxImage &image, int x, int y )
365{
366 wxCHECK_RET( Ok(), wxT("invalid image") );
367 wxCHECK_RET( image.Ok(), wxT("invalid image") );
368
369 int xx = 0;
370 int yy = 0;
371 int width = image.GetWidth();
372 int height = image.GetHeight();
373
374 if (x < 0)
375 {
376 xx = -x;
377 width += x;
378 }
379 if (y < 0)
380 {
381 yy = -y;
382 height += y;
383 }
384
385 if ((x+xx)+width > M_IMGDATA->m_width)
386 width = M_IMGDATA->m_width - (x+xx);
387 if ((y+yy)+height > M_IMGDATA->m_height)
388 height = M_IMGDATA->m_height - (y+yy);
389
390 if (width < 1) return;
391 if (height < 1) return;
392
393 if ((!HasMask() && !image.HasMask()) ||
394 ((HasMask() && image.HasMask() &&
395 (GetMaskRed()==image.GetMaskRed()) &&
396 (GetMaskGreen()==image.GetMaskGreen()) &&
397 (GetMaskBlue()==image.GetMaskBlue()))))
398 {
399 width *= 3;
400 unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth();
401 int source_step = image.GetWidth()*3;
402
403 unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width;
404 int target_step = M_IMGDATA->m_width*3;
405 for (int j = 0; j < height; j++)
406 {
407 memcpy( target_data, source_data, width );
408 source_data += source_step;
409 target_data += target_step;
410 }
411 return;
412 }
413
414 if (!HasMask() && image.HasMask())
415 {
416 unsigned char r = image.GetMaskRed();
417 unsigned char g = image.GetMaskGreen();
418 unsigned char b = image.GetMaskBlue();
419
420 width *= 3;
421 unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth();
422 int source_step = image.GetWidth()*3;
423
424 unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width;
425 int target_step = M_IMGDATA->m_width*3;
426
427 for (int j = 0; j < height; j++)
428 {
429 for (int i = 0; i < width; i+=3)
430 {
431 if ((source_data[i] != r) &&
432 (source_data[i+1] != g) &&
433 (source_data[i+2] != b))
434 {
435 memcpy( target_data+i, source_data+i, 3 );
436 }
437 }
438 source_data += source_step;
439 target_data += target_step;
440 }
441 }
442}
443
444void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1,
445 unsigned char r2, unsigned char g2, unsigned char b2 )
446{
447 wxCHECK_RET( Ok(), wxT("invalid image") );
448
449 char unsigned *data = GetData();
450
451 const int w = GetWidth();
452 const int h = GetHeight();
453
454 for (int j = 0; j < h; j++)
455 for (int i = 0; i < w; i++)
456 {
457 if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1))
458 {
459 data[0] = r2;
460 data[1] = g2;
461 data[2] = b2;
462 }
463 data += 3;
464 }
465}
466
467wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const
468{
469 wxImage image;
470
471 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
472
473 image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
474
475 char unsigned *data = image.GetData();
476
477 wxCHECK_MSG( data, image, wxT("unable to create image") );
478
479 if (M_IMGDATA->m_hasMask)
480 {
481 if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g &&
482 M_IMGDATA->m_maskBlue == b)
483 image.SetMaskColour( 255, 255, 255 );
484 else
485 image.SetMaskColour( 0, 0, 0 );
486 }
487
488 long size = M_IMGDATA->m_height * M_IMGDATA->m_width;
489
490 char unsigned *srcd = M_IMGDATA->m_data;
491 char unsigned *tard = image.GetData();
492
493 for ( long i = 0; i < size; i++, srcd += 3, tard += 3 )
494 {
495 if (srcd[0] == r && srcd[1] == g && srcd[2] == b)
496 tard[0] = tard[1] = tard[2] = 255;
497 else
498 tard[0] = tard[1] = tard[2] = 0;
499 }
500
501 return image;
502}
503
504void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
505{
506 wxCHECK_RET( Ok(), wxT("invalid image") );
507
508 int w = M_IMGDATA->m_width;
509 int h = M_IMGDATA->m_height;
510
511 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
512
513 long pos = (y * w + x) * 3;
514
515 M_IMGDATA->m_data[ pos ] = r;
516 M_IMGDATA->m_data[ pos+1 ] = g;
517 M_IMGDATA->m_data[ pos+2 ] = b;
518}
519
520unsigned char wxImage::GetRed( int x, int y ) const
521{
522 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
523
524 int w = M_IMGDATA->m_width;
525 int h = M_IMGDATA->m_height;
526
527 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
528
529 long pos = (y * w + x) * 3;
530
531 return M_IMGDATA->m_data[pos];
532}
533
534unsigned char wxImage::GetGreen( int x, int y ) const
535{
536 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
537
538 int w = M_IMGDATA->m_width;
539 int h = M_IMGDATA->m_height;
540
541 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
542
543 long pos = (y * w + x) * 3;
544
545 return M_IMGDATA->m_data[pos+1];
546}
547
548unsigned char wxImage::GetBlue( int x, int y ) const
549{
550 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
551
552 int w = M_IMGDATA->m_width;
553 int h = M_IMGDATA->m_height;
554
555 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
556
557 long pos = (y * w + x) * 3;
558
559 return M_IMGDATA->m_data[pos+2];
560}
561
562bool wxImage::Ok() const
563{
564 // image of 0 width or height can't be considered ok - at least because it
565 // causes crashes in ConvertToBitmap() if we don't catch it in time
566 wxImageRefData *data = M_IMGDATA;
567 return data && data->m_ok && data->m_width && data->m_height;
568}
569
570char unsigned *wxImage::GetData() const
571{
572 wxCHECK_MSG( Ok(), (char unsigned *)NULL, wxT("invalid image") );
573
574 return M_IMGDATA->m_data;
575}
576
577void wxImage::SetData( char unsigned *data )
578{
579 wxCHECK_RET( Ok(), wxT("invalid image") );
580
581 wxImageRefData *newRefData = new wxImageRefData();
582
583 newRefData->m_width = M_IMGDATA->m_width;
584 newRefData->m_height = M_IMGDATA->m_height;
585 newRefData->m_data = data;
586 newRefData->m_ok = TRUE;
587 newRefData->m_maskRed = M_IMGDATA->m_maskRed;
588 newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
589 newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
590 newRefData->m_hasMask = M_IMGDATA->m_hasMask;
591
592 UnRef();
593
594 m_refData = newRefData;
595}
596
597void wxImage::SetData( char unsigned *data, int new_width, int new_height )
598{
599 wxImageRefData *newRefData = new wxImageRefData();
600
601 if (m_refData)
602 {
603 newRefData->m_width = new_width;
604 newRefData->m_height = new_height;
605 newRefData->m_data = data;
606 newRefData->m_ok = TRUE;
607 newRefData->m_maskRed = M_IMGDATA->m_maskRed;
608 newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
609 newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
610 newRefData->m_hasMask = M_IMGDATA->m_hasMask;
611 }
612 else
613 {
614 newRefData->m_width = new_width;
615 newRefData->m_height = new_height;
616 newRefData->m_data = data;
617 newRefData->m_ok = TRUE;
618 }
619
620 UnRef();
621
622 m_refData = newRefData;
623}
624
625void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
626{
627 wxCHECK_RET( Ok(), wxT("invalid image") );
628
629 M_IMGDATA->m_maskRed = r;
630 M_IMGDATA->m_maskGreen = g;
631 M_IMGDATA->m_maskBlue = b;
632 M_IMGDATA->m_hasMask = TRUE;
633}
634
635unsigned char wxImage::GetMaskRed() const
636{
637 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
638
639 return M_IMGDATA->m_maskRed;
640}
641
642unsigned char wxImage::GetMaskGreen() const
643{
644 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
645
646 return M_IMGDATA->m_maskGreen;
647}
648
649unsigned char wxImage::GetMaskBlue() const
650{
651 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
652
653 return M_IMGDATA->m_maskBlue;
654}
655
656void wxImage::SetMask( bool mask )
657{
658 wxCHECK_RET( Ok(), wxT("invalid image") );
659
660 M_IMGDATA->m_hasMask = mask;
661}
662
663bool wxImage::HasMask() const
664{
665 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
666
667 return M_IMGDATA->m_hasMask;
668}
669
670int wxImage::GetWidth() const
671{
672 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
673
674 return M_IMGDATA->m_width;
675}
676
677int wxImage::GetHeight() const
678{
679 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
680
681 return M_IMGDATA->m_height;
682}
683
684// Palette functions
685
686bool wxImage::HasPalette() const
687{
688 if (!Ok())
689 return FALSE;
690
691 return M_IMGDATA->m_palette.Ok();
692}
693
694const wxPalette& wxImage::GetPalette() const
695{
696 wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") );
697
698 return M_IMGDATA->m_palette;
699}
700
701void wxImage::SetPalette(const wxPalette& palette)
702{
703 wxCHECK_RET( Ok(), wxT("invalid image") );
704
705 M_IMGDATA->m_palette = palette;
706}
707
708// Option functions (arbitrary name/value mapping)
709void wxImage::SetOption(const wxString& name, const wxString& value)
710{
711 wxCHECK_RET( Ok(), wxT("invalid image") );
712
713 int idx = M_IMGDATA->m_optionNames.Index(name, FALSE);
714 if (idx == wxNOT_FOUND)
715 {
716 M_IMGDATA->m_optionNames.Add(name);
717 M_IMGDATA->m_optionValues.Add(value);
718 }
719 else
720 {
721 M_IMGDATA->m_optionNames[idx] = name;
722 M_IMGDATA->m_optionValues[idx] = value;
723 }
724}
725
726void wxImage::SetOption(const wxString& name, int value)
727{
728 wxString valStr;
729 valStr.Printf(wxT("%d"), value);
730 SetOption(name, valStr);
731}
732
733wxString wxImage::GetOption(const wxString& name) const
734{
735 wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid image") );
736
737 int idx = M_IMGDATA->m_optionNames.Index(name, FALSE);
738 if (idx == wxNOT_FOUND)
739 return wxEmptyString;
740 else
741 return M_IMGDATA->m_optionValues[idx];
742}
743
744int wxImage::GetOptionInt(const wxString& name) const
745{
746 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
747
748 return wxAtoi(GetOption(name));
749}
750
751bool wxImage::HasOption(const wxString& name) const
752{
753 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
754
755 return (M_IMGDATA->m_optionNames.Index(name, FALSE) != wxNOT_FOUND);
756}
757
758bool wxImage::LoadFile( const wxString& filename, long type )
759{
760#if wxUSE_STREAMS
761 if (wxFileExists(filename))
762 {
763 wxFileInputStream stream(filename);
764 wxBufferedInputStream bstream( stream );
765 return LoadFile(bstream, type);
766 }
767 else
768 {
769 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
770
771 return FALSE;
772 }
773#else // !wxUSE_STREAMS
774 return FALSE;
775#endif // wxUSE_STREAMS
776}
777
778bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype )
779{
780#if wxUSE_STREAMS
781 if (wxFileExists(filename))
782 {
783 wxFileInputStream stream(filename);
784 wxBufferedInputStream bstream( stream );
785 return LoadFile(bstream, mimetype);
786 }
787 else
788 {
789 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
790
791 return FALSE;
792 }
793#else // !wxUSE_STREAMS
794 return FALSE;
795#endif // wxUSE_STREAMS
796}
797
798bool wxImage::SaveFile( const wxString& filename, int type )
799{
800#if wxUSE_STREAMS
801 wxFileOutputStream stream(filename);
802
803 if ( stream.LastError() == wxStream_NOERROR )
804 {
805 wxBufferedOutputStream bstream( stream );
806 return SaveFile(bstream, type);
807 }
808#endif // wxUSE_STREAMS
809
810 return FALSE;
811}
812
813bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype )
814{
815#if wxUSE_STREAMS
816 wxFileOutputStream stream(filename);
817
818 if ( stream.LastError() == wxStream_NOERROR )
819 {
820 wxBufferedOutputStream bstream( stream );
821 return SaveFile(bstream, mimetype);
822 }
823#endif // wxUSE_STREAMS
824
825 return FALSE;
826}
827
828bool wxImage::CanRead( const wxString &name )
829{
830#if wxUSE_STREAMS
831 wxFileInputStream stream(name);
832 return CanRead(stream);
833#else
834 return FALSE;
835#endif
836}
837
838#if wxUSE_STREAMS
839
840bool wxImage::CanRead( wxInputStream &stream )
841{
842 wxList &list=GetHandlers();
843
844 for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
845 {
846 wxImageHandler *handler=(wxImageHandler*)node->GetData();
847 if (handler->CanRead( stream ))
848 return TRUE;
849 }
850
851 return FALSE;
852}
853
854bool wxImage::LoadFile( wxInputStream& stream, long type )
855{
856 UnRef();
857
858 m_refData = new wxImageRefData;
859
860 wxImageHandler *handler;
861
862 if (type==wxBITMAP_TYPE_ANY)
863 {
864 wxList &list=GetHandlers();
865
866 for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
867 {
868 handler=(wxImageHandler*)node->GetData();
869 if (handler->CanRead( stream ))
870 return handler->LoadFile( this, stream );
871
872 }
873
874 wxLogWarning( _("No handler found for image type.") );
875 return FALSE;
876 }
877
878 handler = FindHandler(type);
879
880 if (handler == NULL)
881 {
882 wxLogWarning( _("No image handler for type %d defined."), type );
883
884 return FALSE;
885 }
886
887 return handler->LoadFile( this, stream );
888}
889
890bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype )
891{
892 UnRef();
893
894 m_refData = new wxImageRefData;
895
896 wxImageHandler *handler = FindHandlerMime(mimetype);
897
898 if (handler == NULL)
899 {
900 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
901
902 return FALSE;
903 }
904
905 return handler->LoadFile( this, stream );
906}
907
908bool wxImage::SaveFile( wxOutputStream& stream, int type )
909{
910 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
911
912 wxImageHandler *handler = FindHandler(type);
913
914 if (handler == NULL)
915 {
916 wxLogWarning( _("No image handler for type %d defined."), type );
917
918 return FALSE;
919 }
920
921 return handler->SaveFile( this, stream );
922}
923
924bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype )
925{
926 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
927
928 wxImageHandler *handler = FindHandlerMime(mimetype);
929
930 if (handler == NULL)
931 {
932 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
933
934 return FALSE;
935 }
936
937 return handler->SaveFile( this, stream );
938}
939#endif // wxUSE_STREAMS
940
941void wxImage::AddHandler( wxImageHandler *handler )
942{
943 // make sure that the memory will be freed at the program end
944 sm_handlers.DeleteContents(TRUE);
945
946 sm_handlers.Append( handler );
947}
948
949void wxImage::InsertHandler( wxImageHandler *handler )
950{
951 // make sure that the memory will be freed at the program end
952 sm_handlers.DeleteContents(TRUE);
953
954 sm_handlers.Insert( handler );
955}
956
957bool wxImage::RemoveHandler( const wxString& name )
958{
959 wxImageHandler *handler = FindHandler(name);
960 if (handler)
961 {
962 sm_handlers.DeleteObject(handler);
963 return TRUE;
964 }
965 else
966 return FALSE;
967}
968
969wxImageHandler *wxImage::FindHandler( const wxString& name )
970{
971 wxNode *node = sm_handlers.First();
972 while (node)
973 {
974 wxImageHandler *handler = (wxImageHandler*)node->Data();
975 if (handler->GetName().Cmp(name) == 0) return handler;
976
977 node = node->Next();
978 }
979 return (wxImageHandler *)NULL;
980}
981
982wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
983{
984 wxNode *node = sm_handlers.First();
985 while (node)
986 {
987 wxImageHandler *handler = (wxImageHandler*)node->Data();
988 if ( (handler->GetExtension().Cmp(extension) == 0) &&
989 (bitmapType == -1 || handler->GetType() == bitmapType) )
990 return handler;
991 node = node->Next();
992 }
993 return (wxImageHandler*)NULL;
994}
995
996wxImageHandler *wxImage::FindHandler( long bitmapType )
997{
998 wxNode *node = sm_handlers.First();
999 while (node)
1000 {
1001 wxImageHandler *handler = (wxImageHandler *)node->Data();
1002 if (handler->GetType() == bitmapType) return handler;
1003 node = node->Next();
1004 }
1005 return NULL;
1006}
1007
1008wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
1009{
1010 wxNode *node = sm_handlers.First();
1011 while (node)
1012 {
1013 wxImageHandler *handler = (wxImageHandler *)node->Data();
1014 if (handler->GetMimeType().IsSameAs(mimetype, FALSE)) return handler;
1015 node = node->Next();
1016 }
1017 return NULL;
1018}
1019
1020void wxImage::InitStandardHandlers()
1021{
1022 AddHandler( new wxBMPHandler );
1023}
1024
1025void wxImage::CleanUpHandlers()
1026{
1027 wxNode *node = sm_handlers.First();
1028 while (node)
1029 {
1030 wxImageHandler *handler = (wxImageHandler *)node->Data();
1031 wxNode *next = node->Next();
1032 delete handler;
1033 delete node;
1034 node = next;
1035 }
1036}
1037
1038//-----------------------------------------------------------------------------
1039// wxImageHandler
1040//-----------------------------------------------------------------------------
1041
1042IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject)
1043
1044#if wxUSE_STREAMS
1045bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
1046{
1047 return FALSE;
1048}
1049
1050bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) )
1051{
1052 return FALSE;
1053}
1054
1055int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
1056{
1057 return 1;
1058}
1059
1060bool wxImageHandler::CanRead( const wxString& name )
1061{
1062 if (wxFileExists(name))
1063 {
1064 wxFileInputStream stream(name);
1065 return CanRead(stream);
1066 }
1067
1068 else {
1069 wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() );
1070
1071 return FALSE;
1072 }
1073// return FALSE;
1074}
1075
1076#endif // wxUSE_STREAMS
1077
1078
1079
1080//-----------------------------------------------------------------------------
1081// wxBitmap convertion routines
1082//-----------------------------------------------------------------------------
1083
1084#if wxUSE_GUI
1085
1086#ifdef __WXGTK__
1087wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue ) const
1088{
1089 wxImage mono = this->ConvertToMono( red, green, blue );
1090 wxBitmap bitmap( mono, 1 );
1091 return bitmap;
1092}
1093#endif
1094
1095wxBitmap wxImage::ConvertToBitmap() const
1096{
1097 wxBitmap bitmap( *this );
1098 return bitmap;
1099}
1100
1101wxImage::wxImage( const wxBitmap &bitmap )
1102{
1103 *this = bitmap.ConvertToImage();
1104}
1105
1106#endif
1107
1108
1109
1110// A module to allow wxImage initialization/cleanup
1111// without calling these functions from app.cpp or from
1112// the user's application.
1113
1114class wxImageModule: public wxModule
1115{
1116DECLARE_DYNAMIC_CLASS(wxImageModule)
1117public:
1118 wxImageModule() {}
1119 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
1120 void OnExit() { wxImage::CleanUpHandlers(); };
1121};
1122
1123IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
1124
1125
1126//-----------------------------------------------------------------------------
1127
1128// GRG, Dic/99
1129// Counts and returns the number of different colours. Optionally stops
1130// when it exceeds 'stopafter' different colours. This is useful, for
1131// example, to see if the image can be saved as 8-bit (256 colour or
1132// less, in this case it would be invoked as CountColours(256)). Default
1133// value for stopafter is -1 (don't care).
1134//
1135unsigned long wxImage::CountColours( unsigned long stopafter )
1136{
1137 wxHashTable h;
1138 wxObject dummy;
1139 unsigned char r, g, b, *p;
1140 unsigned long size, nentries, key;
1141
1142 p = GetData();
1143 size = GetWidth() * GetHeight();
1144 nentries = 0;
1145
1146 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
1147 {
1148 r = *(p++);
1149 g = *(p++);
1150 b = *(p++);
1151 key = (r << 16) | (g << 8) | b;
1152
1153 if (h.Get(key) == NULL)
1154 {
1155 h.Put(key, &dummy);
1156 nentries++;
1157 }
1158 }
1159
1160 return nentries;
1161}
1162
1163
1164// GRG, Dic/99
1165// Computes the histogram of the image and fills a hash table, indexed
1166// with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
1167// wxHNode contains an 'index' (useful to build a palette with the image
1168// colours) and a 'value', which is the number of pixels in the image with
1169// that colour.
1170//
1171unsigned long wxImage::ComputeHistogram( wxHashTable &h )
1172{
1173 unsigned char r, g, b, *p;
1174 unsigned long size, nentries, key;
1175 wxHNode *hnode;
1176
1177 p = GetData();
1178 size = GetWidth() * GetHeight();
1179 nentries = 0;
1180
1181 for (unsigned long j = 0; j < size; j++)
1182 {
1183 r = *(p++);
1184 g = *(p++);
1185 b = *(p++);
1186 key = (r << 16) | (g << 8) | b;
1187
1188 hnode = (wxHNode *) h.Get(key);
1189
1190 if (hnode)
1191 hnode->value++;
1192 else
1193 {
1194 hnode = new wxHNode();
1195 hnode->index = nentries++;
1196 hnode->value = 1;
1197
1198 h.Put(key, (wxObject *)hnode);
1199 }
1200 }
1201
1202 return nentries;
1203}
1204
1205/*
1206 * Rotation code by Carlos Moreno
1207 */
1208
1209// GRG: I've removed wxRotationPoint - we already have wxRealPoint which
1210// does exactly the same thing. And I also got rid of wxRotationPixel
1211// bacause of potential problems in architectures where alignment
1212// is an issue, so I had to rewrite parts of the code.
1213
1214static const double gs_Epsilon = 1e-10;
1215
1216static inline int wxCint (double x)
1217{
1218 return (x > 0) ? (int) (x + 0.5) : (int) (x - 0.5);
1219}
1220
1221
1222// Auxiliary function to rotate a point (x,y) with respect to point p0
1223// make it inline and use a straight return to facilitate optimization
1224// also, the function receives the sine and cosine of the angle to avoid
1225// repeating the time-consuming calls to these functions -- sin/cos can
1226// be computed and stored in the calling function.
1227
1228inline wxRealPoint rotated_point (const wxRealPoint & p, double cos_angle, double sin_angle, const wxRealPoint & p0)
1229{
1230 return wxRealPoint (p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle,
1231 p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle);
1232}
1233
1234inline wxRealPoint rotated_point (double x, double y, double cos_angle, double sin_angle, const wxRealPoint & p0)
1235{
1236 return rotated_point (wxRealPoint(x,y), cos_angle, sin_angle, p0);
1237}
1238
1239wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const
1240{
1241 int i;
1242 angle = -angle; // screen coordinates are a mirror image of "real" coordinates
1243
1244 // Create pointer-based array to accelerate access to wxImage's data
1245 unsigned char ** data = new unsigned char * [GetHeight()];
1246
1247 data[0] = GetData();
1248
1249 for (i = 1; i < GetHeight(); i++)
1250 data[i] = data[i - 1] + (3 * GetWidth());
1251
1252 // precompute coefficients for rotation formula
1253 // (sine and cosine of the angle)
1254 const double cos_angle = cos(angle);
1255 const double sin_angle = sin(angle);
1256
1257 // Create new Image to store the result
1258 // First, find rectangle that covers the rotated image; to do that,
1259 // rotate the four corners
1260
1261 const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y);
1262
1263 wxRealPoint p1 = rotated_point (0, 0, cos_angle, sin_angle, p0);
1264 wxRealPoint p2 = rotated_point (0, GetHeight(), cos_angle, sin_angle, p0);
1265 wxRealPoint p3 = rotated_point (GetWidth(), 0, cos_angle, sin_angle, p0);
1266 wxRealPoint p4 = rotated_point (GetWidth(), GetHeight(), cos_angle, sin_angle, p0);
1267
1268 int x1 = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x)));
1269 int y1 = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y)));
1270 int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
1271 int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
1272
1273 wxImage rotated (x2 - x1 + 1, y2 - y1 + 1);
1274
1275 if (offset_after_rotation != NULL)
1276 {
1277 *offset_after_rotation = wxPoint (x1, y1);
1278 }
1279
1280 // GRG: The rotated (destination) image is always accessed
1281 // sequentially, so there is no need for a pointer-based
1282 // array here (and in fact it would be slower).
1283 //
1284 unsigned char * dst = rotated.GetData();
1285
1286 // GRG: if the original image has a mask, use its RGB values
1287 // as the blank pixel, else, fall back to default (black).
1288 //
1289 unsigned char blank_r = 0;
1290 unsigned char blank_g = 0;
1291 unsigned char blank_b = 0;
1292
1293 if (HasMask())
1294 {
1295 blank_r = GetMaskRed();
1296 blank_g = GetMaskGreen();
1297 blank_b = GetMaskBlue();
1298 rotated.SetMaskColour( blank_r, blank_g, blank_b );
1299 }
1300
1301 // Now, for each point of the rotated image, find where it came from, by
1302 // performing an inverse rotation (a rotation of -angle) and getting the
1303 // pixel at those coordinates
1304
1305 // GRG: I've taken the (interpolating) test out of the loops, so that
1306 // it is done only once, instead of repeating it for each pixel.
1307
1308 int x;
1309 if (interpolating)
1310 {
1311 for (int y = 0; y < rotated.GetHeight(); y++)
1312 {
1313 for (x = 0; x < rotated.GetWidth(); x++)
1314 {
1315 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
1316
1317 if (-0.25 < src.x && src.x < GetWidth() - 0.75 &&
1318 -0.25 < src.y && src.y < GetHeight() - 0.75)
1319 {
1320 // interpolate using the 4 enclosing grid-points. Those
1321 // points can be obtained using floor and ceiling of the
1322 // exact coordinates of the point
1323 // C.M. 2000-02-17: when the point is near the border, special care is required.
1324
1325 int x1, y1, x2, y2;
1326
1327 if (0 < src.x && src.x < GetWidth() - 1)
1328 {
1329 x1 = wxCint(floor(src.x));
1330 x2 = wxCint(ceil(src.x));
1331 }
1332 else // else means that x is near one of the borders (0 or width-1)
1333 {
1334 x1 = x2 = wxCint (src.x);
1335 }
1336
1337 if (0 < src.y && src.y < GetHeight() - 1)
1338 {
1339 y1 = wxCint(floor(src.y));
1340 y2 = wxCint(ceil(src.y));
1341 }
1342 else
1343 {
1344 y1 = y2 = wxCint (src.y);
1345 }
1346
1347 // get four points and the distances (square of the distance,
1348 // for efficiency reasons) for the interpolation formula
1349
1350 // GRG: Do not calculate the points until they are
1351 // really needed -- this way we can calculate
1352 // just one, instead of four, if d1, d2, d3
1353 // or d4 are < gs_Epsilon
1354
1355 const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1);
1356 const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1);
1357 const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2);
1358 const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2);
1359
1360 // Now interpolate as a weighted average of the four surrounding
1361 // points, where the weights are the distances to each of those points
1362
1363 // If the point is exactly at one point of the grid of the source
1364 // image, then don't interpolate -- just assign the pixel
1365
1366 if (d1 < gs_Epsilon) // d1,d2,d3,d4 are positive -- no need for abs()
1367 {
1368 unsigned char *p = data[y1] + (3 * x1);
1369 *(dst++) = *(p++);
1370 *(dst++) = *(p++);
1371 *(dst++) = *(p++);
1372 }
1373 else if (d2 < gs_Epsilon)
1374 {
1375 unsigned char *p = data[y1] + (3 * x2);
1376 *(dst++) = *(p++);
1377 *(dst++) = *(p++);
1378 *(dst++) = *(p++);
1379 }
1380 else if (d3 < gs_Epsilon)
1381 {
1382 unsigned char *p = data[y2] + (3 * x2);
1383 *(dst++) = *(p++);
1384 *(dst++) = *(p++);
1385 *(dst++) = *(p++);
1386 }
1387 else if (d4 < gs_Epsilon)
1388 {
1389 unsigned char *p = data[y2] + (3 * x1);
1390 *(dst++) = *(p++);
1391 *(dst++) = *(p++);
1392 *(dst++) = *(p++);
1393 }
1394 else
1395 {
1396 // weights for the weighted average are proportional to the inverse of the distance
1397 unsigned char *v1 = data[y1] + (3 * x1);
1398 unsigned char *v2 = data[y1] + (3 * x2);
1399 unsigned char *v3 = data[y2] + (3 * x2);
1400 unsigned char *v4 = data[y2] + (3 * x1);
1401
1402 const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4;
1403
1404 // GRG: Unrolled.
1405
1406 *(dst++) = (unsigned char)
1407 ( (w1 * *(v1++) + w2 * *(v2++) +
1408 w3 * *(v3++) + w4 * *(v4++)) /
1409 (w1 + w2 + w3 + w4) );
1410 *(dst++) = (unsigned char)
1411 ( (w1 * *(v1++) + w2 * *(v2++) +
1412 w3 * *(v3++) + w4 * *(v4++)) /
1413 (w1 + w2 + w3 + w4) );
1414 *(dst++) = (unsigned char)
1415 ( (w1 * *(v1++) + w2 * *(v2++) +
1416 w3 * *(v3++) + w4 * *(v4++)) /
1417 (w1 + w2 + w3 + w4) );
1418 }
1419 }
1420 else
1421 {
1422 *(dst++) = blank_r;
1423 *(dst++) = blank_g;
1424 *(dst++) = blank_b;
1425 }
1426 }
1427 }
1428 }
1429 else // not interpolating
1430 {
1431 for (int y = 0; y < rotated.GetHeight(); y++)
1432 {
1433 for (x = 0; x < rotated.GetWidth(); x++)
1434 {
1435 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
1436
1437 const int xs = wxCint (src.x); // wxCint rounds to the
1438 const int ys = wxCint (src.y); // closest integer
1439
1440 if (0 <= xs && xs < GetWidth() &&
1441 0 <= ys && ys < GetHeight())
1442 {
1443 unsigned char *p = data[ys] + (3 * xs);
1444 *(dst++) = *(p++);
1445 *(dst++) = *(p++);
1446 *(dst++) = *(p++);
1447 }
1448 else
1449 {
1450 *(dst++) = blank_r;
1451 *(dst++) = blank_g;
1452 *(dst++) = blank_b;
1453 }
1454 }
1455 }
1456 }
1457
1458 delete [] data;
1459
1460 return rotated;
1461}
1462