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