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