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( SaveAnimatedGIF
);
75 CPPUNIT_TEST_SUITE_END();
77 void LoadFromSocketStream();
78 void LoadFromZipStream();
81 void CompareLoadedImage();
82 void CompareSavedImage();
83 void SaveAnimatedGIF();
85 DECLARE_NO_COPY_CLASS(ImageTestCase
)
88 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase
);
89 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase
, "ImageTestCase" );
91 ImageTestCase
::ImageTestCase()
93 wxSocketBase
::Initialize();
95 // the formats we're going to test:
96 wxImage
::AddHandler(new wxICOHandler
);
97 wxImage
::AddHandler(new wxXPMHandler
);
98 wxImage
::AddHandler(new wxPNGHandler
);
99 wxImage
::AddHandler(new wxANIHandler
);
100 wxImage
::AddHandler(new wxBMPHandler
);
101 wxImage
::AddHandler(new wxCURHandler
);
102 wxImage
::AddHandler(new wxGIFHandler
);
103 wxImage
::AddHandler(new wxJPEGHandler
);
104 wxImage
::AddHandler(new wxPCXHandler
);
105 wxImage
::AddHandler(new wxPNMHandler
);
106 wxImage
::AddHandler(new wxTGAHandler
);
107 wxImage
::AddHandler(new wxTIFFHandler
);
110 ImageTestCase
::~ImageTestCase()
112 wxSocketBase
::Shutdown();
115 void ImageTestCase
::LoadFromFile()
118 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
119 CPPUNIT_ASSERT(img
.LoadFile(g_testfiles
[i
].file
));
122 void ImageTestCase
::LoadFromSocketStream()
124 if (!IsNetworkAvailable()) // implemented in test.cpp
126 wxLogWarning("No network connectivity; skipping the "
127 "ImageTestCase::LoadFromSocketStream test unit.");
136 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG
},
137 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO
}
140 for (unsigned int i
=0; i
<WXSIZEOF(testData
); i
++)
142 wxURL
url(testData
[i
].url
);
143 WX_ASSERT_EQUAL_MESSAGE
145 ("Constructing URL \"%s\" failed.", testData
[i
].url
),
150 wxInputStream
*in_stream
= url
.GetInputStream();
153 ("Opening URL \"%s\" failed.", testData
[i
].url
),
154 in_stream
&& in_stream
->IsOk()
159 // NOTE: it's important to inform wxImage about the type of the image being
160 // loaded otherwise it will try to autodetect the format, but that
161 // requires a seekable stream!
164 ("Loading image from \"%s\" failed.", testData
[i
].url
),
165 img
.LoadFile(*in_stream
, testData
[i
].type
)
172 void ImageTestCase
::LoadFromZipStream()
174 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
176 switch (g_testfiles
[i
].type
)
178 case wxBITMAP_TYPE_XPM
:
179 case wxBITMAP_TYPE_GIF
:
180 case wxBITMAP_TYPE_PCX
:
181 case wxBITMAP_TYPE_TGA
:
182 case wxBITMAP_TYPE_TIF
:
183 continue; // skip testing those wxImageHandlers which cannot
184 // load data from non-seekable streams
190 // compress the test file on the fly:
191 wxMemoryOutputStream memOut
;
193 wxFileInputStream
file(g_testfiles
[i
].file
);
194 CPPUNIT_ASSERT(file
.IsOk());
196 wxZlibOutputStream
compressFilter(memOut
, 5, wxZLIB_GZIP
);
197 CPPUNIT_ASSERT(compressFilter
.IsOk());
199 file
.Read(compressFilter
);
200 CPPUNIT_ASSERT(file
.GetLastError() == wxSTREAM_EOF
);
203 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
204 // allows us to test loading images from non-seekable streams other than socket streams
205 wxMemoryInputStream
memIn(memOut
);
206 CPPUNIT_ASSERT(memIn
.IsOk());
207 wxZlibInputStream
decompressFilter(memIn
, wxZLIB_GZIP
);
208 CPPUNIT_ASSERT(decompressFilter
.IsOk());
212 // NOTE: it's important to inform wxImage about the type of the image being
213 // loaded otherwise it will try to autodetect the format, but that
214 // requires a seekable stream!
215 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles
[i
].type
),
216 img
.LoadFile(decompressFilter
, g_testfiles
[i
].type
));
220 void ImageTestCase
::SizeImage()
222 // Test the wxImage::Size() function which takes a rectangle from source and
223 // places it in a new image at a given position. This test checks, if the
224 // correct areas are chosen, and clipping is done correctly.
227 static const char * xpm_orig
[] = {
228 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
240 // the expected results for all tests:
241 static const char * xpm_l_t
[] = {
242 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
254 static const char * xpm_t
[] = {
255 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
267 static const char * xpm_r_t
[] = {
268 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
280 static const char * xpm_l
[] = {
281 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
293 static const char * xpm_r
[] = {
294 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
306 static const char * xpm_l_b
[] = {
307 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
319 static const char * xpm_b
[] = {
320 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
332 static const char * xpm_r_b
[] = {
333 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
345 static const char * xpm_sm
[] = {
346 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
356 static const char * xpm_gt
[] = {
357 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
371 static const char * xpm_gt_l_t
[] = {
372 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
386 static const char * xpm_gt_l
[] = {
387 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
401 static const char * xpm_gt_l_b
[] = {
402 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
416 static const char * xpm_gt_l_bb
[] = {
417 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
431 static const char * xpm_gt_t
[] = {
432 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
446 static const char * xpm_gt_b
[] = {
447 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
461 static const char * xpm_gt_bb
[] = {
462 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
476 static const char * xpm_gt_r_t
[] = {
477 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
491 static const char * xpm_gt_r
[] = {
492 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
506 static const char * xpm_gt_r_b
[] = {
507 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
521 static const char * xpm_gt_r_bb
[] = {
522 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
536 static const char * xpm_gt_rr_t
[] = {
537 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
551 static const char * xpm_gt_rr
[] = {
552 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
566 static const char * xpm_gt_rr_b
[] = {
567 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
581 static const char * xpm_gt_rr_bb
[] = {
582 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
596 static const char * xpm_sm_ll_tt
[] = {
597 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
607 static const char * xpm_sm_ll_t
[] = {
608 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
618 static const char * xpm_sm_ll
[] = {
619 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
629 static const char * xpm_sm_ll_b
[] = {
630 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
640 static const char * xpm_sm_l_tt
[] = {
641 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
651 static const char * xpm_sm_l_t
[] = {
652 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
662 static const char * xpm_sm_l
[] = {
663 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
673 static const char * xpm_sm_l_b
[] = {
674 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
684 static const char * xpm_sm_tt
[] = {
685 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
695 static const char * xpm_sm_t
[] = {
696 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
706 static const char * xpm_sm_b
[] = {
707 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
717 static const char * xpm_sm_r_tt
[] = {
718 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
728 static const char * xpm_sm_r_t
[] = {
729 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
739 static const char * xpm_sm_r
[] = {
740 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
750 static const char * xpm_sm_r_b
[] = {
751 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
762 // this table defines all tests
765 int w
, h
, dx
, dy
; // first parameters for Size()
766 const char **ref_xpm
; // expected result
769 { 10, 10, 0, 0, xpm_orig
}, // same size, same position
770 { 12, 12, 0, 0, xpm_gt
}, // target larger, same position
771 { 8, 8, 0, 0, xpm_sm
}, // target smaller, same position
772 { 10, 10, -2, -2, xpm_l_t
}, // same size, move left up
773 { 10, 10, -2, 0, xpm_l
}, // same size, move left
774 { 10, 10, -2, 2, xpm_l_b
}, // same size, move left down
775 { 10, 10, 0, -2, xpm_t
}, // same size, move up
776 { 10, 10, 0, 2, xpm_b
}, // same size, move down
777 { 10, 10, 2, -2, xpm_r_t
}, // same size, move right up
778 { 10, 10, 2, 0, xpm_r
}, // same size, move right
779 { 10, 10, 2, 2, xpm_r_b
}, // same size, move right down
780 { 12, 12, -2, -2, xpm_gt_l_t
}, // target larger, move left up
781 { 12, 12, -2, 0, xpm_gt_l
}, // target larger, move left
782 { 12, 12, -2, 2, xpm_gt_l_b
}, // target larger, move left down
783 { 12, 12, -2, 4, xpm_gt_l_bb
}, // target larger, move left down
784 { 12, 12, 0, -2, xpm_gt_t
}, // target larger, move up
785 { 12, 12, 0, 2, xpm_gt_b
}, // target larger, move down
786 { 12, 12, 0, 4, xpm_gt_bb
}, // target larger, move down
787 { 12, 12, 2, -2, xpm_gt_r_t
}, // target larger, move right up
788 { 12, 12, 2, 0, xpm_gt_r
}, // target larger, move right
789 { 12, 12, 2, 2, xpm_gt_r_b
}, // target larger, move right down
790 { 12, 12, 2, 4, xpm_gt_r_bb
}, // target larger, move right down
791 { 12, 12, 4, -2, xpm_gt_rr_t
}, // target larger, move right up
792 { 12, 12, 4, 0, xpm_gt_rr
}, // target larger, move right
793 { 12, 12, 4, 2, xpm_gt_rr_b
}, // target larger, move right down
794 { 12, 12, 4, 4, xpm_gt_rr_bb
}, // target larger, move right down
795 { 8, 8, -4, -4, xpm_sm_ll_tt
}, // target smaller, move left up
796 { 8, 8, -4, -2, xpm_sm_ll_t
}, // target smaller, move left up
797 { 8, 8, -4, 0, xpm_sm_ll
}, // target smaller, move left
798 { 8, 8, -4, 2, xpm_sm_ll_b
}, // target smaller, move left down
799 { 8, 8, -2, -4, xpm_sm_l_tt
}, // target smaller, move left up
800 { 8, 8, -2, -2, xpm_sm_l_t
}, // target smaller, move left up
801 { 8, 8, -2, 0, xpm_sm_l
}, // target smaller, move left
802 { 8, 8, -2, 2, xpm_sm_l_b
}, // target smaller, move left down
803 { 8, 8, 0, -4, xpm_sm_tt
}, // target smaller, move up
804 { 8, 8, 0, -2, xpm_sm_t
}, // target smaller, move up
805 { 8, 8, 0, 2, xpm_sm_b
}, // target smaller, move down
806 { 8, 8, 2, -4, xpm_sm_r_tt
}, // target smaller, move right up
807 { 8, 8, 2, -2, xpm_sm_r_t
}, // target smaller, move right up
808 { 8, 8, 2, 0, xpm_sm_r
}, // target smaller, move right
809 { 8, 8, 2, 2, xpm_sm_r_b
}, // target smaller, move right down
812 const wxImage
src_img(xpm_orig
);
813 for ( unsigned i
= 0; i
< WXSIZEOF(sizeTestData
); i
++ )
815 SizeTestData
& st
= sizeTestData
[i
];
817 actual(src_img
.Size(wxSize(st
.w
, st
.h
), wxPoint(st
.dx
, st
.dy
), 0, 0, 0)),
818 expected(st
.ref_xpm
);
820 // to check results with an image viewer uncomment this:
821 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
822 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
824 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().x
, expected
.GetSize().x
);
825 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().y
, expected
.GetSize().y
);
827 const unsigned data_len
= 3 * expected
.GetHeight() * expected
.GetWidth();
831 ("Resize test #%u: (%d, %d), (%d, %d)", i
, st
.w
, st
.h
, st
.dx
, st
.dy
),
832 memcmp(actual
.GetData(), expected
.GetData(), data_len
) == 0
837 void ImageTestCase
::CompareLoadedImage()
839 wxImage
expected8("horse.xpm");
840 CPPUNIT_ASSERT( expected8
.IsOk() );
842 wxImage
expected24("horse.png");
843 CPPUNIT_ASSERT( expected24
.IsOk() );
845 const size_t dataLen
= expected8
.GetWidth() * expected8
.GetHeight() * 3;
847 for (size_t i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
849 if ( !(g_testfiles
[i
].bitDepth
== 8 || g_testfiles
[i
].bitDepth
== 24)
850 || g_testfiles
[i
].type
== wxBITMAP_TYPE_JPEG
/*skip lossy JPEG*/)
855 wxImage
actual(g_testfiles
[i
].file
);
857 if ( actual
.GetSize() != expected8
.GetSize() )
865 ("Compare test '%s' for loading failed", g_testfiles
[i
].file
),
867 memcmp(actual
.GetData(),
868 (g_testfiles
[i
].bitDepth
== 8)
869 ? expected8
.GetData()
870 : expected24
.GetData(),
879 wxIMAGE_HAVE_ALPHA
= (1 << 0),
880 wxIMAGE_HAVE_PALETTE
= (1 << 1)
884 void CompareImage(const wxImageHandler
& handler
, const wxImage
& image
,
885 int properties
= 0, const wxImage
*compareTo
= NULL
)
887 wxBitmapType type
= handler
.GetType();
889 const bool testPalette
= (properties
& wxIMAGE_HAVE_PALETTE
) != 0;
891 This is getting messy and should probably be transformed into a table
892 with image format features before it gets hairier.
895 && ( !(type
== wxBITMAP_TYPE_BMP
896 || type
== wxBITMAP_TYPE_GIF
897 || type
== wxBITMAP_TYPE_PNG
)
898 || type
== wxBITMAP_TYPE_XPM
) )
903 const bool testAlpha
= (properties
& wxIMAGE_HAVE_ALPHA
) != 0;
905 && !(type
== wxBITMAP_TYPE_PNG
|| type
== wxBITMAP_TYPE_TGA
) )
907 // don't test images with alpha if this handler doesn't support alpha
911 if (type
== wxBITMAP_TYPE_JPEG
/* skip lossy JPEG */
912 || type
== wxBITMAP_TYPE_TIF
)
915 TIFF is skipped because the memory stream can't be loaded. Libtiff
916 looks for a TIFF directory at offset 120008 while the memory
917 stream size is only 120008 bytes (when saving as a file
918 the file size is 120280 bytes).
923 wxMemoryOutputStream memOut
;
924 if ( !image
.SaveFile(memOut
, type
) )
926 // Unfortunately we can't know if the handler just doesn't support
927 // saving images, or if it failed to save.
931 wxMemoryInputStream
memIn(memOut
);
932 CPPUNIT_ASSERT(memIn
.IsOk());
934 wxImage
actual(memIn
);
935 CPPUNIT_ASSERT(actual
.IsOk());
937 const wxImage
*expected
= compareTo ? compareTo
: &image
;
938 CPPUNIT_ASSERT( actual
.GetSize() == expected
->GetSize() );
940 unsigned bitsPerPixel
= testPalette ?
8 : (testAlpha ?
32 : 24);
943 ("Compare test '%s (%d-bit)' for saving failed",
944 handler
.GetExtension(), bitsPerPixel
),
946 memcmp(actual
.GetData(), expected
->GetData(),
947 expected
->GetWidth() * expected
->GetHeight() * 3) == 0
951 CPPUNIT_ASSERT(actual
.HasPalette()
952 == (testPalette
|| type
== wxBITMAP_TYPE_XPM
));
955 CPPUNIT_ASSERT( actual
.HasAlpha() == testAlpha
);
964 ("Compare alpha test '%s' for saving failed", handler
.GetExtension()),
966 memcmp(actual
.GetAlpha(), expected
->GetAlpha(),
967 expected
->GetWidth() * expected
->GetHeight()) == 0
971 void ImageTestCase
::CompareSavedImage()
973 // FIXME-VC6: Pre-declare the loop variables for compatibility with
974 // pre-standard compilers such as MSVC6 that don't implement proper scope
975 // for the variables declared in the for loops.
978 wxImage
expected24("horse.png");
979 CPPUNIT_ASSERT( expected24
.IsOk() );
980 CPPUNIT_ASSERT( !expected24
.HasAlpha() );
982 wxImage expected8
= expected24
.ConvertToGreyscale();
985 unsigned char greys
[256];
986 for (i
= 0; i
< 256; ++i
)
990 wxPalette
palette(256, greys
, greys
, greys
);
991 expected8
.SetPalette(palette
);
992 #endif // #if wxUSE_PALETTE
994 expected8
.SetOption(wxIMAGE_OPTION_BMP_FORMAT
, wxBMP_8BPP_PALETTE
);
996 // Create an image with alpha based on the loaded image
997 wxImage
expected32(expected24
);
998 expected32
.SetAlpha();
1000 int width
= expected32
.GetWidth();
1001 int height
= expected32
.GetHeight();
1002 for (y
= 0; y
< height
; ++y
)
1004 for (x
= 0; x
< width
; ++x
)
1006 expected32
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1010 const wxList
& list
= wxImage
::GetHandlers();
1011 for ( wxList
::compatibility_iterator node
= list
.GetFirst();
1012 node
; node
= node
->GetNext() )
1014 wxImageHandler
*handler
= (wxImageHandler
*) node
->GetData();
1017 CompareImage(*handler
, expected8
, wxIMAGE_HAVE_PALETTE
);
1019 CompareImage(*handler
, expected24
);
1020 CompareImage(*handler
, expected32
, wxIMAGE_HAVE_ALPHA
);
1024 expected8
.LoadFile("horse.gif");
1025 CPPUNIT_ASSERT( expected8
.IsOk() );
1027 CPPUNIT_ASSERT( expected8
.HasPalette() );
1028 #endif // #if wxUSE_PALETTE
1030 expected8
.SetAlpha();
1032 width
= expected8
.GetWidth();
1033 height
= expected8
.GetHeight();
1034 for (y
= 0; y
< height
; ++y
)
1036 for (x
= 0; x
< width
; ++x
)
1038 expected8
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1043 Explicitly make known we want a palettised PNG. If we don't then this
1044 particular image gets saved as a true colour image because there's an
1045 alpha channel present and the PNG saver prefers to keep the alpha over
1046 saving as a palettised image that has alpha converted to a mask.
1048 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1051 The image contains 256 indexed colours and needs another palette entry
1052 for storing the transparency index. This results in wanting 257 palette
1053 entries but that amount is not supported by PNG, as such this image
1054 should not contain a palette (but still have alpha) and be stored as a
1055 true colour image instead.
1057 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
),
1058 expected8
, wxIMAGE_HAVE_ALPHA
);
1062 Now do the same test again but remove one (random) palette entry. This
1063 should result in saving the PNG with a palette.
1065 unsigned char red
[256], green
[256], blue
[256];
1066 const wxPalette
& pal
= expected8
.GetPalette();
1067 const int paletteCount
= pal
.GetColoursCount();
1068 for (i
= 0; i
< paletteCount
; ++i
)
1070 expected8
.GetPalette().GetRGB(i
, &red
[i
], &green
[i
], &blue
[i
]);
1072 wxPalette
newPal(paletteCount
- 1, red
, green
, blue
);
1074 red
[paletteCount
-1], green
[paletteCount
-1], blue
[paletteCount
-1],
1075 red
[paletteCount
-2], green
[paletteCount
-2], blue
[paletteCount
-2]);
1077 expected8
.SetPalette(newPal
);
1079 wxImage ref8
= expected8
;
1082 Convert the alpha channel to a mask like the PNG saver does. Also convert
1083 the colour used for transparency from 1,0,0 to 2,0,0. The latter gets
1084 done by the PNG loader in search of an unused colour to use for
1085 transparency (this should be fixed).
1087 ref8
.ConvertAlphaToMask();
1088 ref8
.Replace(1, 0, 0, 2, 0, 0);
1090 CompareImage(*wxImage
::FindHandler(wxBITMAP_TYPE_PNG
),
1091 expected8
, wxIMAGE_HAVE_PALETTE
, &ref8
);
1095 void ImageTestCase
::SaveAnimatedGIF()
1098 wxImage
image("horse.gif");
1099 CPPUNIT_ASSERT( image
.IsOk() );
1101 wxImageArray images
;
1104 for (i
= 0; i
< 4-1; ++i
)
1106 images
.Add( images
[i
].Rotate90() );
1108 images
[i
+1].SetPalette(images
[0].GetPalette());
1111 wxMemoryOutputStream memOut
;
1112 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1114 wxGIFHandler handler
;
1115 wxMemoryInputStream
memIn(memOut
);
1116 CPPUNIT_ASSERT(memIn
.IsOk());
1117 const int imageCount
= handler
.GetImageCount(memIn
);
1118 CPPUNIT_ASSERT_EQUAL(4, imageCount
);
1120 for (i
= 0; i
< imageCount
; ++i
)
1122 wxFileOffset pos
= memIn
.TellI();
1123 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true, i
) );
1128 ("Compare test for GIF frame number %d failed", i
),
1129 memcmp(image
.GetData(), images
[i
].GetData(),
1130 images
[i
].GetWidth() * images
[i
].GetHeight() * 3) == 0
1133 #endif // #if wxUSE_PALETTE
1136 #endif //wxUSE_IMAGE
1140 TODO: add lots of more tests to wxImage functions