Fix FILETIME <-> wxDateTime conversions while DST is in effect in wxMSW.
[wxWidgets.git] / tests / image / image.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/image/image.cpp
3 // Purpose: Test wxImage
4 // Author: Francesco Montorsi
5 // Created: 2009-05-31
6 // RCS-ID: $Id$
7 // Copyright: (c) 2009 Francesco Montorsi
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ----------------------------------------------------------------------------
12 // headers
13 // ----------------------------------------------------------------------------
14
15 #include "testprec.h"
16
17 #if wxUSE_IMAGE
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #endif // WX_PRECOMP
25
26 #include "wx/anidecod.h" // wxImageArray
27 #include "wx/palette.h"
28 #include "wx/url.h"
29 #include "wx/log.h"
30 #include "wx/mstream.h"
31 #include "wx/zstream.h"
32 #include "wx/wfstream.h"
33
34 #include "testimage.h"
35
36 struct testData {
37 const char* file;
38 wxBitmapType type;
39 unsigned bitDepth;
40 } g_testfiles[] =
41 {
42 { "horse.ico", wxBITMAP_TYPE_ICO, 4 },
43 { "horse.xpm", wxBITMAP_TYPE_XPM, 8 },
44 { "horse.png", wxBITMAP_TYPE_PNG, 24 },
45 { "horse.ani", wxBITMAP_TYPE_ANI, 24 },
46 { "horse.bmp", wxBITMAP_TYPE_BMP, 8 },
47 { "horse.cur", wxBITMAP_TYPE_CUR, 1 },
48 { "horse.gif", wxBITMAP_TYPE_GIF, 8 },
49 { "horse.jpg", wxBITMAP_TYPE_JPEG, 24 },
50 { "horse.pcx", wxBITMAP_TYPE_PCX, 8 },
51 { "horse.pnm", wxBITMAP_TYPE_PNM, 24 },
52 { "horse.tga", wxBITMAP_TYPE_TGA, 8 },
53 { "horse.tif", wxBITMAP_TYPE_TIFF, 8 }
54 };
55
56
57 // ----------------------------------------------------------------------------
58 // test class
59 // ----------------------------------------------------------------------------
60
61 class ImageTestCase : public CppUnit::TestCase
62 {
63 public:
64 ImageTestCase();
65 ~ImageTestCase();
66
67 private:
68 CPPUNIT_TEST_SUITE( ImageTestCase );
69 CPPUNIT_TEST( LoadFromSocketStream );
70 CPPUNIT_TEST( LoadFromZipStream );
71 CPPUNIT_TEST( LoadFromFile );
72 CPPUNIT_TEST( SizeImage );
73 CPPUNIT_TEST( CompareLoadedImage );
74 CPPUNIT_TEST( CompareSavedImage );
75 CPPUNIT_TEST( SavePNG );
76 CPPUNIT_TEST( SaveTIFF );
77 CPPUNIT_TEST( SaveAnimatedGIF );
78 CPPUNIT_TEST( ReadCorruptedTGA );
79 CPPUNIT_TEST( GIFComment );
80 CPPUNIT_TEST( DibPadding );
81 CPPUNIT_TEST( BMPFlippingAndRLECompression );
82 CPPUNIT_TEST( ScaleCompare );
83 CPPUNIT_TEST_SUITE_END();
84
85 void LoadFromSocketStream();
86 void LoadFromZipStream();
87 void LoadFromFile();
88 void SizeImage();
89 void CompareLoadedImage();
90 void CompareSavedImage();
91 void SavePNG();
92 void SaveTIFF();
93 void SaveAnimatedGIF();
94 void ReadCorruptedTGA();
95 void GIFComment();
96 void DibPadding();
97 void BMPFlippingAndRLECompression();
98 void ScaleCompare();
99
100 DECLARE_NO_COPY_CLASS(ImageTestCase)
101 };
102
103 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase );
104 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase, "ImageTestCase" );
105
106 ImageTestCase::ImageTestCase()
107 {
108 wxSocketBase::Initialize();
109
110 // the formats we're going to test:
111 wxImage::AddHandler(new wxICOHandler);
112 wxImage::AddHandler(new wxXPMHandler);
113 wxImage::AddHandler(new wxPNGHandler);
114 wxImage::AddHandler(new wxANIHandler);
115 wxImage::AddHandler(new wxBMPHandler);
116 wxImage::AddHandler(new wxCURHandler);
117 wxImage::AddHandler(new wxGIFHandler);
118 wxImage::AddHandler(new wxJPEGHandler);
119 wxImage::AddHandler(new wxPCXHandler);
120 wxImage::AddHandler(new wxPNMHandler);
121 wxImage::AddHandler(new wxTGAHandler);
122 wxImage::AddHandler(new wxTIFFHandler);
123 }
124
125 ImageTestCase::~ImageTestCase()
126 {
127 wxSocketBase::Shutdown();
128 }
129
130 void ImageTestCase::LoadFromFile()
131 {
132 wxImage img;
133 for (unsigned int i=0; i<WXSIZEOF(g_testfiles); i++)
134 CPPUNIT_ASSERT(img.LoadFile(g_testfiles[i].file));
135 }
136
137 void ImageTestCase::LoadFromSocketStream()
138 {
139 if (!IsNetworkAvailable()) // implemented in test.cpp
140 {
141 wxLogWarning("No network connectivity; skipping the "
142 "ImageTestCase::LoadFromSocketStream test unit.");
143 return;
144 }
145
146 struct {
147 const char* url;
148 wxBitmapType type;
149 } testData[] =
150 {
151 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG },
152 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO }
153 };
154
155 for (unsigned int i=0; i<WXSIZEOF(testData); i++)
156 {
157 wxURL url(testData[i].url);
158 WX_ASSERT_EQUAL_MESSAGE
159 (
160 ("Constructing URL \"%s\" failed.", testData[i].url),
161 wxURL_NOERR,
162 url.GetError()
163 );
164
165 wxInputStream *in_stream = url.GetInputStream();
166 WX_ASSERT_MESSAGE
167 (
168 ("Opening URL \"%s\" failed.", testData[i].url),
169 in_stream && in_stream->IsOk()
170 );
171
172 wxImage img;
173
174 // NOTE: it's important to inform wxImage about the type of the image being
175 // loaded otherwise it will try to autodetect the format, but that
176 // requires a seekable stream!
177 WX_ASSERT_MESSAGE
178 (
179 ("Loading image from \"%s\" failed.", testData[i].url),
180 img.LoadFile(*in_stream, testData[i].type)
181 );
182
183 delete in_stream;
184 }
185 }
186
187 void ImageTestCase::LoadFromZipStream()
188 {
189 for (unsigned int i=0; i<WXSIZEOF(g_testfiles); i++)
190 {
191 switch (g_testfiles[i].type)
192 {
193 case wxBITMAP_TYPE_XPM:
194 case wxBITMAP_TYPE_GIF:
195 case wxBITMAP_TYPE_PCX:
196 case wxBITMAP_TYPE_TGA:
197 case wxBITMAP_TYPE_TIFF:
198 continue; // skip testing those wxImageHandlers which cannot
199 // load data from non-seekable streams
200
201 default:
202 ; // proceed
203 }
204
205 // compress the test file on the fly:
206 wxMemoryOutputStream memOut;
207 {
208 wxFileInputStream file(g_testfiles[i].file);
209 CPPUNIT_ASSERT(file.IsOk());
210
211 wxZlibOutputStream compressFilter(memOut, 5, wxZLIB_GZIP);
212 CPPUNIT_ASSERT(compressFilter.IsOk());
213
214 file.Read(compressFilter);
215 CPPUNIT_ASSERT(file.GetLastError() == wxSTREAM_EOF);
216 }
217
218 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
219 // allows us to test loading images from non-seekable streams other than socket streams
220 wxMemoryInputStream memIn(memOut);
221 CPPUNIT_ASSERT(memIn.IsOk());
222 wxZlibInputStream decompressFilter(memIn, wxZLIB_GZIP);
223 CPPUNIT_ASSERT(decompressFilter.IsOk());
224
225 wxImage img;
226
227 // NOTE: it's important to inform wxImage about the type of the image being
228 // loaded otherwise it will try to autodetect the format, but that
229 // requires a seekable stream!
230 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles[i].type),
231 img.LoadFile(decompressFilter, g_testfiles[i].type));
232 }
233 }
234
235 void ImageTestCase::SizeImage()
236 {
237 // Test the wxImage::Size() function which takes a rectangle from source and
238 // places it in a new image at a given position. This test checks, if the
239 // correct areas are chosen, and clipping is done correctly.
240
241 // our test image:
242 static const char * xpm_orig[] = {
243 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
244 " .....",
245 " ++++@@@@.",
246 " +... @.",
247 " +.@@++ @.",
248 " +.@ .+ @.",
249 ".@ +. @.+ ",
250 ".@ ++@@.+ ",
251 ".@ ...+ ",
252 ".@@@@++++ ",
253 "..... "
254 };
255 // the expected results for all tests:
256 static const char * xpm_l_t[] = {
257 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
258 "... @.BB",
259 ".@@++ @.BB",
260 ".@ .+ @.BB",
261 " +. @.+ BB",
262 " ++@@.+ BB",
263 " ...+ BB",
264 "@@@++++ BB",
265 "... BB",
266 "BBBBBBBBBB",
267 "BBBBBBBBBB"
268 };
269 static const char * xpm_t[] = {
270 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
271 " +... @.",
272 " +.@@++ @.",
273 " +.@ .+ @.",
274 ".@ +. @.+ ",
275 ".@ ++@@.+ ",
276 ".@ ...+ ",
277 ".@@@@++++ ",
278 "..... ",
279 "BBBBBBBBBB",
280 "BBBBBBBBBB"
281 };
282 static const char * xpm_r_t[] = {
283 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
284 "BB +... ",
285 "BB +.@@++ ",
286 "BB +.@ .+ ",
287 "BB.@ +. @.",
288 "BB.@ ++@@.",
289 "BB.@ ...",
290 "BB.@@@@+++",
291 "BB..... ",
292 "BBBBBBBBBB",
293 "BBBBBBBBBB"
294 };
295 static const char * xpm_l[] = {
296 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
297 " .....BB",
298 "+++@@@@.BB",
299 "... @.BB",
300 ".@@++ @.BB",
301 ".@ .+ @.BB",
302 " +. @.+ BB",
303 " ++@@.+ BB",
304 " ...+ BB",
305 "@@@++++ BB",
306 "... BB"
307 };
308 static const char * xpm_r[] = {
309 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
310 "BB ...",
311 "BB ++++@@@",
312 "BB +... ",
313 "BB +.@@++ ",
314 "BB +.@ .+ ",
315 "BB.@ +. @.",
316 "BB.@ ++@@.",
317 "BB.@ ...",
318 "BB.@@@@+++",
319 "BB..... "
320 };
321 static const char * xpm_l_b[] = {
322 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
323 "BBBBBBBBBB",
324 "BBBBBBBBBB",
325 " .....BB",
326 "+++@@@@.BB",
327 "... @.BB",
328 ".@@++ @.BB",
329 ".@ .+ @.BB",
330 " +. @.+ BB",
331 " ++@@.+ BB",
332 " ...+ BB"
333 };
334 static const char * xpm_b[] = {
335 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
336 "BBBBBBBBBB",
337 "BBBBBBBBBB",
338 " .....",
339 " ++++@@@@.",
340 " +... @.",
341 " +.@@++ @.",
342 " +.@ .+ @.",
343 ".@ +. @.+ ",
344 ".@ ++@@.+ ",
345 ".@ ...+ "
346 };
347 static const char * xpm_r_b[] = {
348 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
349 "BBBBBBBBBB",
350 "BBBBBBBBBB",
351 "BB ...",
352 "BB ++++@@@",
353 "BB +... ",
354 "BB +.@@++ ",
355 "BB +.@ .+ ",
356 "BB.@ +. @.",
357 "BB.@ ++@@.",
358 "BB.@ ..."
359 };
360 static const char * xpm_sm[] = {
361 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
362 " .....",
363 " ++++@@@",
364 " +... ",
365 " +.@@++ ",
366 " +.@ .+ ",
367 ".@ +. @.",
368 ".@ ++@@.",
369 ".@ ..."
370 };
371 static const char * xpm_gt[] = {
372 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
373 " .....BB",
374 " ++++@@@@.BB",
375 " +... @.BB",
376 " +.@@++ @.BB",
377 " +.@ .+ @.BB",
378 ".@ +. @.+ BB",
379 ".@ ++@@.+ BB",
380 ".@ ...+ BB",
381 ".@@@@++++ BB",
382 "..... BB",
383 "BBBBBBBBBBBB",
384 "BBBBBBBBBBBB"
385 };
386 static const char * xpm_gt_l_t[] = {
387 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
388 "... @.BBBB",
389 ".@@++ @.BBBB",
390 ".@ .+ @.BBBB",
391 " +. @.+ BBBB",
392 " ++@@.+ BBBB",
393 " ...+ BBBB",
394 "@@@++++ BBBB",
395 "... BBBB",
396 "BBBBBBBBBBBB",
397 "BBBBBBBBBBBB",
398 "BBBBBBBBBBBB",
399 "BBBBBBBBBBBB"
400 };
401 static const char * xpm_gt_l[] = {
402 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
403 " .....BBBB",
404 "+++@@@@.BBBB",
405 "... @.BBBB",
406 ".@@++ @.BBBB",
407 ".@ .+ @.BBBB",
408 " +. @.+ BBBB",
409 " ++@@.+ BBBB",
410 " ...+ BBBB",
411 "@@@++++ BBBB",
412 "... BBBB",
413 "BBBBBBBBBBBB",
414 "BBBBBBBBBBBB"
415 };
416 static const char * xpm_gt_l_b[] = {
417 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
418 "BBBBBBBBBBBB",
419 "BBBBBBBBBBBB",
420 " .....BBBB",
421 "+++@@@@.BBBB",
422 "... @.BBBB",
423 ".@@++ @.BBBB",
424 ".@ .+ @.BBBB",
425 " +. @.+ BBBB",
426 " ++@@.+ BBBB",
427 " ...+ BBBB",
428 "@@@++++ BBBB",
429 "... BBBB"
430 };
431 static const char * xpm_gt_l_bb[] = {
432 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
433 "BBBBBBBBBBBB",
434 "BBBBBBBBBBBB",
435 "BBBBBBBBBBBB",
436 "BBBBBBBBBBBB",
437 " .....BBBB",
438 "+++@@@@.BBBB",
439 "... @.BBBB",
440 ".@@++ @.BBBB",
441 ".@ .+ @.BBBB",
442 " +. @.+ BBBB",
443 " ++@@.+ BBBB",
444 " ...+ BBBB"
445 };
446 static const char * xpm_gt_t[] = {
447 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
448 " +... @.BB",
449 " +.@@++ @.BB",
450 " +.@ .+ @.BB",
451 ".@ +. @.+ BB",
452 ".@ ++@@.+ BB",
453 ".@ ...+ BB",
454 ".@@@@++++ BB",
455 "..... BB",
456 "BBBBBBBBBBBB",
457 "BBBBBBBBBBBB",
458 "BBBBBBBBBBBB",
459 "BBBBBBBBBBBB"
460 };
461 static const char * xpm_gt_b[] = {
462 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
463 "BBBBBBBBBBBB",
464 "BBBBBBBBBBBB",
465 " .....BB",
466 " ++++@@@@.BB",
467 " +... @.BB",
468 " +.@@++ @.BB",
469 " +.@ .+ @.BB",
470 ".@ +. @.+ BB",
471 ".@ ++@@.+ BB",
472 ".@ ...+ BB",
473 ".@@@@++++ BB",
474 "..... BB"
475 };
476 static const char * xpm_gt_bb[] = {
477 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
478 "BBBBBBBBBBBB",
479 "BBBBBBBBBBBB",
480 "BBBBBBBBBBBB",
481 "BBBBBBBBBBBB",
482 " .....BB",
483 " ++++@@@@.BB",
484 " +... @.BB",
485 " +.@@++ @.BB",
486 " +.@ .+ @.BB",
487 ".@ +. @.+ BB",
488 ".@ ++@@.+ BB",
489 ".@ ...+ BB"
490 };
491 static const char * xpm_gt_r_t[] = {
492 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
493 "BB +... @.",
494 "BB +.@@++ @.",
495 "BB +.@ .+ @.",
496 "BB.@ +. @.+ ",
497 "BB.@ ++@@.+ ",
498 "BB.@ ...+ ",
499 "BB.@@@@++++ ",
500 "BB..... ",
501 "BBBBBBBBBBBB",
502 "BBBBBBBBBBBB",
503 "BBBBBBBBBBBB",
504 "BBBBBBBBBBBB"
505 };
506 static const char * xpm_gt_r[] = {
507 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
508 "BB .....",
509 "BB ++++@@@@.",
510 "BB +... @.",
511 "BB +.@@++ @.",
512 "BB +.@ .+ @.",
513 "BB.@ +. @.+ ",
514 "BB.@ ++@@.+ ",
515 "BB.@ ...+ ",
516 "BB.@@@@++++ ",
517 "BB..... ",
518 "BBBBBBBBBBBB",
519 "BBBBBBBBBBBB"
520 };
521 static const char * xpm_gt_r_b[] = {
522 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
523 "BBBBBBBBBBBB",
524 "BBBBBBBBBBBB",
525 "BB .....",
526 "BB ++++@@@@.",
527 "BB +... @.",
528 "BB +.@@++ @.",
529 "BB +.@ .+ @.",
530 "BB.@ +. @.+ ",
531 "BB.@ ++@@.+ ",
532 "BB.@ ...+ ",
533 "BB.@@@@++++ ",
534 "BB..... "
535 };
536 static const char * xpm_gt_r_bb[] = {
537 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
538 "BBBBBBBBBBBB",
539 "BBBBBBBBBBBB",
540 "BBBBBBBBBBBB",
541 "BBBBBBBBBBBB",
542 "BB .....",
543 "BB ++++@@@@.",
544 "BB +... @.",
545 "BB +.@@++ @.",
546 "BB +.@ .+ @.",
547 "BB.@ +. @.+ ",
548 "BB.@ ++@@.+ ",
549 "BB.@ ...+ "
550 };
551 static const char * xpm_gt_rr_t[] = {
552 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
553 "BBBB +... ",
554 "BBBB +.@@++ ",
555 "BBBB +.@ .+ ",
556 "BBBB.@ +. @.",
557 "BBBB.@ ++@@.",
558 "BBBB.@ ...",
559 "BBBB.@@@@+++",
560 "BBBB..... ",
561 "BBBBBBBBBBBB",
562 "BBBBBBBBBBBB",
563 "BBBBBBBBBBBB",
564 "BBBBBBBBBBBB"
565 };
566 static const char * xpm_gt_rr[] = {
567 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
568 "BBBB ...",
569 "BBBB ++++@@@",
570 "BBBB +... ",
571 "BBBB +.@@++ ",
572 "BBBB +.@ .+ ",
573 "BBBB.@ +. @.",
574 "BBBB.@ ++@@.",
575 "BBBB.@ ...",
576 "BBBB.@@@@+++",
577 "BBBB..... ",
578 "BBBBBBBBBBBB",
579 "BBBBBBBBBBBB"
580 };
581 static const char * xpm_gt_rr_b[] = {
582 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
583 "BBBBBBBBBBBB",
584 "BBBBBBBBBBBB",
585 "BBBB ...",
586 "BBBB ++++@@@",
587 "BBBB +... ",
588 "BBBB +.@@++ ",
589 "BBBB +.@ .+ ",
590 "BBBB.@ +. @.",
591 "BBBB.@ ++@@.",
592 "BBBB.@ ...",
593 "BBBB.@@@@+++",
594 "BBBB..... "
595 };
596 static const char * xpm_gt_rr_bb[] = {
597 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
598 "BBBBBBBBBBBB",
599 "BBBBBBBBBBBB",
600 "BBBBBBBBBBBB",
601 "BBBBBBBBBBBB",
602 "BBBB ...",
603 "BBBB ++++@@@",
604 "BBBB +... ",
605 "BBBB +.@@++ ",
606 "BBBB +.@ .+ ",
607 "BBBB.@ +. @.",
608 "BBBB.@ ++@@.",
609 "BBBB.@ ..."
610 };
611 static const char * xpm_sm_ll_tt[] = {
612 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
613 " .+ @.BB",
614 ". @.+ BB",
615 "+@@.+ BB",
616 " ...+ BB",
617 "@++++ BB",
618 ". BB",
619 "BBBBBBBB",
620 "BBBBBBBB"
621 };
622 static const char * xpm_sm_ll_t[] = {
623 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
624 ". @.BB",
625 "@++ @.BB",
626 " .+ @.BB",
627 ". @.+ BB",
628 "+@@.+ BB",
629 " ...+ BB",
630 "@++++ BB",
631 ". BB"
632 };
633 static const char * xpm_sm_ll[] = {
634 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
635 " .....BB",
636 "+@@@@.BB",
637 ". @.BB",
638 "@++ @.BB",
639 " .+ @.BB",
640 ". @.+ BB",
641 "+@@.+ BB",
642 " ...+ BB"
643 };
644 static const char * xpm_sm_ll_b[] = {
645 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
646 "BBBBBBBB",
647 "BBBBBBBB",
648 " .....BB",
649 "+@@@@.BB",
650 ". @.BB",
651 "@++ @.BB",
652 " .+ @.BB",
653 ". @.+ BB"
654 };
655 static const char * xpm_sm_l_tt[] = {
656 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
657 ".@ .+ @.",
658 " +. @.+ ",
659 " ++@@.+ ",
660 " ...+ ",
661 "@@@++++ ",
662 "... ",
663 "BBBBBBBB",
664 "BBBBBBBB"
665 };
666 static const char * xpm_sm_l_t[] = {
667 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
668 "... @.",
669 ".@@++ @.",
670 ".@ .+ @.",
671 " +. @.+ ",
672 " ++@@.+ ",
673 " ...+ ",
674 "@@@++++ ",
675 "... "
676 };
677 static const char * xpm_sm_l[] = {
678 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
679 " .....",
680 "+++@@@@.",
681 "... @.",
682 ".@@++ @.",
683 ".@ .+ @.",
684 " +. @.+ ",
685 " ++@@.+ ",
686 " ...+ "
687 };
688 static const char * xpm_sm_l_b[] = {
689 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
690 "BBBBBBBB",
691 "BBBBBBBB",
692 " .....",
693 "+++@@@@.",
694 "... @.",
695 ".@@++ @.",
696 ".@ .+ @.",
697 " +. @.+ "
698 };
699 static const char * xpm_sm_tt[] = {
700 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
701 " +.@ .+ ",
702 ".@ +. @.",
703 ".@ ++@@.",
704 ".@ ...",
705 ".@@@@+++",
706 "..... ",
707 "BBBBBBBB",
708 "BBBBBBBB"
709 };
710 static const char * xpm_sm_t[] = {
711 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
712 " +... ",
713 " +.@@++ ",
714 " +.@ .+ ",
715 ".@ +. @.",
716 ".@ ++@@.",
717 ".@ ...",
718 ".@@@@+++",
719 "..... "
720 };
721 static const char * xpm_sm_b[] = {
722 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
723 "BBBBBBBB",
724 "BBBBBBBB",
725 " ...",
726 " ++++@@@",
727 " +... ",
728 " +.@@++ ",
729 " +.@ .+ ",
730 ".@ +. @."
731 };
732 static const char * xpm_sm_r_tt[] = {
733 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
734 "BB +.@ .",
735 "BB.@ +. ",
736 "BB.@ ++@",
737 "BB.@ .",
738 "BB.@@@@+",
739 "BB..... ",
740 "BBBBBBBB",
741 "BBBBBBBB"
742 };
743 static const char * xpm_sm_r_t[] = {
744 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
745 "BB +... ",
746 "BB +.@@+",
747 "BB +.@ .",
748 "BB.@ +. ",
749 "BB.@ ++@",
750 "BB.@ .",
751 "BB.@@@@+",
752 "BB..... "
753 };
754 static const char * xpm_sm_r[] = {
755 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
756 "BB .",
757 "BB ++++@",
758 "BB +... ",
759 "BB +.@@+",
760 "BB +.@ .",
761 "BB.@ +. ",
762 "BB.@ ++@",
763 "BB.@ ."
764 };
765 static const char * xpm_sm_r_b[] = {
766 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
767 "BBBBBBBB",
768 "BBBBBBBB",
769 "BB .",
770 "BB ++++@",
771 "BB +... ",
772 "BB +.@@+",
773 "BB +.@ .",
774 "BB.@ +. "
775 };
776
777 // this table defines all tests
778 struct SizeTestData
779 {
780 int w, h, dx, dy; // first parameters for Size()
781 const char **ref_xpm; // expected result
782 } sizeTestData[] =
783 {
784 { 10, 10, 0, 0, xpm_orig}, // same size, same position
785 { 12, 12, 0, 0, xpm_gt}, // target larger, same position
786 { 8, 8, 0, 0, xpm_sm}, // target smaller, same position
787 { 10, 10, -2, -2, xpm_l_t}, // same size, move left up
788 { 10, 10, -2, 0, xpm_l}, // same size, move left
789 { 10, 10, -2, 2, xpm_l_b}, // same size, move left down
790 { 10, 10, 0, -2, xpm_t}, // same size, move up
791 { 10, 10, 0, 2, xpm_b}, // same size, move down
792 { 10, 10, 2, -2, xpm_r_t}, // same size, move right up
793 { 10, 10, 2, 0, xpm_r}, // same size, move right
794 { 10, 10, 2, 2, xpm_r_b}, // same size, move right down
795 { 12, 12, -2, -2, xpm_gt_l_t}, // target larger, move left up
796 { 12, 12, -2, 0, xpm_gt_l}, // target larger, move left
797 { 12, 12, -2, 2, xpm_gt_l_b}, // target larger, move left down
798 { 12, 12, -2, 4, xpm_gt_l_bb}, // target larger, move left down
799 { 12, 12, 0, -2, xpm_gt_t}, // target larger, move up
800 { 12, 12, 0, 2, xpm_gt_b}, // target larger, move down
801 { 12, 12, 0, 4, xpm_gt_bb}, // target larger, move down
802 { 12, 12, 2, -2, xpm_gt_r_t}, // target larger, move right up
803 { 12, 12, 2, 0, xpm_gt_r}, // target larger, move right
804 { 12, 12, 2, 2, xpm_gt_r_b}, // target larger, move right down
805 { 12, 12, 2, 4, xpm_gt_r_bb}, // target larger, move right down
806 { 12, 12, 4, -2, xpm_gt_rr_t}, // target larger, move right up
807 { 12, 12, 4, 0, xpm_gt_rr}, // target larger, move right
808 { 12, 12, 4, 2, xpm_gt_rr_b}, // target larger, move right down
809 { 12, 12, 4, 4, xpm_gt_rr_bb}, // target larger, move right down
810 { 8, 8, -4, -4, xpm_sm_ll_tt}, // target smaller, move left up
811 { 8, 8, -4, -2, xpm_sm_ll_t}, // target smaller, move left up
812 { 8, 8, -4, 0, xpm_sm_ll}, // target smaller, move left
813 { 8, 8, -4, 2, xpm_sm_ll_b}, // target smaller, move left down
814 { 8, 8, -2, -4, xpm_sm_l_tt}, // target smaller, move left up
815 { 8, 8, -2, -2, xpm_sm_l_t}, // target smaller, move left up
816 { 8, 8, -2, 0, xpm_sm_l}, // target smaller, move left
817 { 8, 8, -2, 2, xpm_sm_l_b}, // target smaller, move left down
818 { 8, 8, 0, -4, xpm_sm_tt}, // target smaller, move up
819 { 8, 8, 0, -2, xpm_sm_t}, // target smaller, move up
820 { 8, 8, 0, 2, xpm_sm_b}, // target smaller, move down
821 { 8, 8, 2, -4, xpm_sm_r_tt}, // target smaller, move right up
822 { 8, 8, 2, -2, xpm_sm_r_t}, // target smaller, move right up
823 { 8, 8, 2, 0, xpm_sm_r}, // target smaller, move right
824 { 8, 8, 2, 2, xpm_sm_r_b}, // target smaller, move right down
825 };
826
827 const wxImage src_img(xpm_orig);
828 for ( unsigned i = 0; i < WXSIZEOF(sizeTestData); i++ )
829 {
830 SizeTestData& st = sizeTestData[i];
831 wxImage
832 actual(src_img.Size(wxSize(st.w, st.h), wxPoint(st.dx, st.dy), 0, 0, 0)),
833 expected(st.ref_xpm);
834
835 // to check results with an image viewer uncomment this:
836 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
837 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
838
839 CPPUNIT_ASSERT_EQUAL( actual.GetSize().x, expected.GetSize().x );
840 CPPUNIT_ASSERT_EQUAL( actual.GetSize().y, expected.GetSize().y );
841
842 WX_ASSERT_EQUAL_MESSAGE
843 (
844 ("Resize test #%u: (%d, %d), (%d, %d)", i, st.w, st.h, st.dx, st.dy),
845 expected, actual
846 );
847 }
848 }
849
850 void ImageTestCase::CompareLoadedImage()
851 {
852 wxImage expected8("horse.xpm");
853 CPPUNIT_ASSERT( expected8.IsOk() );
854
855 wxImage expected24("horse.png");
856 CPPUNIT_ASSERT( expected24.IsOk() );
857
858 for (size_t i=0; i<WXSIZEOF(g_testfiles); i++)
859 {
860 if ( !(g_testfiles[i].bitDepth == 8 || g_testfiles[i].bitDepth == 24)
861 || g_testfiles[i].type == wxBITMAP_TYPE_JPEG /*skip lossy JPEG*/)
862 {
863 continue;
864 }
865
866 wxImage actual(g_testfiles[i].file);
867
868 if ( actual.GetSize() != expected8.GetSize() )
869 {
870 continue;
871 }
872
873
874 WX_ASSERT_EQUAL_MESSAGE
875 (
876 ("Compare test '%s' for loading failed", g_testfiles[i].file),
877 g_testfiles[i].bitDepth == 8 ? expected8 : expected24,
878 actual
879 );
880 }
881
882 }
883
884 enum
885 {
886 wxIMAGE_HAVE_ALPHA = (1 << 0),
887 wxIMAGE_HAVE_PALETTE = (1 << 1)
888 };
889
890 static
891 void CompareImage(const wxImageHandler& handler, const wxImage& image,
892 int properties = 0, const wxImage *compareTo = NULL)
893 {
894 wxBitmapType type = handler.GetType();
895
896 const bool testPalette = (properties & wxIMAGE_HAVE_PALETTE) != 0;
897 /*
898 This is getting messy and should probably be transformed into a table
899 with image format features before it gets hairier.
900 */
901 if ( testPalette
902 && ( !(type == wxBITMAP_TYPE_BMP
903 || type == wxBITMAP_TYPE_GIF
904 || type == wxBITMAP_TYPE_ICO
905 || type == wxBITMAP_TYPE_PNG)
906 || type == wxBITMAP_TYPE_XPM) )
907 {
908 return;
909 }
910
911 const bool testAlpha = (properties & wxIMAGE_HAVE_ALPHA) != 0;
912 if (testAlpha
913 && !(type == wxBITMAP_TYPE_PNG || type == wxBITMAP_TYPE_TGA
914 || type == wxBITMAP_TYPE_TIFF) )
915 {
916 // don't test images with alpha if this handler doesn't support alpha
917 return;
918 }
919
920 if (type == wxBITMAP_TYPE_JPEG /* skip lossy JPEG */)
921 {
922 return;
923 }
924
925 wxMemoryOutputStream memOut;
926 if ( !image.SaveFile(memOut, type) )
927 {
928 // Unfortunately we can't know if the handler just doesn't support
929 // saving images, or if it failed to save.
930 return;
931 }
932
933 wxMemoryInputStream memIn(memOut);
934 CPPUNIT_ASSERT(memIn.IsOk());
935
936 wxImage actual(memIn);
937 CPPUNIT_ASSERT(actual.IsOk());
938
939 const wxImage *expected = compareTo ? compareTo : &image;
940 CPPUNIT_ASSERT( actual.GetSize() == expected->GetSize() );
941
942 unsigned bitsPerPixel = testPalette ? 8 : (testAlpha ? 32 : 24);
943 WX_ASSERT_EQUAL_MESSAGE
944 (
945 ("Compare test '%s (%d-bit)' for saving failed",
946 handler.GetExtension(), bitsPerPixel),
947 *expected,
948 actual
949 );
950
951 #if wxUSE_PALETTE
952 CPPUNIT_ASSERT(actual.HasPalette()
953 == (testPalette || type == wxBITMAP_TYPE_XPM));
954 #endif
955
956 CPPUNIT_ASSERT( actual.HasAlpha() == testAlpha);
957
958 if (!testAlpha)
959 {
960 return;
961 }
962
963 WX_ASSERT_EQUAL_MESSAGE
964 (
965 ("Compare alpha test '%s' for saving failed", handler.GetExtension()),
966 *expected,
967 actual
968 );
969 }
970
971 static void SetAlpha(wxImage *image)
972 {
973 image->SetAlpha();
974
975 unsigned char *ptr = image->GetAlpha();
976 const int width = image->GetWidth();
977 const int height = image->GetHeight();
978 for (int y = 0; y < height; ++y)
979 {
980 for (int x = 0; x < width; ++x)
981 {
982 ptr[y*width + x] = (x*y) & wxIMAGE_ALPHA_OPAQUE;
983 }
984 }
985 }
986
987 void ImageTestCase::CompareSavedImage()
988 {
989 // FIXME-VC6: Pre-declare the loop variables for compatibility with
990 // pre-standard compilers such as MSVC6 that don't implement proper scope
991 // for the variables declared in the for loops.
992 int i;
993
994 wxImage expected24("horse.png");
995 CPPUNIT_ASSERT( expected24.IsOk() );
996 CPPUNIT_ASSERT( !expected24.HasAlpha() );
997
998 wxImage expected8 = expected24.ConvertToGreyscale();
999
1000 #if wxUSE_PALETTE
1001 unsigned char greys[256];
1002 for (i = 0; i < 256; ++i)
1003 {
1004 greys[i] = i;
1005 }
1006 wxPalette palette(256, greys, greys, greys);
1007 expected8.SetPalette(palette);
1008 #endif // #if wxUSE_PALETTE
1009
1010 expected8.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP_PALETTE);
1011
1012 // Create an image with alpha based on the loaded image
1013 wxImage expected32(expected24);
1014
1015 SetAlpha(&expected32);
1016
1017 const wxList& list = wxImage::GetHandlers();
1018 for ( wxList::compatibility_iterator node = list.GetFirst();
1019 node; node = node->GetNext() )
1020 {
1021 wxImageHandler *handler = (wxImageHandler *) node->GetData();
1022
1023 #if wxUSE_PALETTE
1024 CompareImage(*handler, expected8, wxIMAGE_HAVE_PALETTE);
1025 #endif
1026 CompareImage(*handler, expected24);
1027 CompareImage(*handler, expected32, wxIMAGE_HAVE_ALPHA);
1028 }
1029 }
1030
1031 void ImageTestCase::SavePNG()
1032 {
1033 wxImage expected24("horse.png");
1034 CPPUNIT_ASSERT( expected24.IsOk() );
1035 #if wxUSE_PALETTE
1036 CPPUNIT_ASSERT( !expected24.HasPalette() );
1037 #endif // #if wxUSE_PALETTE
1038
1039 wxImage expected8 = expected24.ConvertToGreyscale();
1040
1041 /*
1042 horse.png converted to greyscale should be saved without a palette.
1043 */
1044 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG), expected8);
1045
1046 /*
1047 But if we explicitly ask for trying to save with a palette, it should work.
1048 */
1049 expected8.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_PALETTE);
1050
1051 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG),
1052 expected8, wxIMAGE_HAVE_PALETTE);
1053
1054
1055 CPPUNIT_ASSERT( expected8.LoadFile("horse.gif") );
1056 #if wxUSE_PALETTE
1057 CPPUNIT_ASSERT( expected8.HasPalette() );
1058 #endif // #if wxUSE_PALETTE
1059
1060 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG),
1061 expected8, wxIMAGE_HAVE_PALETTE);
1062
1063 /*
1064 Add alpha to the image in such a way that there will still be a maximum
1065 of 256 unique RGBA combinations. This should result in a saved
1066 PNG image still being palettised and having alpha.
1067 */
1068 expected8.SetAlpha();
1069
1070 int x, y;
1071 const int width = expected8.GetWidth();
1072 const int height = expected8.GetHeight();
1073 for (y = 0; y < height; ++y)
1074 {
1075 for (x = 0; x < width; ++x)
1076 {
1077 expected8.SetAlpha(x, y, expected8.GetRed(x, y));
1078 }
1079 }
1080
1081 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG),
1082 expected8, wxIMAGE_HAVE_ALPHA|wxIMAGE_HAVE_PALETTE);
1083
1084 /*
1085 Now change the alpha of the first pixel so that we can't save palettised
1086 anymore because there will be 256+1 entries which is beyond PNGs limit
1087 of 256 entries.
1088 */
1089 expected8.SetAlpha(0, 0, 1);
1090
1091 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG),
1092 expected8, wxIMAGE_HAVE_ALPHA);
1093
1094 /*
1095 Even if we explicitly ask for saving palettised it should not be done.
1096 */
1097 expected8.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_PALETTE);
1098 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG),
1099 expected8, wxIMAGE_HAVE_ALPHA);
1100
1101 }
1102
1103 static void TestTIFFImage(const wxString& option, int value,
1104 const wxImage *compareImage = NULL)
1105 {
1106 wxImage image;
1107 if (compareImage)
1108 {
1109 image = *compareImage;
1110 }
1111 else
1112 {
1113 (void) image.LoadFile("horse.png");
1114 }
1115 CPPUNIT_ASSERT( image.IsOk() );
1116
1117 wxMemoryOutputStream memOut;
1118 image.SetOption(option, value);
1119
1120 CPPUNIT_ASSERT(image.SaveFile(memOut, wxBITMAP_TYPE_TIFF));
1121
1122 wxMemoryInputStream memIn(memOut);
1123 CPPUNIT_ASSERT(memIn.IsOk());
1124
1125 wxImage savedImage(memIn);
1126 CPPUNIT_ASSERT(savedImage.IsOk());
1127
1128 WX_ASSERT_EQUAL_MESSAGE(("While checking for option %s", option),
1129 true, savedImage.HasOption(option));
1130
1131 WX_ASSERT_EQUAL_MESSAGE(("While testing for %s", option),
1132 value, savedImage.GetOptionInt(option));
1133
1134 WX_ASSERT_EQUAL_MESSAGE(("HasAlpha() not equal"), image.HasAlpha(), savedImage.HasAlpha());
1135 }
1136
1137 void ImageTestCase::SaveTIFF()
1138 {
1139 TestTIFFImage(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, 1);
1140 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 1);
1141 TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, 0/*PHOTOMETRIC_MINISWHITE*/);
1142 TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, 1/*PHOTOMETRIC_MINISBLACK*/);
1143
1144 wxImage alphaImage("horse.png");
1145 CPPUNIT_ASSERT( alphaImage.IsOk() );
1146 SetAlpha(&alphaImage);
1147
1148 // RGB with alpha
1149 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 4, &alphaImage);
1150
1151 // Grey with alpha
1152 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 2, &alphaImage);
1153
1154 // B/W with alpha
1155 alphaImage.SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, 1);
1156 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 2, &alphaImage);
1157 }
1158
1159 void ImageTestCase::SaveAnimatedGIF()
1160 {
1161 #if wxUSE_PALETTE
1162 wxImage image("horse.gif");
1163 CPPUNIT_ASSERT( image.IsOk() );
1164
1165 wxImageArray images;
1166 images.Add(image);
1167 int i;
1168 for (i = 0; i < 4-1; ++i)
1169 {
1170 images.Add( images[i].Rotate90() );
1171
1172 images[i+1].SetPalette(images[0].GetPalette());
1173 }
1174
1175 wxMemoryOutputStream memOut;
1176 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images, &memOut) );
1177
1178 wxGIFHandler handler;
1179 wxMemoryInputStream memIn(memOut);
1180 CPPUNIT_ASSERT(memIn.IsOk());
1181 const int imageCount = handler.GetImageCount(memIn);
1182 CPPUNIT_ASSERT_EQUAL(4, imageCount);
1183
1184 for (i = 0; i < imageCount; ++i)
1185 {
1186 wxFileOffset pos = memIn.TellI();
1187 CPPUNIT_ASSERT( handler.LoadFile(&image, memIn, true, i) );
1188 memIn.SeekI(pos);
1189
1190 WX_ASSERT_EQUAL_MESSAGE
1191 (
1192 ("Compare test for GIF frame number %d failed", i),
1193 images[i],
1194 image
1195 );
1196 }
1197 #endif // #if wxUSE_PALETTE
1198 }
1199
1200 void ImageTestCase::ReadCorruptedTGA()
1201 {
1202 static unsigned char corruptTGA[18+1+3] =
1203 {
1204 0,
1205 0,
1206 10, // RLE compressed image.
1207 0, 0,
1208 0, 0,
1209 0,
1210 0, 0,
1211 0, 0,
1212 1, 0, // Width is 1.
1213 1, 0, // Height is 1.
1214 24, // Bits per pixel.
1215 0,
1216
1217 0xff, // Run length (repeat next pixel 127+1 times).
1218 0xff, 0xff, 0xff // One 24-bit pixel.
1219 };
1220
1221 wxMemoryInputStream memIn(corruptTGA, WXSIZEOF(corruptTGA));
1222 CPPUNIT_ASSERT(memIn.IsOk());
1223
1224 wxImage tgaImage;
1225 CPPUNIT_ASSERT( !tgaImage.LoadFile(memIn) );
1226
1227
1228 /*
1229 Instead of repeating a pixel 127+1 times, now tell it there will
1230 follow 127+1 uncompressed pixels (while we only should have 1 in total).
1231 */
1232 corruptTGA[18] = 0x7f;
1233 CPPUNIT_ASSERT( !tgaImage.LoadFile(memIn) );
1234 }
1235
1236 static void TestGIFComment(const wxString& comment)
1237 {
1238 wxImage image("horse.gif");
1239
1240 image.SetOption(wxIMAGE_OPTION_GIF_COMMENT, comment);
1241 wxMemoryOutputStream memOut;
1242 CPPUNIT_ASSERT(image.SaveFile(memOut, wxBITMAP_TYPE_GIF));
1243
1244 wxMemoryInputStream memIn(memOut);
1245 CPPUNIT_ASSERT( image.LoadFile(memIn) );
1246
1247 CPPUNIT_ASSERT_EQUAL(comment,
1248 image.GetOption(wxIMAGE_OPTION_GIF_COMMENT));
1249 }
1250
1251 void ImageTestCase::GIFComment()
1252 {
1253 // Test reading a comment.
1254 wxImage image("horse.gif");
1255 CPPUNIT_ASSERT_EQUAL(" Imported from GRADATION image: gray",
1256 image.GetOption(wxIMAGE_OPTION_GIF_COMMENT));
1257
1258
1259 // Test writing a comment and reading it back.
1260 TestGIFComment("Giving the GIF a gifted giraffe as a gift");
1261
1262
1263 // Test writing and reading a comment again but with a long comment.
1264 TestGIFComment(wxString(wxT('a'), 256)
1265 + wxString(wxT('b'), 256)
1266 + wxString(wxT('c'), 256));
1267
1268
1269 // Test writing comments in an animated GIF and reading them back.
1270 CPPUNIT_ASSERT( image.LoadFile("horse.gif") );
1271
1272 wxImageArray images;
1273 int i;
1274 for (i = 0; i < 4; ++i)
1275 {
1276 if (i)
1277 {
1278 images.Add( images[i-1].Rotate90() );
1279 images[i].SetPalette(images[0].GetPalette());
1280 }
1281 else
1282 {
1283 images.Add(image);
1284 }
1285
1286 images[i].SetOption(wxIMAGE_OPTION_GIF_COMMENT,
1287 wxString::Format("GIF comment for frame #%d", i+1));
1288
1289 }
1290
1291
1292 wxMemoryOutputStream memOut;
1293 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images, &memOut) );
1294
1295 wxGIFHandler handler;
1296 wxMemoryInputStream memIn(memOut);
1297 CPPUNIT_ASSERT(memIn.IsOk());
1298 const int imageCount = handler.GetImageCount(memIn);
1299 for (i = 0; i < imageCount; ++i)
1300 {
1301 wxFileOffset pos = memIn.TellI();
1302 CPPUNIT_ASSERT( handler.LoadFile(&image, memIn, true /*verbose?*/, i) );
1303
1304 CPPUNIT_ASSERT_EQUAL(
1305 wxString::Format("GIF comment for frame #%d", i+1),
1306 image.GetOption(wxIMAGE_OPTION_GIF_COMMENT));
1307 memIn.SeekI(pos);
1308 }
1309 }
1310
1311 void ImageTestCase::DibPadding()
1312 {
1313 /*
1314 There used to be an error with calculating the DWORD aligned scan line
1315 pitch for a BMP/ICO resulting in buffer overwrites (with at least MSVC9
1316 Debug this gave a heap corruption assertion when saving the mask of
1317 an ICO). Test for it here.
1318 */
1319 wxImage image("horse.gif");
1320 CPPUNIT_ASSERT( image.IsOk() );
1321
1322 image = image.Scale(99, 99);
1323
1324 wxMemoryOutputStream memOut;
1325 CPPUNIT_ASSERT( image.SaveFile(memOut, wxBITMAP_TYPE_ICO) );
1326 }
1327
1328 static void CompareBMPImage(const wxString& file1, const wxString& file2)
1329 {
1330 wxImage image1(file1);
1331 CPPUNIT_ASSERT( image1.IsOk() );
1332
1333 wxImage image2(file2);
1334 CPPUNIT_ASSERT( image2.IsOk() );
1335
1336 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_BMP), image1, 0, &image2);
1337 }
1338
1339 void ImageTestCase::BMPFlippingAndRLECompression()
1340 {
1341 CompareBMPImage("image/horse_grey.bmp", "image/horse_grey_flipped.bmp");
1342
1343 CompareBMPImage("image/horse_rle8.bmp", "image/horse_grey.bmp");
1344 CompareBMPImage("image/horse_rle8.bmp", "image/horse_rle8_flipped.bmp");
1345
1346 CompareBMPImage("image/horse_rle4.bmp", "image/horse_rle4_flipped.bmp");
1347 }
1348
1349
1350 #define ASSERT_IMAGE_EQUAL_TO_FILE(image, file) \
1351 { \
1352 wxImage imageFromFile(file); \
1353 CPPUNIT_ASSERT_MESSAGE( "Failed to load " file, imageFromFile.IsOk() ); \
1354 CPPUNIT_ASSERT_EQUAL( imageFromFile, image ); \
1355 }
1356
1357 void ImageTestCase::ScaleCompare()
1358 {
1359 wxImage original;
1360 CPPUNIT_ASSERT(original.LoadFile("horse.bmp"));
1361
1362 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale( 50, 50, wxIMAGE_QUALITY_BICUBIC),
1363 "image/horse_bicubic_50x50.png");
1364 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(100, 100, wxIMAGE_QUALITY_BICUBIC),
1365 "image/horse_bicubic_100x100.png");
1366 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(150, 150, wxIMAGE_QUALITY_BICUBIC),
1367 "image/horse_bicubic_150x150.png");
1368 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(300, 300, wxIMAGE_QUALITY_BICUBIC),
1369 "image/horse_bicubic_300x300.png");
1370
1371 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale( 50, 50, wxIMAGE_QUALITY_BOX_AVERAGE),
1372 "image/horse_box_average_50x50.png");
1373 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(100, 100, wxIMAGE_QUALITY_BOX_AVERAGE),
1374 "image/horse_box_average_100x100.png");
1375 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(150, 150, wxIMAGE_QUALITY_BOX_AVERAGE),
1376 "image/horse_box_average_150x150.png");
1377 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(300, 300, wxIMAGE_QUALITY_BOX_AVERAGE),
1378 "image/horse_box_average_300x300.png");
1379
1380 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale( 50, 50, wxIMAGE_QUALITY_BILINEAR),
1381 "image/horse_bilinear_50x50.png");
1382 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(100, 100, wxIMAGE_QUALITY_BILINEAR),
1383 "image/horse_bilinear_100x100.png");
1384 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(150, 150, wxIMAGE_QUALITY_BILINEAR),
1385 "image/horse_bilinear_150x150.png");
1386 ASSERT_IMAGE_EQUAL_TO_FILE(original.Scale(300, 300, wxIMAGE_QUALITY_BILINEAR),
1387 "image/horse_bilinear_300x300.png");
1388 }
1389
1390 #endif //wxUSE_IMAGE
1391
1392
1393 /*
1394 TODO: add lots of more tests to wxImage functions
1395 */