1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/image/image.cpp
3 // Purpose: Test wxImage
4 // Author: Francesco Montorsi
7 // Copyright: (c) 2009 Francesco Montorsi
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ----------------------------------------------------------------------------
13 // ----------------------------------------------------------------------------
26 #include "wx/anidecod.h" // wxImageArray
28 #include "wx/palette.h"
31 #include "wx/mstream.h"
32 #include "wx/zstream.h"
33 #include "wx/wfstream.h"
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 }
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 class ImageTestCase
: public CppUnit::TestCase
67 CPPUNIT_TEST_SUITE( ImageTestCase
);
68 CPPUNIT_TEST( LoadFromSocketStream
);
69 CPPUNIT_TEST( LoadFromZipStream
);
70 CPPUNIT_TEST( LoadFromFile
);
71 CPPUNIT_TEST( SizeImage
);
72 CPPUNIT_TEST( CompareLoadedImage
);
73 CPPUNIT_TEST( CompareSavedImage
);
74 CPPUNIT_TEST( SavePNG
);
75 CPPUNIT_TEST( SaveAnimatedGIF
);
76 CPPUNIT_TEST( ReadCorruptedTGA
);
77 CPPUNIT_TEST( GIFComment
);
78 CPPUNIT_TEST( DibPadding
);
79 CPPUNIT_TEST_SUITE_END();
81 void LoadFromSocketStream();
82 void LoadFromZipStream();
85 void CompareLoadedImage();
86 void CompareSavedImage();
88 void SaveAnimatedGIF();
89 void ReadCorruptedTGA();
93 DECLARE_NO_COPY_CLASS(ImageTestCase
)
96 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase
);
97 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase
, "ImageTestCase" );
99 ImageTestCase::ImageTestCase()
101 wxSocketBase::Initialize();
103 // the formats we're going to test:
104 wxImage::AddHandler(new wxICOHandler
);
105 wxImage::AddHandler(new wxXPMHandler
);
106 wxImage::AddHandler(new wxPNGHandler
);
107 wxImage::AddHandler(new wxANIHandler
);
108 wxImage::AddHandler(new wxBMPHandler
);
109 wxImage::AddHandler(new wxCURHandler
);
110 wxImage::AddHandler(new wxGIFHandler
);
111 wxImage::AddHandler(new wxJPEGHandler
);
112 wxImage::AddHandler(new wxPCXHandler
);
113 wxImage::AddHandler(new wxPNMHandler
);
114 wxImage::AddHandler(new wxTGAHandler
);
115 wxImage::AddHandler(new wxTIFFHandler
);
118 ImageTestCase::~ImageTestCase()
120 wxSocketBase::Shutdown();
123 void ImageTestCase::LoadFromFile()
126 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
127 CPPUNIT_ASSERT(img
.LoadFile(g_testfiles
[i
].file
));
130 void ImageTestCase::LoadFromSocketStream()
132 if (!IsNetworkAvailable()) // implemented in test.cpp
134 wxLogWarning("No network connectivity; skipping the "
135 "ImageTestCase::LoadFromSocketStream test unit.");
144 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG
},
145 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO
}
148 for (unsigned int i
=0; i
<WXSIZEOF(testData
); i
++)
150 wxURL
url(testData
[i
].url
);
151 WX_ASSERT_EQUAL_MESSAGE
153 ("Constructing URL \"%s\" failed.", testData
[i
].url
),
158 wxInputStream
*in_stream
= url
.GetInputStream();
161 ("Opening URL \"%s\" failed.", testData
[i
].url
),
162 in_stream
&& in_stream
->IsOk()
167 // NOTE: it's important to inform wxImage about the type of the image being
168 // loaded otherwise it will try to autodetect the format, but that
169 // requires a seekable stream!
172 ("Loading image from \"%s\" failed.", testData
[i
].url
),
173 img
.LoadFile(*in_stream
, testData
[i
].type
)
180 void ImageTestCase::LoadFromZipStream()
182 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
184 switch (g_testfiles
[i
].type
)
186 case wxBITMAP_TYPE_XPM
:
187 case wxBITMAP_TYPE_GIF
:
188 case wxBITMAP_TYPE_PCX
:
189 case wxBITMAP_TYPE_TGA
:
190 case wxBITMAP_TYPE_TIF
:
191 continue; // skip testing those wxImageHandlers which cannot
192 // load data from non-seekable streams
198 // compress the test file on the fly:
199 wxMemoryOutputStream memOut
;
201 wxFileInputStream
file(g_testfiles
[i
].file
);
202 CPPUNIT_ASSERT(file
.IsOk());
204 wxZlibOutputStream
compressFilter(memOut
, 5, wxZLIB_GZIP
);
205 CPPUNIT_ASSERT(compressFilter
.IsOk());
207 file
.Read(compressFilter
);
208 CPPUNIT_ASSERT(file
.GetLastError() == wxSTREAM_EOF
);
211 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
212 // allows us to test loading images from non-seekable streams other than socket streams
213 wxMemoryInputStream
memIn(memOut
);
214 CPPUNIT_ASSERT(memIn
.IsOk());
215 wxZlibInputStream
decompressFilter(memIn
, wxZLIB_GZIP
);
216 CPPUNIT_ASSERT(decompressFilter
.IsOk());
220 // NOTE: it's important to inform wxImage about the type of the image being
221 // loaded otherwise it will try to autodetect the format, but that
222 // requires a seekable stream!
223 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles
[i
].type
),
224 img
.LoadFile(decompressFilter
, g_testfiles
[i
].type
));
228 void ImageTestCase::SizeImage()
230 // Test the wxImage::Size() function which takes a rectangle from source and
231 // places it in a new image at a given position. This test checks, if the
232 // correct areas are chosen, and clipping is done correctly.
235 static const char * xpm_orig
[] = {
236 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
248 // the expected results for all tests:
249 static const char * xpm_l_t
[] = {
250 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
262 static const char * xpm_t
[] = {
263 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
275 static const char * xpm_r_t
[] = {
276 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
288 static const char * xpm_l
[] = {
289 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
301 static const char * xpm_r
[] = {
302 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
314 static const char * xpm_l_b
[] = {
315 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
327 static const char * xpm_b
[] = {
328 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
340 static const char * xpm_r_b
[] = {
341 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
353 static const char * xpm_sm
[] = {
354 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
364 static const char * xpm_gt
[] = {
365 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
379 static const char * xpm_gt_l_t
[] = {
380 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
394 static const char * xpm_gt_l
[] = {
395 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
409 static const char * xpm_gt_l_b
[] = {
410 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
424 static const char * xpm_gt_l_bb
[] = {
425 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
439 static const char * xpm_gt_t
[] = {
440 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
454 static const char * xpm_gt_b
[] = {
455 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
469 static const char * xpm_gt_bb
[] = {
470 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
484 static const char * xpm_gt_r_t
[] = {
485 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
499 static const char * xpm_gt_r
[] = {
500 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
514 static const char * xpm_gt_r_b
[] = {
515 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
529 static const char * xpm_gt_r_bb
[] = {
530 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
544 static const char * xpm_gt_rr_t
[] = {
545 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
559 static const char * xpm_gt_rr
[] = {
560 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
574 static const char * xpm_gt_rr_b
[] = {
575 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
589 static const char * xpm_gt_rr_bb
[] = {
590 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
604 static const char * xpm_sm_ll_tt
[] = {
605 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
615 static const char * xpm_sm_ll_t
[] = {
616 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
626 static const char * xpm_sm_ll
[] = {
627 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
637 static const char * xpm_sm_ll_b
[] = {
638 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
648 static const char * xpm_sm_l_tt
[] = {
649 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
659 static const char * xpm_sm_l_t
[] = {
660 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
670 static const char * xpm_sm_l
[] = {
671 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
681 static const char * xpm_sm_l_b
[] = {
682 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
692 static const char * xpm_sm_tt
[] = {
693 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
703 static const char * xpm_sm_t
[] = {
704 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
714 static const char * xpm_sm_b
[] = {
715 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
725 static const char * xpm_sm_r_tt
[] = {
726 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
736 static const char * xpm_sm_r_t
[] = {
737 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
747 static const char * xpm_sm_r
[] = {
748 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
758 static const char * xpm_sm_r_b
[] = {
759 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
770 // this table defines all tests
773 int w
, h
, dx
, dy
; // first parameters for Size()
774 const char **ref_xpm
; // expected result
777 { 10, 10, 0, 0, xpm_orig
}, // same size, same position
778 { 12, 12, 0, 0, xpm_gt
}, // target larger, same position
779 { 8, 8, 0, 0, xpm_sm
}, // target smaller, same position
780 { 10, 10, -2, -2, xpm_l_t
}, // same size, move left up
781 { 10, 10, -2, 0, xpm_l
}, // same size, move left
782 { 10, 10, -2, 2, xpm_l_b
}, // same size, move left down
783 { 10, 10, 0, -2, xpm_t
}, // same size, move up
784 { 10, 10, 0, 2, xpm_b
}, // same size, move down
785 { 10, 10, 2, -2, xpm_r_t
}, // same size, move right up
786 { 10, 10, 2, 0, xpm_r
}, // same size, move right
787 { 10, 10, 2, 2, xpm_r_b
}, // same size, move right down
788 { 12, 12, -2, -2, xpm_gt_l_t
}, // target larger, move left up
789 { 12, 12, -2, 0, xpm_gt_l
}, // target larger, move left
790 { 12, 12, -2, 2, xpm_gt_l_b
}, // target larger, move left down
791 { 12, 12, -2, 4, xpm_gt_l_bb
}, // target larger, move left down
792 { 12, 12, 0, -2, xpm_gt_t
}, // target larger, move up
793 { 12, 12, 0, 2, xpm_gt_b
}, // target larger, move down
794 { 12, 12, 0, 4, xpm_gt_bb
}, // target larger, move down
795 { 12, 12, 2, -2, xpm_gt_r_t
}, // target larger, move right up
796 { 12, 12, 2, 0, xpm_gt_r
}, // target larger, move right
797 { 12, 12, 2, 2, xpm_gt_r_b
}, // target larger, move right down
798 { 12, 12, 2, 4, xpm_gt_r_bb
}, // target larger, move right down
799 { 12, 12, 4, -2, xpm_gt_rr_t
}, // target larger, move right up
800 { 12, 12, 4, 0, xpm_gt_rr
}, // target larger, move right
801 { 12, 12, 4, 2, xpm_gt_rr_b
}, // target larger, move right down
802 { 12, 12, 4, 4, xpm_gt_rr_bb
}, // target larger, move right down
803 { 8, 8, -4, -4, xpm_sm_ll_tt
}, // target smaller, move left up
804 { 8, 8, -4, -2, xpm_sm_ll_t
}, // target smaller, move left up
805 { 8, 8, -4, 0, xpm_sm_ll
}, // target smaller, move left
806 { 8, 8, -4, 2, xpm_sm_ll_b
}, // target smaller, move left down
807 { 8, 8, -2, -4, xpm_sm_l_tt
}, // target smaller, move left up
808 { 8, 8, -2, -2, xpm_sm_l_t
}, // target smaller, move left up
809 { 8, 8, -2, 0, xpm_sm_l
}, // target smaller, move left
810 { 8, 8, -2, 2, xpm_sm_l_b
}, // target smaller, move left down
811 { 8, 8, 0, -4, xpm_sm_tt
}, // target smaller, move up
812 { 8, 8, 0, -2, xpm_sm_t
}, // target smaller, move up
813 { 8, 8, 0, 2, xpm_sm_b
}, // target smaller, move down
814 { 8, 8, 2, -4, xpm_sm_r_tt
}, // target smaller, move right up
815 { 8, 8, 2, -2, xpm_sm_r_t
}, // target smaller, move right up
816 { 8, 8, 2, 0, xpm_sm_r
}, // target smaller, move right
817 { 8, 8, 2, 2, xpm_sm_r_b
}, // target smaller, move right down
820 const wxImage
src_img(xpm_orig
);
821 for ( unsigned i
= 0; i
< WXSIZEOF(sizeTestData
); i
++ )
823 SizeTestData
& st
= sizeTestData
[i
];
825 actual(src_img
.Size(wxSize(st
.w
, st
.h
), wxPoint(st
.dx
, st
.dy
), 0, 0, 0)),
826 expected(st
.ref_xpm
);
828 // to check results with an image viewer uncomment this:
829 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
830 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
832 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().x
, expected
.GetSize().x
);
833 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().y
, expected
.GetSize().y
);
835 const unsigned data_len
= 3 * expected
.GetHeight() * expected
.GetWidth();
839 ("Resize test #%u: (%d, %d), (%d, %d)", i
, st
.w
, st
.h
, st
.dx
, st
.dy
),
840 memcmp(actual
.GetData(), expected
.GetData(), data_len
) == 0
845 void ImageTestCase::CompareLoadedImage()
847 wxImage
expected8("horse.xpm");
848 CPPUNIT_ASSERT( expected8
.IsOk() );
850 wxImage
expected24("horse.png");
851 CPPUNIT_ASSERT( expected24
.IsOk() );
853 const size_t dataLen
= expected8
.GetWidth() * expected8
.GetHeight() * 3;
855 for (size_t i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
857 if ( !(g_testfiles
[i
].bitDepth
== 8 || g_testfiles
[i
].bitDepth
== 24)
858 || g_testfiles
[i
].type
== wxBITMAP_TYPE_JPEG
/*skip lossy JPEG*/)
863 wxImage
actual(g_testfiles
[i
].file
);
865 if ( actual
.GetSize() != expected8
.GetSize() )
873 ("Compare test '%s' for loading failed", g_testfiles
[i
].file
),
875 memcmp(actual
.GetData(),
876 (g_testfiles
[i
].bitDepth
== 8)
877 ? expected8
.GetData()
878 : expected24
.GetData(),
887 wxIMAGE_HAVE_ALPHA
= (1 << 0),
888 wxIMAGE_HAVE_PALETTE
= (1 << 1)
892 void CompareImage(const wxImageHandler
& handler
, const wxImage
& image
,
893 int properties
= 0, const wxImage
*compareTo
= NULL
)
895 wxBitmapType type
= handler
.GetType();
897 const bool testPalette
= (properties
& wxIMAGE_HAVE_PALETTE
) != 0;
899 This is getting messy and should probably be transformed into a table
900 with image format features before it gets hairier.
903 && ( !(type
== wxBITMAP_TYPE_BMP
904 || type
== wxBITMAP_TYPE_GIF
905 || type
== wxBITMAP_TYPE_ICO
906 || type
== wxBITMAP_TYPE_PNG
)
907 || type
== wxBITMAP_TYPE_XPM
) )
912 const bool testAlpha
= (properties
& wxIMAGE_HAVE_ALPHA
) != 0;
914 && !(type
== wxBITMAP_TYPE_PNG
|| type
== wxBITMAP_TYPE_TGA
) )
916 // don't test images with alpha if this handler doesn't support alpha
920 if (type
== wxBITMAP_TYPE_JPEG
/* skip lossy JPEG */
921 || type
== wxBITMAP_TYPE_TIF
)
924 TIFF is skipped because the memory stream can't be loaded. Libtiff
925 looks for a TIFF directory at offset 120008 while the memory
926 stream size is only 120008 bytes (when saving as a file
927 the file size is 120280 bytes).
932 wxMemoryOutputStream memOut
;
933 if ( !image
.SaveFile(memOut
, type
) )
935 // Unfortunately we can't know if the handler just doesn't support
936 // saving images, or if it failed to save.
940 wxMemoryInputStream
memIn(memOut
);
941 CPPUNIT_ASSERT(memIn
.IsOk());
943 wxImage
actual(memIn
);
944 CPPUNIT_ASSERT(actual
.IsOk());
946 const wxImage
*expected
= compareTo
? compareTo
: &image
;
947 CPPUNIT_ASSERT( actual
.GetSize() == expected
->GetSize() );
949 unsigned bitsPerPixel
= testPalette
? 8 : (testAlpha
? 32 : 24);
952 ("Compare test '%s (%d-bit)' for saving failed",
953 handler
.GetExtension(), bitsPerPixel
),
955 memcmp(actual
.GetData(), expected
->GetData(),
956 expected
->GetWidth() * expected
->GetHeight() * 3) == 0
960 CPPUNIT_ASSERT(actual
.HasPalette()
961 == (testPalette
|| type
== wxBITMAP_TYPE_XPM
));
964 CPPUNIT_ASSERT( actual
.HasAlpha() == testAlpha
);
973 ("Compare alpha test '%s' for saving failed", handler
.GetExtension()),
975 memcmp(actual
.GetAlpha(), expected
->GetAlpha(),
976 expected
->GetWidth() * expected
->GetHeight()) == 0
980 void ImageTestCase::CompareSavedImage()
982 // FIXME-VC6: Pre-declare the loop variables for compatibility with
983 // pre-standard compilers such as MSVC6 that don't implement proper scope
984 // for the variables declared in the for loops.
987 wxImage
expected24("horse.png");
988 CPPUNIT_ASSERT( expected24
.IsOk() );
989 CPPUNIT_ASSERT( !expected24
.HasAlpha() );
991 wxImage expected8
= expected24
.ConvertToGreyscale();
994 unsigned char greys
[256];
995 for (i
= 0; i
< 256; ++i
)
999 wxPalette
palette(256, greys
, greys
, greys
);
1000 expected8
.SetPalette(palette
);
1001 #endif // #if wxUSE_PALETTE
1003 expected8
.SetOption(wxIMAGE_OPTION_BMP_FORMAT
, wxBMP_8BPP_PALETTE
);
1005 // Create an image with alpha based on the loaded image
1006 wxImage
expected32(expected24
);
1007 expected32
.SetAlpha();
1009 int width
= expected32
.GetWidth();
1010 int height
= expected32
.GetHeight();
1011 for (y
= 0; y
< height
; ++y
)
1013 for (x
= 0; x
< width
; ++x
)
1015 expected32
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1019 const wxList
& list
= wxImage::GetHandlers();
1020 for ( wxList::compatibility_iterator node
= list
.GetFirst();
1021 node
; node
= node
->GetNext() )
1023 wxImageHandler
*handler
= (wxImageHandler
*) node
->GetData();
1026 CompareImage(*handler
, expected8
, wxIMAGE_HAVE_PALETTE
);
1028 CompareImage(*handler
, expected24
);
1029 CompareImage(*handler
, expected32
, wxIMAGE_HAVE_ALPHA
);
1033 void ImageTestCase::SavePNG()
1035 wxImage
expected24("horse.png");
1036 CPPUNIT_ASSERT( expected24
.IsOk() );
1038 CPPUNIT_ASSERT( !expected24
.HasPalette() );
1039 #endif // #if wxUSE_PALETTE
1041 wxImage expected8
= expected24
.ConvertToGreyscale();
1044 horse.png converted to greyscale should be saved without a palette.
1046 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
), expected8
);
1049 But if we explicitly ask for trying to save with a palette, it should work.
1051 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1053 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1054 expected8
, wxIMAGE_HAVE_PALETTE
);
1057 CPPUNIT_ASSERT( expected8
.LoadFile("horse.gif") );
1059 CPPUNIT_ASSERT( expected8
.HasPalette() );
1060 #endif // #if wxUSE_PALETTE
1062 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1063 expected8
, wxIMAGE_HAVE_PALETTE
);
1066 Add alpha to the image in such a way that there will still be a maximum
1067 of 256 unique RGBA combinations. This should result in a saved
1068 PNG image still being palettised and having alpha.
1070 expected8
.SetAlpha();
1073 const int width
= expected8
.GetWidth();
1074 const int height
= expected8
.GetHeight();
1075 for (y
= 0; y
< height
; ++y
)
1077 for (x
= 0; x
< width
; ++x
)
1079 expected8
.SetAlpha(x
, y
, expected8
.GetRed(x
, y
));
1083 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1084 expected8
, wxIMAGE_HAVE_ALPHA
|wxIMAGE_HAVE_PALETTE
);
1087 Now change the alpha of the first pixel so that we can't save palettised
1088 anymore because there will be 256+1 entries which is beyond PNGs limit
1091 expected8
.SetAlpha(0, 0, 1);
1093 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1094 expected8
, wxIMAGE_HAVE_ALPHA
);
1097 Even if we explicitly ask for saving palettised it should not be done.
1099 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1100 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1101 expected8
, wxIMAGE_HAVE_ALPHA
);
1105 void ImageTestCase::SaveAnimatedGIF()
1108 wxImage
image("horse.gif");
1109 CPPUNIT_ASSERT( image
.IsOk() );
1111 wxImageArray images
;
1114 for (i
= 0; i
< 4-1; ++i
)
1116 images
.Add( images
[i
].Rotate90() );
1118 images
[i
+1].SetPalette(images
[0].GetPalette());
1121 wxMemoryOutputStream memOut
;
1122 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1124 wxGIFHandler handler
;
1125 wxMemoryInputStream
memIn(memOut
);
1126 CPPUNIT_ASSERT(memIn
.IsOk());
1127 const int imageCount
= handler
.GetImageCount(memIn
);
1128 CPPUNIT_ASSERT_EQUAL(4, imageCount
);
1130 for (i
= 0; i
< imageCount
; ++i
)
1132 wxFileOffset pos
= memIn
.TellI();
1133 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true, i
) );
1138 ("Compare test for GIF frame number %d failed", i
),
1139 memcmp(image
.GetData(), images
[i
].GetData(),
1140 images
[i
].GetWidth() * images
[i
].GetHeight() * 3) == 0
1143 #endif // #if wxUSE_PALETTE
1146 void ImageTestCase::ReadCorruptedTGA()
1148 static unsigned char corruptTGA
[18+1+3] =
1152 10, // RLE compressed image.
1158 1, 0, // Width is 1.
1159 1, 0, // Height is 1.
1160 24, // Bits per pixel.
1163 0xff, // Run length (repeat next pixel 127+1 times).
1164 0xff, 0xff, 0xff // One 24-bit pixel.
1167 wxMemoryInputStream
memIn(corruptTGA
, WXSIZEOF(corruptTGA
));
1168 CPPUNIT_ASSERT(memIn
.IsOk());
1171 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1175 Instead of repeating a pixel 127+1 times, now tell it there will
1176 follow 127+1 uncompressed pixels (while we only should have 1 in total).
1178 corruptTGA
[18] = 0x7f;
1179 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1182 static void TestGIFComment(const wxString
& comment
)
1184 wxImage
image("horse.gif");
1186 image
.SetOption(wxIMAGE_OPTION_GIF_COMMENT
, comment
);
1187 wxMemoryOutputStream memOut
;
1188 CPPUNIT_ASSERT(image
.SaveFile(memOut
, wxBITMAP_TYPE_GIF
));
1190 wxMemoryInputStream
memIn(memOut
);
1191 CPPUNIT_ASSERT( image
.LoadFile(memIn
) );
1193 CPPUNIT_ASSERT_EQUAL(comment
,
1194 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1197 void ImageTestCase::GIFComment()
1199 // Test reading a comment.
1200 wxImage
image("horse.gif");
1201 CPPUNIT_ASSERT_EQUAL(" Imported from GRADATION image: gray",
1202 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1205 // Test writing a comment and reading it back.
1206 TestGIFComment("Giving the GIF a gifted giraffe as a gift");
1209 // Test writing and reading a comment again but with a long comment.
1210 TestGIFComment(wxString(wxT('a'), 256)
1211 + wxString(wxT('b'), 256)
1212 + wxString(wxT('c'), 256));
1215 // Test writing comments in an animated GIF and reading them back.
1216 CPPUNIT_ASSERT( image
.LoadFile("horse.gif") );
1218 wxImageArray images
;
1220 for (i
= 0; i
< 4; ++i
)
1224 images
.Add( images
[i
-1].Rotate90() );
1225 images
[i
].SetPalette(images
[0].GetPalette());
1232 images
[i
].SetOption(wxIMAGE_OPTION_GIF_COMMENT
,
1233 wxString::Format("GIF comment for frame #%d", i
+1));
1238 wxMemoryOutputStream memOut
;
1239 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1241 wxGIFHandler handler
;
1242 wxMemoryInputStream
memIn(memOut
);
1243 CPPUNIT_ASSERT(memIn
.IsOk());
1244 const int imageCount
= handler
.GetImageCount(memIn
);
1245 for (i
= 0; i
< imageCount
; ++i
)
1247 wxFileOffset pos
= memIn
.TellI();
1248 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true /*verbose?*/, i
) );
1250 CPPUNIT_ASSERT_EQUAL(
1251 wxString::Format("GIF comment for frame #%d", i
+1),
1252 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1257 void ImageTestCase::DibPadding()
1260 There used to be an error with calculating the DWORD aligned scan line
1261 pitch for a BMP/ICO resulting in buffer overwrites (with at least MSVC9
1262 Debug this gave a heap corruption assertion when saving the mask of
1263 an ICO). Test for it here.
1265 wxImage
image("horse.gif");
1266 CPPUNIT_ASSERT( image
.IsOk() );
1268 image
= image
.Scale(99, 99);
1270 wxMemoryOutputStream memOut
;
1271 CPPUNIT_ASSERT( image
.SaveFile(memOut
, wxBITMAP_TYPE_ICO
) );
1274 #endif //wxUSE_IMAGE
1278 TODO: add lots of more tests to wxImage functions