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