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
27 #include "wx/palette.h"
30 #include "wx/mstream.h"
31 #include "wx/zstream.h"
32 #include "wx/wfstream.h"
34 #include "testimage.h"
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 }
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 class ImageTestCase
: public CppUnit
::TestCase
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( SaveTIFF
);
77 CPPUNIT_TEST( SaveAnimatedGIF
);
78 CPPUNIT_TEST( ReadCorruptedTGA
);
79 CPPUNIT_TEST( GIFComment
);
80 CPPUNIT_TEST( DibPadding
);
81 CPPUNIT_TEST( BMPFlippingAndRLECompression
);
82 CPPUNIT_TEST_SUITE_END();
84 void LoadFromSocketStream();
85 void LoadFromZipStream();
88 void CompareLoadedImage();
89 void CompareSavedImage();
92 void SaveAnimatedGIF();
93 void ReadCorruptedTGA();
96 void BMPFlippingAndRLECompression();
98 DECLARE_NO_COPY_CLASS(ImageTestCase
)
101 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase
);
102 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase
, "ImageTestCase" );
104 ImageTestCase
::ImageTestCase()
106 wxSocketBase
::Initialize();
108 // the formats we're going to test:
109 wxImage
::AddHandler(new wxICOHandler
);
110 wxImage
::AddHandler(new wxXPMHandler
);
111 wxImage
::AddHandler(new wxPNGHandler
);
112 wxImage
::AddHandler(new wxANIHandler
);
113 wxImage
::AddHandler(new wxBMPHandler
);
114 wxImage
::AddHandler(new wxCURHandler
);
115 wxImage
::AddHandler(new wxGIFHandler
);
116 wxImage
::AddHandler(new wxJPEGHandler
);
117 wxImage
::AddHandler(new wxPCXHandler
);
118 wxImage
::AddHandler(new wxPNMHandler
);
119 wxImage
::AddHandler(new wxTGAHandler
);
120 wxImage
::AddHandler(new wxTIFFHandler
);
123 ImageTestCase
::~ImageTestCase()
125 wxSocketBase
::Shutdown();
128 void ImageTestCase
::LoadFromFile()
131 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
132 CPPUNIT_ASSERT(img
.LoadFile(g_testfiles
[i
].file
));
135 void ImageTestCase
::LoadFromSocketStream()
137 if (!IsNetworkAvailable()) // implemented in test.cpp
139 wxLogWarning("No network connectivity; skipping the "
140 "ImageTestCase::LoadFromSocketStream test unit.");
149 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG
},
150 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO
}
153 for (unsigned int i
=0; i
<WXSIZEOF(testData
); i
++)
155 wxURL
url(testData
[i
].url
);
156 WX_ASSERT_EQUAL_MESSAGE
158 ("Constructing URL \"%s\" failed.", testData
[i
].url
),
163 wxInputStream
*in_stream
= url
.GetInputStream();
166 ("Opening URL \"%s\" failed.", testData
[i
].url
),
167 in_stream
&& in_stream
->IsOk()
172 // NOTE: it's important to inform wxImage about the type of the image being
173 // loaded otherwise it will try to autodetect the format, but that
174 // requires a seekable stream!
177 ("Loading image from \"%s\" failed.", testData
[i
].url
),
178 img
.LoadFile(*in_stream
, testData
[i
].type
)
185 void ImageTestCase
::LoadFromZipStream()
187 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
189 switch (g_testfiles
[i
].type
)
191 case wxBITMAP_TYPE_XPM
:
192 case wxBITMAP_TYPE_GIF
:
193 case wxBITMAP_TYPE_PCX
:
194 case wxBITMAP_TYPE_TGA
:
195 case wxBITMAP_TYPE_TIF
:
196 continue; // skip testing those wxImageHandlers which cannot
197 // load data from non-seekable streams
203 // compress the test file on the fly:
204 wxMemoryOutputStream memOut
;
206 wxFileInputStream
file(g_testfiles
[i
].file
);
207 CPPUNIT_ASSERT(file
.IsOk());
209 wxZlibOutputStream
compressFilter(memOut
, 5, wxZLIB_GZIP
);
210 CPPUNIT_ASSERT(compressFilter
.IsOk());
212 file
.Read(compressFilter
);
213 CPPUNIT_ASSERT(file
.GetLastError() == wxSTREAM_EOF
);
216 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
217 // allows us to test loading images from non-seekable streams other than socket streams
218 wxMemoryInputStream
memIn(memOut
);
219 CPPUNIT_ASSERT(memIn
.IsOk());
220 wxZlibInputStream
decompressFilter(memIn
, wxZLIB_GZIP
);
221 CPPUNIT_ASSERT(decompressFilter
.IsOk());
225 // NOTE: it's important to inform wxImage about the type of the image being
226 // loaded otherwise it will try to autodetect the format, but that
227 // requires a seekable stream!
228 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles
[i
].type
),
229 img
.LoadFile(decompressFilter
, g_testfiles
[i
].type
));
233 void ImageTestCase
::SizeImage()
235 // Test the wxImage::Size() function which takes a rectangle from source and
236 // places it in a new image at a given position. This test checks, if the
237 // correct areas are chosen, and clipping is done correctly.
240 static const char * xpm_orig
[] = {
241 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
253 // the expected results for all tests:
254 static const char * xpm_l_t
[] = {
255 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
267 static const char * xpm_t
[] = {
268 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
280 static const char * xpm_r_t
[] = {
281 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
293 static const char * xpm_l
[] = {
294 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
306 static const char * xpm_r
[] = {
307 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
319 static const char * xpm_l_b
[] = {
320 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
332 static const char * xpm_b
[] = {
333 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
345 static const char * xpm_r_b
[] = {
346 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
358 static const char * xpm_sm
[] = {
359 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
369 static const char * xpm_gt
[] = {
370 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
384 static const char * xpm_gt_l_t
[] = {
385 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
399 static const char * xpm_gt_l
[] = {
400 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
414 static const char * xpm_gt_l_b
[] = {
415 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
429 static const char * xpm_gt_l_bb
[] = {
430 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
444 static const char * xpm_gt_t
[] = {
445 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
459 static const char * xpm_gt_b
[] = {
460 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
474 static const char * xpm_gt_bb
[] = {
475 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
489 static const char * xpm_gt_r_t
[] = {
490 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
504 static const char * xpm_gt_r
[] = {
505 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
519 static const char * xpm_gt_r_b
[] = {
520 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
534 static const char * xpm_gt_r_bb
[] = {
535 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
549 static const char * xpm_gt_rr_t
[] = {
550 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
564 static const char * xpm_gt_rr
[] = {
565 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
579 static const char * xpm_gt_rr_b
[] = {
580 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
594 static const char * xpm_gt_rr_bb
[] = {
595 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
609 static const char * xpm_sm_ll_tt
[] = {
610 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
620 static const char * xpm_sm_ll_t
[] = {
621 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
631 static const char * xpm_sm_ll
[] = {
632 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
642 static const char * xpm_sm_ll_b
[] = {
643 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
653 static const char * xpm_sm_l_tt
[] = {
654 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
664 static const char * xpm_sm_l_t
[] = {
665 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
675 static const char * xpm_sm_l
[] = {
676 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
686 static const char * xpm_sm_l_b
[] = {
687 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
697 static const char * xpm_sm_tt
[] = {
698 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
708 static const char * xpm_sm_t
[] = {
709 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
719 static const char * xpm_sm_b
[] = {
720 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
730 static const char * xpm_sm_r_tt
[] = {
731 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
741 static const char * xpm_sm_r_t
[] = {
742 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
752 static const char * xpm_sm_r
[] = {
753 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
763 static const char * xpm_sm_r_b
[] = {
764 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
775 // this table defines all tests
778 int w
, h
, dx
, dy
; // first parameters for Size()
779 const char **ref_xpm
; // expected result
782 { 10, 10, 0, 0, xpm_orig
}, // same size, same position
783 { 12, 12, 0, 0, xpm_gt
}, // target larger, same position
784 { 8, 8, 0, 0, xpm_sm
}, // target smaller, same position
785 { 10, 10, -2, -2, xpm_l_t
}, // same size, move left up
786 { 10, 10, -2, 0, xpm_l
}, // same size, move left
787 { 10, 10, -2, 2, xpm_l_b
}, // same size, move left down
788 { 10, 10, 0, -2, xpm_t
}, // same size, move up
789 { 10, 10, 0, 2, xpm_b
}, // same size, move down
790 { 10, 10, 2, -2, xpm_r_t
}, // same size, move right up
791 { 10, 10, 2, 0, xpm_r
}, // same size, move right
792 { 10, 10, 2, 2, xpm_r_b
}, // same size, move right down
793 { 12, 12, -2, -2, xpm_gt_l_t
}, // target larger, move left up
794 { 12, 12, -2, 0, xpm_gt_l
}, // target larger, move left
795 { 12, 12, -2, 2, xpm_gt_l_b
}, // target larger, move left down
796 { 12, 12, -2, 4, xpm_gt_l_bb
}, // target larger, move left down
797 { 12, 12, 0, -2, xpm_gt_t
}, // target larger, move up
798 { 12, 12, 0, 2, xpm_gt_b
}, // target larger, move down
799 { 12, 12, 0, 4, xpm_gt_bb
}, // target larger, move down
800 { 12, 12, 2, -2, xpm_gt_r_t
}, // target larger, move right up
801 { 12, 12, 2, 0, xpm_gt_r
}, // target larger, move right
802 { 12, 12, 2, 2, xpm_gt_r_b
}, // target larger, move right down
803 { 12, 12, 2, 4, xpm_gt_r_bb
}, // target larger, move right down
804 { 12, 12, 4, -2, xpm_gt_rr_t
}, // target larger, move right up
805 { 12, 12, 4, 0, xpm_gt_rr
}, // target larger, move right
806 { 12, 12, 4, 2, xpm_gt_rr_b
}, // target larger, move right down
807 { 12, 12, 4, 4, xpm_gt_rr_bb
}, // target larger, move right down
808 { 8, 8, -4, -4, xpm_sm_ll_tt
}, // target smaller, move left up
809 { 8, 8, -4, -2, xpm_sm_ll_t
}, // target smaller, move left up
810 { 8, 8, -4, 0, xpm_sm_ll
}, // target smaller, move left
811 { 8, 8, -4, 2, xpm_sm_ll_b
}, // target smaller, move left down
812 { 8, 8, -2, -4, xpm_sm_l_tt
}, // target smaller, move left up
813 { 8, 8, -2, -2, xpm_sm_l_t
}, // target smaller, move left up
814 { 8, 8, -2, 0, xpm_sm_l
}, // target smaller, move left
815 { 8, 8, -2, 2, xpm_sm_l_b
}, // target smaller, move left down
816 { 8, 8, 0, -4, xpm_sm_tt
}, // target smaller, move up
817 { 8, 8, 0, -2, xpm_sm_t
}, // target smaller, move up
818 { 8, 8, 0, 2, xpm_sm_b
}, // target smaller, move down
819 { 8, 8, 2, -4, xpm_sm_r_tt
}, // target smaller, move right up
820 { 8, 8, 2, -2, xpm_sm_r_t
}, // target smaller, move right up
821 { 8, 8, 2, 0, xpm_sm_r
}, // target smaller, move right
822 { 8, 8, 2, 2, xpm_sm_r_b
}, // target smaller, move right down
825 const wxImage
src_img(xpm_orig
);
826 for ( unsigned i
= 0; i
< WXSIZEOF(sizeTestData
); i
++ )
828 SizeTestData
& st
= sizeTestData
[i
];
830 actual(src_img
.Size(wxSize(st
.w
, st
.h
), wxPoint(st
.dx
, st
.dy
), 0, 0, 0)),
831 expected(st
.ref_xpm
);
833 // to check results with an image viewer uncomment this:
834 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
835 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
837 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().x
, expected
.GetSize().x
);
838 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().y
, expected
.GetSize().y
);
840 WX_ASSERT_EQUAL_MESSAGE
842 ("Resize test #%u: (%d, %d), (%d, %d)", i
, st
.w
, st
.h
, st
.dx
, st
.dy
),
848 void ImageTestCase
::CompareLoadedImage()
850 wxImage
expected8("horse.xpm");
851 CPPUNIT_ASSERT( expected8
.IsOk() );
853 wxImage
expected24("horse.png");
854 CPPUNIT_ASSERT( expected24
.IsOk() );
856 for (size_t i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
858 if ( !(g_testfiles
[i
].bitDepth
== 8 || g_testfiles
[i
].bitDepth
== 24)
859 || g_testfiles
[i
].type
== wxBITMAP_TYPE_JPEG
/*skip lossy JPEG*/)
864 wxImage
actual(g_testfiles
[i
].file
);
866 if ( actual
.GetSize() != expected8
.GetSize() )
872 WX_ASSERT_EQUAL_MESSAGE
874 ("Compare test '%s' for loading failed", g_testfiles
[i
].file
),
875 g_testfiles
[i
].bitDepth
== 8 ? expected8
: expected24
,
884 wxIMAGE_HAVE_ALPHA
= (1 << 0),
885 wxIMAGE_HAVE_PALETTE
= (1 << 1)
889 void CompareImage(const wxImageHandler
& handler
, const wxImage
& image
,
890 int properties
= 0, const wxImage
*compareTo
= NULL
)
892 wxBitmapType type
= handler
.GetType();
894 const bool testPalette
= (properties
& wxIMAGE_HAVE_PALETTE
) != 0;
896 This is getting messy and should probably be transformed into a table
897 with image format features before it gets hairier.
900 && ( !(type
== wxBITMAP_TYPE_BMP
901 || type
== wxBITMAP_TYPE_GIF
902 || type
== wxBITMAP_TYPE_ICO
903 || type
== wxBITMAP_TYPE_PNG
)
904 || type
== wxBITMAP_TYPE_XPM
) )
909 const bool testAlpha
= (properties
& wxIMAGE_HAVE_ALPHA
) != 0;
911 && !(type
== wxBITMAP_TYPE_PNG
|| type
== wxBITMAP_TYPE_TGA
) )
913 // don't test images with alpha if this handler doesn't support alpha
917 if (type
== wxBITMAP_TYPE_JPEG
/* skip lossy JPEG */)
922 wxMemoryOutputStream memOut
;
923 if ( !image
.SaveFile(memOut
, type
) )
925 // Unfortunately we can't know if the handler just doesn't support
926 // saving images, or if it failed to save.
930 wxMemoryInputStream
memIn(memOut
);
931 CPPUNIT_ASSERT(memIn
.IsOk());
933 wxImage
actual(memIn
);
934 CPPUNIT_ASSERT(actual
.IsOk());
936 const wxImage
*expected
= compareTo ? compareTo
: &image
;
937 CPPUNIT_ASSERT( actual
.GetSize() == expected
->GetSize() );
939 unsigned bitsPerPixel
= testPalette ?
8 : (testAlpha ?
32 : 24);
940 WX_ASSERT_EQUAL_MESSAGE
942 ("Compare test '%s (%d-bit)' for saving failed",
943 handler
.GetExtension(), bitsPerPixel
),
949 CPPUNIT_ASSERT(actual
.HasPalette()
950 == (testPalette
|| type
== wxBITMAP_TYPE_XPM
));
953 CPPUNIT_ASSERT( actual
.HasAlpha() == testAlpha
);
960 WX_ASSERT_EQUAL_MESSAGE
962 ("Compare alpha test '%s' for saving failed", handler
.GetExtension()),
968 void ImageTestCase
::CompareSavedImage()
970 // FIXME-VC6: Pre-declare the loop variables for compatibility with
971 // pre-standard compilers such as MSVC6 that don't implement proper scope
972 // for the variables declared in the for loops.
975 wxImage
expected24("horse.png");
976 CPPUNIT_ASSERT( expected24
.IsOk() );
977 CPPUNIT_ASSERT( !expected24
.HasAlpha() );
979 wxImage expected8
= expected24
.ConvertToGreyscale();
982 unsigned char greys
[256];
983 for (i
= 0; i
< 256; ++i
)
987 wxPalette
palette(256, greys
, greys
, greys
);
988 expected8
.SetPalette(palette
);
989 #endif // #if wxUSE_PALETTE
991 expected8
.SetOption(wxIMAGE_OPTION_BMP_FORMAT
, wxBMP_8BPP_PALETTE
);
993 // Create an image with alpha based on the loaded image
994 wxImage
expected32(expected24
);
995 expected32
.SetAlpha();
997 int width
= expected32
.GetWidth();
998 int height
= expected32
.GetHeight();
999 for (y
= 0; y
< height
; ++y
)
1001 for (x
= 0; x
< width
; ++x
)
1003 expected32
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1007 const wxList
& list
= wxImage
::GetHandlers();
1008 for ( wxList
::compatibility_iterator node
= list
.GetFirst();
1009 node
; node
= node
->GetNext() )
1011 wxImageHandler
*handler
= (wxImageHandler
*) node
->GetData();
1014 CompareImage(*handler
, expected8
, wxIMAGE_HAVE_PALETTE
);
1016 CompareImage(*handler
, expected24
);
1017 CompareImage(*handler
, expected32
, wxIMAGE_HAVE_ALPHA
);
1021 void ImageTestCase
::SavePNG()
1023 wxImage
expected24("horse.png");
1024 CPPUNIT_ASSERT( expected24
.IsOk() );
1026 CPPUNIT_ASSERT( !expected24
.HasPalette() );
1027 #endif // #if wxUSE_PALETTE
1029 wxImage expected8
= expected24
.ConvertToGreyscale();
1032 horse.png converted to greyscale should be saved without a palette.
1034 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
), expected8
);
1037 But if we explicitly ask for trying to save with a palette, it should work.
1039 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1041 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
),
1042 expected8
, wxIMAGE_HAVE_PALETTE
);
1045 CPPUNIT_ASSERT( expected8
.LoadFile("horse.gif") );
1047 CPPUNIT_ASSERT( expected8
.HasPalette() );
1048 #endif // #if wxUSE_PALETTE
1050 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
),
1051 expected8
, wxIMAGE_HAVE_PALETTE
);
1054 Add alpha to the image in such a way that there will still be a maximum
1055 of 256 unique RGBA combinations. This should result in a saved
1056 PNG image still being palettised and having alpha.
1058 expected8
.SetAlpha();
1061 const int width
= expected8
.GetWidth();
1062 const int height
= expected8
.GetHeight();
1063 for (y
= 0; y
< height
; ++y
)
1065 for (x
= 0; x
< width
; ++x
)
1067 expected8
.SetAlpha(x
, y
, expected8
.GetRed(x
, y
));
1071 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
),
1072 expected8
, wxIMAGE_HAVE_ALPHA
|wxIMAGE_HAVE_PALETTE
);
1075 Now change the alpha of the first pixel so that we can't save palettised
1076 anymore because there will be 256+1 entries which is beyond PNGs limit
1079 expected8
.SetAlpha(0, 0, 1);
1081 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
),
1082 expected8
, wxIMAGE_HAVE_ALPHA
);
1085 Even if we explicitly ask for saving palettised it should not be done.
1087 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1088 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
),
1089 expected8
, wxIMAGE_HAVE_ALPHA
);
1093 static void TestTIFFImage(const wxString
& option
, int value
)
1095 wxImage
image("horse.png");
1097 wxMemoryOutputStream memOut
;
1098 image
.SetOption(option
, value
);
1100 CPPUNIT_ASSERT(image
.SaveFile(memOut
, wxBITMAP_TYPE_TIF
));
1102 wxMemoryInputStream
memIn(memOut
);
1103 CPPUNIT_ASSERT(memIn
.IsOk());
1105 wxImage
savedImage(memIn
);
1106 CPPUNIT_ASSERT(savedImage
.IsOk());
1108 WX_ASSERT_EQUAL_MESSAGE(("While checking for option %s", option
),
1109 true, savedImage
.HasOption(option
));
1111 WX_ASSERT_EQUAL_MESSAGE(("While testing for %s", option
),
1112 value
, savedImage
.GetOptionInt(option
));
1115 void ImageTestCase
::SaveTIFF()
1117 TestTIFFImage(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE
, 1);
1118 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL
, 1);
1121 void ImageTestCase
::SaveAnimatedGIF()
1124 wxImage
image("horse.gif");
1125 CPPUNIT_ASSERT( image
.IsOk() );
1127 wxImageArray images
;
1130 for (i
= 0; i
< 4-1; ++i
)
1132 images
.Add( images
[i
].Rotate90() );
1134 images
[i
+1].SetPalette(images
[0].GetPalette());
1137 wxMemoryOutputStream memOut
;
1138 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1140 wxGIFHandler handler
;
1141 wxMemoryInputStream
memIn(memOut
);
1142 CPPUNIT_ASSERT(memIn
.IsOk());
1143 const int imageCount
= handler
.GetImageCount(memIn
);
1144 CPPUNIT_ASSERT_EQUAL(4, imageCount
);
1146 for (i
= 0; i
< imageCount
; ++i
)
1148 wxFileOffset pos
= memIn
.TellI();
1149 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true, i
) );
1152 WX_ASSERT_EQUAL_MESSAGE
1154 ("Compare test for GIF frame number %d failed", i
),
1159 #endif // #if wxUSE_PALETTE
1162 void ImageTestCase
::ReadCorruptedTGA()
1164 static unsigned char corruptTGA
[18+1+3] =
1168 10, // RLE compressed image.
1174 1, 0, // Width is 1.
1175 1, 0, // Height is 1.
1176 24, // Bits per pixel.
1179 0xff, // Run length (repeat next pixel 127+1 times).
1180 0xff, 0xff, 0xff // One 24-bit pixel.
1183 wxMemoryInputStream
memIn(corruptTGA
, WXSIZEOF(corruptTGA
));
1184 CPPUNIT_ASSERT(memIn
.IsOk());
1187 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1191 Instead of repeating a pixel 127+1 times, now tell it there will
1192 follow 127+1 uncompressed pixels (while we only should have 1 in total).
1194 corruptTGA
[18] = 0x7f;
1195 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1198 static void TestGIFComment(const wxString
& comment
)
1200 wxImage
image("horse.gif");
1202 image
.SetOption(wxIMAGE_OPTION_GIF_COMMENT
, comment
);
1203 wxMemoryOutputStream memOut
;
1204 CPPUNIT_ASSERT(image
.SaveFile(memOut
, wxBITMAP_TYPE_GIF
));
1206 wxMemoryInputStream
memIn(memOut
);
1207 CPPUNIT_ASSERT( image
.LoadFile(memIn
) );
1209 CPPUNIT_ASSERT_EQUAL(comment
,
1210 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1213 void ImageTestCase
::GIFComment()
1215 // Test reading a comment.
1216 wxImage
image("horse.gif");
1217 CPPUNIT_ASSERT_EQUAL(" Imported from GRADATION image: gray",
1218 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1221 // Test writing a comment and reading it back.
1222 TestGIFComment("Giving the GIF a gifted giraffe as a gift");
1225 // Test writing and reading a comment again but with a long comment.
1226 TestGIFComment(wxString(wxT('a'), 256)
1227 + wxString(wxT('b'), 256)
1228 + wxString(wxT('c'), 256));
1231 // Test writing comments in an animated GIF and reading them back.
1232 CPPUNIT_ASSERT( image
.LoadFile("horse.gif") );
1234 wxImageArray images
;
1236 for (i
= 0; i
< 4; ++i
)
1240 images
.Add( images
[i
-1].Rotate90() );
1241 images
[i
].SetPalette(images
[0].GetPalette());
1248 images
[i
].SetOption(wxIMAGE_OPTION_GIF_COMMENT
,
1249 wxString
::Format("GIF comment for frame #%d", i
+1));
1254 wxMemoryOutputStream memOut
;
1255 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1257 wxGIFHandler handler
;
1258 wxMemoryInputStream
memIn(memOut
);
1259 CPPUNIT_ASSERT(memIn
.IsOk());
1260 const int imageCount
= handler
.GetImageCount(memIn
);
1261 for (i
= 0; i
< imageCount
; ++i
)
1263 wxFileOffset pos
= memIn
.TellI();
1264 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true /*verbose?*/, i
) );
1266 CPPUNIT_ASSERT_EQUAL(
1267 wxString
::Format("GIF comment for frame #%d", i
+1),
1268 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1273 void ImageTestCase
::DibPadding()
1276 There used to be an error with calculating the DWORD aligned scan line
1277 pitch for a BMP/ICO resulting in buffer overwrites (with at least MSVC9
1278 Debug this gave a heap corruption assertion when saving the mask of
1279 an ICO). Test for it here.
1281 wxImage
image("horse.gif");
1282 CPPUNIT_ASSERT( image
.IsOk() );
1284 image
= image
.Scale(99, 99);
1286 wxMemoryOutputStream memOut
;
1287 CPPUNIT_ASSERT( image
.SaveFile(memOut
, wxBITMAP_TYPE_ICO
) );
1290 static void CompareBMPImage(const wxString
& file1
, const wxString
& file2
)
1292 wxImage
image1(file1
);
1293 CPPUNIT_ASSERT( image1
.IsOk() );
1295 wxImage
image2(file2
);
1296 CPPUNIT_ASSERT( image2
.IsOk() );
1298 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_BMP
), image1
, 0, &image2
);
1301 void ImageTestCase
::BMPFlippingAndRLECompression()
1303 CompareBMPImage("image/horse_grey.bmp", "image/horse_grey_flipped.bmp");
1305 CompareBMPImage("image/horse_rle8.bmp", "image/horse_grey.bmp");
1306 CompareBMPImage("image/horse_rle8.bmp", "image/horse_rle8_flipped.bmp");
1308 CompareBMPImage("image/horse_rle4.bmp", "image/horse_rle4_flipped.bmp");
1310 #endif //wxUSE_IMAGE
1314 TODO: add lots of more tests to wxImage functions