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