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