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 // ----------------------------------------------------------------------------
29 #include "wx/mstream.h"
30 #include "wx/zstream.h"
31 #include "wx/wfstream.h"
39 { "horse.ico", wxBITMAP_TYPE_ICO
, 4 },
40 { "horse.xpm", wxBITMAP_TYPE_XPM
, 8 },
41 { "horse.png", wxBITMAP_TYPE_PNG
, 24 },
42 { "horse.ani", wxBITMAP_TYPE_ANI
, 24 },
43 { "horse.bmp", wxBITMAP_TYPE_BMP
, 8 },
44 { "horse.cur", wxBITMAP_TYPE_CUR
, 1 },
45 { "horse.gif", wxBITMAP_TYPE_GIF
, 8 },
46 { "horse.jpg", wxBITMAP_TYPE_JPEG
, 24 },
47 { "horse.pcx", wxBITMAP_TYPE_PCX
, 8 },
48 { "horse.pnm", wxBITMAP_TYPE_PNM
, 24 },
49 { "horse.tga", wxBITMAP_TYPE_TGA
, 8 },
50 { "horse.tif", wxBITMAP_TYPE_TIF
, 8 }
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 class ImageTestCase
: public CppUnit::TestCase
65 CPPUNIT_TEST_SUITE( ImageTestCase
);
66 CPPUNIT_TEST( LoadFromSocketStream
);
67 CPPUNIT_TEST( LoadFromZipStream
);
68 CPPUNIT_TEST( LoadFromFile
);
69 CPPUNIT_TEST( SizeImage
);
70 CPPUNIT_TEST( CompareLoadedImage
);
71 CPPUNIT_TEST( CompareSavedImage
);
72 CPPUNIT_TEST_SUITE_END();
74 void LoadFromSocketStream();
75 void LoadFromZipStream();
78 void CompareLoadedImage();
79 void CompareSavedImage();
81 DECLARE_NO_COPY_CLASS(ImageTestCase
)
84 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase
);
85 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase
, "ImageTestCase" );
87 ImageTestCase::ImageTestCase()
89 wxSocketBase::Initialize();
91 // the formats we're going to test:
92 wxImage::AddHandler(new wxICOHandler
);
93 wxImage::AddHandler(new wxXPMHandler
);
94 wxImage::AddHandler(new wxPNGHandler
);
95 wxImage::AddHandler(new wxANIHandler
);
96 wxImage::AddHandler(new wxBMPHandler
);
97 wxImage::AddHandler(new wxCURHandler
);
98 wxImage::AddHandler(new wxGIFHandler
);
99 wxImage::AddHandler(new wxJPEGHandler
);
100 wxImage::AddHandler(new wxPCXHandler
);
101 wxImage::AddHandler(new wxPNMHandler
);
102 wxImage::AddHandler(new wxTGAHandler
);
103 wxImage::AddHandler(new wxTIFFHandler
);
106 ImageTestCase::~ImageTestCase()
108 wxSocketBase::Shutdown();
111 void ImageTestCase::LoadFromFile()
114 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
115 CPPUNIT_ASSERT(img
.LoadFile(g_testfiles
[i
].file
));
118 void ImageTestCase::LoadFromSocketStream()
120 if (!IsNetworkAvailable()) // implemented in test.cpp
122 wxLogWarning("No network connectivity; skipping the "
123 "ImageTestCase::LoadFromSocketStream test unit.");
132 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG
},
133 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO
}
136 for (unsigned int i
=0; i
<WXSIZEOF(testData
); i
++)
138 wxURL
url(testData
[i
].url
);
139 WX_ASSERT_EQUAL_MESSAGE
141 ("Constructing URL \"%s\" failed.", testData
[i
].url
),
146 wxInputStream
*in_stream
= url
.GetInputStream();
149 ("Opening URL \"%s\" failed.", testData
[i
].url
),
150 in_stream
&& in_stream
->IsOk()
155 // NOTE: it's important to inform wxImage about the type of the image being
156 // loaded otherwise it will try to autodetect the format, but that
157 // requires a seekable stream!
160 ("Loading image from \"%s\" failed.", testData
[i
].url
),
161 img
.LoadFile(*in_stream
, testData
[i
].type
)
168 void ImageTestCase::LoadFromZipStream()
170 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
172 switch (g_testfiles
[i
].type
)
174 case wxBITMAP_TYPE_XPM
:
175 case wxBITMAP_TYPE_GIF
:
176 case wxBITMAP_TYPE_PCX
:
177 case wxBITMAP_TYPE_TGA
:
178 case wxBITMAP_TYPE_TIF
:
179 continue; // skip testing those wxImageHandlers which cannot
180 // load data from non-seekable streams
186 // compress the test file on the fly:
187 wxMemoryOutputStream memOut
;
189 wxFileInputStream
file(g_testfiles
[i
].file
);
190 CPPUNIT_ASSERT(file
.IsOk());
192 wxZlibOutputStream
compressFilter(memOut
, 5, wxZLIB_GZIP
);
193 CPPUNIT_ASSERT(compressFilter
.IsOk());
195 file
.Read(compressFilter
);
196 CPPUNIT_ASSERT(file
.GetLastError() == wxSTREAM_EOF
);
199 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
200 // allows us to test loading images from non-seekable streams other than socket streams
201 wxMemoryInputStream
memIn(memOut
);
202 CPPUNIT_ASSERT(memIn
.IsOk());
203 wxZlibInputStream
decompressFilter(memIn
, wxZLIB_GZIP
);
204 CPPUNIT_ASSERT(decompressFilter
.IsOk());
208 // NOTE: it's important to inform wxImage about the type of the image being
209 // loaded otherwise it will try to autodetect the format, but that
210 // requires a seekable stream!
211 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles
[i
].type
),
212 img
.LoadFile(decompressFilter
, g_testfiles
[i
].type
));
216 void ImageTestCase::SizeImage()
218 // Test the wxImage::Size() function which takes a rectangle from source and
219 // places it in a new image at a given position. This test checks, if the
220 // correct areas are chosen, and clipping is done correctly.
223 static const char * xpm_orig
[] = {
224 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
236 // the expected results for all tests:
237 static const char * xpm_l_t
[] = {
238 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
250 static const char * xpm_t
[] = {
251 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
263 static const char * xpm_r_t
[] = {
264 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
276 static const char * xpm_l
[] = {
277 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
289 static const char * xpm_r
[] = {
290 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
302 static const char * xpm_l_b
[] = {
303 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
315 static const char * xpm_b
[] = {
316 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
328 static const char * xpm_r_b
[] = {
329 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
341 static const char * xpm_sm
[] = {
342 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
352 static const char * xpm_gt
[] = {
353 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
367 static const char * xpm_gt_l_t
[] = {
368 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
382 static const char * xpm_gt_l
[] = {
383 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
397 static const char * xpm_gt_l_b
[] = {
398 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
412 static const char * xpm_gt_l_bb
[] = {
413 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
427 static const char * xpm_gt_t
[] = {
428 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
442 static const char * xpm_gt_b
[] = {
443 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
457 static const char * xpm_gt_bb
[] = {
458 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
472 static const char * xpm_gt_r_t
[] = {
473 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
487 static const char * xpm_gt_r
[] = {
488 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
502 static const char * xpm_gt_r_b
[] = {
503 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
517 static const char * xpm_gt_r_bb
[] = {
518 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
532 static const char * xpm_gt_rr_t
[] = {
533 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
547 static const char * xpm_gt_rr
[] = {
548 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
562 static const char * xpm_gt_rr_b
[] = {
563 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
577 static const char * xpm_gt_rr_bb
[] = {
578 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
592 static const char * xpm_sm_ll_tt
[] = {
593 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
603 static const char * xpm_sm_ll_t
[] = {
604 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
614 static const char * xpm_sm_ll
[] = {
615 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
625 static const char * xpm_sm_ll_b
[] = {
626 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
636 static const char * xpm_sm_l_tt
[] = {
637 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
647 static const char * xpm_sm_l_t
[] = {
648 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
658 static const char * xpm_sm_l
[] = {
659 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
669 static const char * xpm_sm_l_b
[] = {
670 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
680 static const char * xpm_sm_tt
[] = {
681 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
691 static const char * xpm_sm_t
[] = {
692 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
702 static const char * xpm_sm_b
[] = {
703 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
713 static const char * xpm_sm_r_tt
[] = {
714 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
724 static const char * xpm_sm_r_t
[] = {
725 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
735 static const char * xpm_sm_r
[] = {
736 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
746 static const char * xpm_sm_r_b
[] = {
747 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
758 // this table defines all tests
761 int w
, h
, dx
, dy
; // first parameters for Size()
762 const char **ref_xpm
; // expected result
765 { 10, 10, 0, 0, xpm_orig
}, // same size, same position
766 { 12, 12, 0, 0, xpm_gt
}, // target larger, same position
767 { 8, 8, 0, 0, xpm_sm
}, // target smaller, same position
768 { 10, 10, -2, -2, xpm_l_t
}, // same size, move left up
769 { 10, 10, -2, 0, xpm_l
}, // same size, move left
770 { 10, 10, -2, 2, xpm_l_b
}, // same size, move left down
771 { 10, 10, 0, -2, xpm_t
}, // same size, move up
772 { 10, 10, 0, 2, xpm_b
}, // same size, move down
773 { 10, 10, 2, -2, xpm_r_t
}, // same size, move right up
774 { 10, 10, 2, 0, xpm_r
}, // same size, move right
775 { 10, 10, 2, 2, xpm_r_b
}, // same size, move right down
776 { 12, 12, -2, -2, xpm_gt_l_t
}, // target larger, move left up
777 { 12, 12, -2, 0, xpm_gt_l
}, // target larger, move left
778 { 12, 12, -2, 2, xpm_gt_l_b
}, // target larger, move left down
779 { 12, 12, -2, 4, xpm_gt_l_bb
}, // target larger, move left down
780 { 12, 12, 0, -2, xpm_gt_t
}, // target larger, move up
781 { 12, 12, 0, 2, xpm_gt_b
}, // target larger, move down
782 { 12, 12, 0, 4, xpm_gt_bb
}, // target larger, move down
783 { 12, 12, 2, -2, xpm_gt_r_t
}, // target larger, move right up
784 { 12, 12, 2, 0, xpm_gt_r
}, // target larger, move right
785 { 12, 12, 2, 2, xpm_gt_r_b
}, // target larger, move right down
786 { 12, 12, 2, 4, xpm_gt_r_bb
}, // target larger, move right down
787 { 12, 12, 4, -2, xpm_gt_rr_t
}, // target larger, move right up
788 { 12, 12, 4, 0, xpm_gt_rr
}, // target larger, move right
789 { 12, 12, 4, 2, xpm_gt_rr_b
}, // target larger, move right down
790 { 12, 12, 4, 4, xpm_gt_rr_bb
}, // target larger, move right down
791 { 8, 8, -4, -4, xpm_sm_ll_tt
}, // target smaller, move left up
792 { 8, 8, -4, -2, xpm_sm_ll_t
}, // target smaller, move left up
793 { 8, 8, -4, 0, xpm_sm_ll
}, // target smaller, move left
794 { 8, 8, -4, 2, xpm_sm_ll_b
}, // target smaller, move left down
795 { 8, 8, -2, -4, xpm_sm_l_tt
}, // target smaller, move left up
796 { 8, 8, -2, -2, xpm_sm_l_t
}, // target smaller, move left up
797 { 8, 8, -2, 0, xpm_sm_l
}, // target smaller, move left
798 { 8, 8, -2, 2, xpm_sm_l_b
}, // target smaller, move left down
799 { 8, 8, 0, -4, xpm_sm_tt
}, // target smaller, move up
800 { 8, 8, 0, -2, xpm_sm_t
}, // target smaller, move up
801 { 8, 8, 0, 2, xpm_sm_b
}, // target smaller, move down
802 { 8, 8, 2, -4, xpm_sm_r_tt
}, // target smaller, move right up
803 { 8, 8, 2, -2, xpm_sm_r_t
}, // target smaller, move right up
804 { 8, 8, 2, 0, xpm_sm_r
}, // target smaller, move right
805 { 8, 8, 2, 2, xpm_sm_r_b
}, // target smaller, move right down
808 const wxImage
src_img(xpm_orig
);
809 for ( unsigned i
= 0; i
< WXSIZEOF(sizeTestData
); i
++ )
811 SizeTestData
& st
= sizeTestData
[i
];
813 actual(src_img
.Size(wxSize(st
.w
, st
.h
), wxPoint(st
.dx
, st
.dy
), 0, 0, 0)),
814 expected(st
.ref_xpm
);
816 // to check results with an image viewer uncomment this:
817 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
818 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
820 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().x
, expected
.GetSize().x
);
821 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().y
, expected
.GetSize().y
);
823 const unsigned data_len
= 3 * expected
.GetHeight() * expected
.GetWidth();
827 ("Resize test #%u: (%d, %d), (%d, %d)", i
, st
.w
, st
.h
, st
.dx
, st
.dy
),
828 memcmp(actual
.GetData(), expected
.GetData(), data_len
) == 0
833 void ImageTestCase::CompareLoadedImage()
835 wxImage
expected8("horse.xpm");
836 CPPUNIT_ASSERT( expected8
.IsOk() );
838 wxImage
expected24("horse.png");
839 CPPUNIT_ASSERT( expected24
.IsOk() );
841 const size_t dataLen
= expected8
.GetWidth() * expected8
.GetHeight() * 3;
843 for (size_t i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
845 if ( !(g_testfiles
[i
].bitDepth
== 8 || g_testfiles
[i
].bitDepth
== 24)
846 || g_testfiles
[i
].type
== wxBITMAP_TYPE_JPEG
/*skip lossy JPEG*/)
851 wxImage
actual(g_testfiles
[i
].file
);
853 if ( actual
.GetSize() != expected8
.GetSize() )
861 ("Compare test '%s' for loading failed", g_testfiles
[i
].file
),
863 memcmp(actual
.GetData(),
864 (g_testfiles
[i
].bitDepth
== 8)
865 ? expected8
.GetData()
866 : expected24
.GetData(),
874 void CompareImage(const wxImageHandler
& handler
, const wxImage
& expected
)
876 bool testAlpha
= expected
.HasAlpha();
877 if (testAlpha
&& type
!= wxBITMAP_TYPE_PNG
)
879 // don't test images with alpha if this handler doesn't support alpha
883 wxBitmapType type
= handler
.GetType();
884 if (type
== wxBITMAP_TYPE_JPEG
/* skip lossy JPEG */
885 || type
== wxBITMAP_TYPE_TIF
)
888 TIFF is skipped because the memory stream can't be loaded. Libtiff
889 looks for a TIFF directory at offset 120008 while the memory
890 stream size is only 120008 bytes (when saving as a file
891 the file size is 120280 bytes).
896 wxMemoryOutputStream memOut
;
897 if ( !expected
.SaveFile(memOut
, type
) )
899 // Unfortunately we can't know if the handler just doesn't support
900 // saving images, or if it failed to save.
904 if ( !memOut
.GetSize() )
906 // A handler that does not support saving can return true during
907 // SaveFile, in that case the stream is empty.
912 wxMemoryInputStream
memIn(memOut
);
913 CPPUNIT_ASSERT(memIn
.IsOk());
915 wxImage
actual(memIn
);
916 CPPUNIT_ASSERT(actual
.IsOk());
918 CPPUNIT_ASSERT( actual
.GetSize() == expected
.GetSize() );
922 ("Compare test '%s' for saving failed", handler
.GetExtension()),
924 memcmp(actual
.GetData(), expected
.GetData(),
925 expected
.GetWidth() * expected
.GetHeight() * 3) == 0
934 CPPUNIT_ASSERT( actual
.HasAlpha() );
938 ("Compare alpha test '%s' for saving failed", handler
.GetExtension()),
940 memcmp(actual
.GetAlpha(), expected
.GetAlpha(),
941 expected
.GetWidth() * expected
.GetHeight()) == 0
945 void ImageTestCase::CompareSavedImage()
947 wxImage
expected24("horse.png");
948 CPPUNIT_ASSERT( expected24
.IsOk() );
949 CPPUNIT_ASSERT( !expected24
.HasAlpha() );
951 // Create an image with alpha based on the loaded image
952 wxImage
expected32(expected24
);
953 expected32
.SetAlpha();
955 int width
= expected32
.GetWidth();
956 int height
= expected32
.GetHeight();
957 for (int y
= 0; y
< height
; ++y
)
959 for (int x
= 0; x
< width
; ++x
)
961 expected32
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
965 const wxList
& list
= wxImage::GetHandlers();
966 for ( wxList::compatibility_iterator node
= list
.GetFirst();
967 node
; node
= node
->GetNext() )
969 wxImageHandler
*handler
= (wxImageHandler
*) node
->GetData();
971 CompareImage(*handler
, expected24
);
972 CompareImage(*handler
, expected32
);
980 TODO: add lots of more tests to wxImage functions