1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Test for CImage
5  * PROGRAMMER:      Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6  */
7 
8 #include <atlimage.h>
9 #include "resource.h"
10 
11 #ifdef __REACTOS__
12     #include <apitest.h>
13 #else
14     #include <stdlib.h>
15     #include <stdio.h>
16     #include <stdarg.h>
17     int g_tests_executed = 0;
18     int g_tests_failed = 0;
19     void ok_func(const char *file, int line, BOOL value, const char *fmt, ...)
20     {
21         va_list va;
22         va_start(va, fmt);
23         if (!value)
24         {
25             printf("%s (%d): ", file, line);
26             vprintf(fmt, va);
27             g_tests_failed++;
28         }
29         g_tests_executed++;
30         va_end(va);
31     }
32     #undef ok
33     #define ok(value, ...)  ok_func(__FILE__, __LINE__, value, __VA_ARGS__)
34     #define START_TEST(x)   int main(void)
35 #endif
36 
37 const TCHAR* szFiles[] = {
38     TEXT("ant.png"),
39     TEXT("ant.tif"),
40     TEXT("ant.gif"),
41     TEXT("ant.jpg"),
42     TEXT("ant.bmp"),
43 };
44 
45 static TCHAR szTempPath[MAX_PATH];
46 TCHAR* file_name(const TCHAR* file)
47 {
48     static TCHAR buffer[MAX_PATH];
49     lstrcpy(buffer, szTempPath);
50     lstrcat(buffer, TEXT("\\"));
51     lstrcat(buffer, file);
52     return buffer;
53 }
54 
55 static void write_bitmap(HINSTANCE hInst, int id, TCHAR* file)
56 {
57     HRSRC rsrc;
58 
59     rsrc = FindResource(hInst, MAKEINTRESOURCE(id), RT_BITMAP);
60     ok(rsrc != NULL, "Expected to find an image resource\n");
61     if (rsrc)
62     {
63         void *rsrc_data;
64         HANDLE hfile;
65         BOOL ret;
66         HGLOBAL glob = LoadResource(hInst, rsrc);
67         DWORD rsrc_size = SizeofResource(hInst, rsrc);
68 
69         rsrc_data = LockResource(glob);
70 
71         hfile = CreateFile(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
72         ok(hfile != INVALID_HANDLE_VALUE, "Unable to open temp file: %lu\n", GetLastError());
73         if (hfile != INVALID_HANDLE_VALUE)
74         {
75             BITMAPFILEHEADER bfh = { 0 };
76             DWORD dwWritten;
77 
78             bfh.bfType = 'MB';
79             bfh.bfSize = rsrc_size + sizeof(BITMAPFILEHEADER);
80             bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
81             bfh.bfReserved1 = bfh.bfReserved2 = 0;
82             ret = WriteFile(hfile, &bfh, sizeof(bfh), &dwWritten, NULL);
83             ok(ret, "Unable to write temp file: %lu\n", GetLastError());
84             ret = WriteFile(hfile, rsrc_data, rsrc_size, &dwWritten, NULL);
85             ok(ret, "Unable to write temp file: %lu\n", GetLastError());
86             CloseHandle(hfile);
87         }
88         UnlockResource(rsrc_data);
89     }
90 }
91 
92 typedef Gdiplus::GpStatus (WINAPI *STARTUP)(ULONG_PTR *, const Gdiplus::GdiplusStartupInput *, Gdiplus::GdiplusStartupOutput *);
93 typedef void (WINAPI *SHUTDOWN)(ULONG_PTR);
94 typedef Gdiplus::GpStatus (WINGDIPAPI *CREATEBITMAPFROMFILE)(GDIPCONST WCHAR*, Gdiplus::GpBitmap **);
95 typedef Gdiplus::GpStatus (WINGDIPAPI *GETPIXELFORMAT)(Gdiplus::GpImage *image, Gdiplus::PixelFormat *format);
96 typedef Gdiplus::GpStatus (WINGDIPAPI *DISPOSEIMAGE)(Gdiplus::GpImage *);
97 
98 static HINSTANCE               hinstGdiPlus;
99 static ULONG_PTR               gdiplusToken;
100 
101 static STARTUP                 Startup;
102 static SHUTDOWN                Shutdown;
103 static CREATEBITMAPFROMFILE    CreateBitmapFromFile;
104 static GETPIXELFORMAT          GetImagePixelFormat;
105 static DISPOSEIMAGE            DisposeImage;
106 
107 template <typename TYPE>
108 TYPE AddrOf(const char *name)
109 {
110     FARPROC proc = ::GetProcAddress(hinstGdiPlus, name);
111     return reinterpret_cast<TYPE>(proc);
112 }
113 
114 static void init_gdip()
115 {
116     hinstGdiPlus = ::LoadLibraryA("gdiplus.dll");
117     Startup = AddrOf<STARTUP>("GdiplusStartup");
118     Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown");
119     CreateBitmapFromFile = AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile");
120     GetImagePixelFormat = AddrOf<GETPIXELFORMAT>("GdipGetImagePixelFormat");
121     DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage");
122 }
123 
124 
125 static void determine_file_bpp(TCHAR* tfile, Gdiplus::PixelFormat expect_pf)
126 {
127     using namespace Gdiplus;
128     GpBitmap *pBitmap = NULL;
129 
130 #ifdef UNICODE
131     WCHAR* file = tfile;
132 #else
133     WCHAR file[MAX_PATH];
134     ::MultiByteToWideChar(CP_ACP, 0, tfile, -1, file, MAX_PATH);
135 #endif
136 
137     if (Startup == NULL)
138         init_gdip();
139 
140     Gdiplus::GdiplusStartupInput gdiplusStartupInput;
141     Startup(&gdiplusToken, &gdiplusStartupInput, NULL);
142 
143 
144     Gdiplus::GpStatus status = CreateBitmapFromFile(file, &pBitmap);
145     ok(status == Gdiplus::Ok, "Expected status to be %i, was: %i\n", (int)Gdiplus::Ok, (int)status);
146     ok(pBitmap != NULL, "Expected a valid bitmap\n");
147     if (pBitmap)
148     {
149         PixelFormat pf;
150         GetImagePixelFormat(pBitmap, &pf);
151         ok(pf == expect_pf, "Expected PixelFormat to be 0x%x, was: 0x%x\n", (int)expect_pf, (int)pf);
152 
153         DisposeImage(pBitmap);
154     }
155     Shutdown(gdiplusToken);
156 }
157 
158 
159 START_TEST(CImage)
160 {
161     HRESULT hr;
162     TCHAR* file;
163     BOOL bOK;
164     int width, height, bpp;
165     size_t n;
166     CImage image1, image2;
167     COLORREF color;
168     HDC hDC;
169 
170 #if 0
171     width = image1.GetWidth();
172     height = image1.GetHeight();
173     bpp = image1.GetBPP();
174 #endif
175 
176     HINSTANCE hInst = GetModuleHandle(NULL);
177     GetTempPath(MAX_PATH, szTempPath);
178 
179     image1.LoadFromResource(hInst, IDB_ANT);
180     ok(!image1.IsNull(), "Expected image1 is not null\n");
181 
182     width = image1.GetWidth();
183     ok(width == 48, "Expected width to be 48, was: %d\n", width);
184     height = image1.GetHeight();
185     ok(height == 48, "Expected height to be 48, was: %d\n", height);
186     bpp = image1.GetBPP();
187     ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
188 
189 
190     image2.LoadFromResource(hInst, IDB_CROSS);
191     ok(!image2.IsNull(), "Expected image2 is not null\n");
192     image2.SetTransparentColor(RGB(255, 255, 255));
193 
194     width = image2.GetWidth();
195     ok(width == 32, "Expected width to be 32, was: %d\n", width);
196     height = image2.GetHeight();
197     ok(height == 32, "Expected height to be 32, was: %d\n", height);
198     bpp = image2.GetBPP();
199     ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
200 
201     color = image1.GetPixel(5, 5);
202     ok(color == RGB(166, 202, 240), "Expected color to be 166, 202, 240; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
203 
204     hDC = image1.GetDC();
205     bOK = image2.Draw(hDC, 0, 0);
206     image1.ReleaseDC();
207     ok(bOK != FALSE, "Expected bDraw to be TRUE, was: %d\n", bOK);
208     image2.Destroy();
209 
210     color = image1.GetPixel(5, 5);
211     ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
212 
213     file = file_name(TEXT("ant.bmp"));
214     write_bitmap(hInst, IDB_ANT, file);
215 
216     init_gdip();
217 
218     determine_file_bpp(file, PixelFormat8bppIndexed);
219 
220     hr = image2.Load(file);
221     ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx\n", hr);
222     ok(!image2.IsNull(), "Expected image1 is not null\n");
223     bOK = DeleteFile(file);
224     ok(bOK, "Expected bOK to be TRUE, was: %d\n", bOK);
225 
226     width = image2.GetWidth();
227     ok(width == 48, "Expected width to be 48, was: %d\n", width);
228     height = image2.GetHeight();
229     ok(height == 48, "Expected height to be 48, was: %d\n", height);
230     bpp = image2.GetBPP();
231     ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
232 
233     for (n = 0; n < _countof(szFiles); ++n)
234     {
235         file = file_name(szFiles[n]);
236         image2.Destroy();
237 
238         if (n == 0)
239             hr = image1.Save(file, Gdiplus::ImageFormatPNG);
240         else
241             hr = image1.Save(file);
242         ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
243 
244         bOK = (GetFileAttributes(file) != 0xFFFFFFFF);
245         ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
246 
247         hr = image2.Load(file);
248         ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
249 
250         width = image2.GetWidth();
251         ok(width == 48, "Expected width to be 48, was: %d (for %i)\n", width, n);
252         height = image2.GetHeight();
253         ok(height == 48, "Expected height to be 48, was: %d (for %i)\n", height, n);
254         bpp = image2.GetBPP();
255         if (n == 3)
256         {
257             ok(bpp == 24, "Expected bpp to be 24, was: %d (for %i)\n", bpp, n);
258             determine_file_bpp(file, PixelFormat24bppRGB);
259         }
260         else
261         {
262             ok(bpp == 8, "Expected bpp to be 8, was: %d (for %i)\n", bpp, n);
263             determine_file_bpp(file, PixelFormat8bppIndexed);
264         }
265         color = image1.GetPixel(5, 5);
266         ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i (for %i)\n", GetRValue(color), GetGValue(color), GetBValue(color), n);
267 
268         bOK = DeleteFile(file);
269         ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
270     }
271 
272     ATL::IAtlStringMgr *mgr = CAtlStringMgr::GetInstance();
273     CSimpleArray<GUID> aguidFileTypes;
274 #ifdef UNICODE
275     CHAR szBuff[512];
276     const WCHAR *psz;
277 #else
278     const CHAR *psz;
279 #endif
280 
281     CSimpleString strImporters(mgr);
282     aguidFileTypes.RemoveAll();
283     hr = CImage::GetImporterFilterString(strImporters,
284                                          aguidFileTypes,
285                                          TEXT("All Image Files"), 0);
286     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
287     ok(aguidFileTypes.GetSize() == 9, "Expected aguidFileTypes.GetSize() to be 8, was %d.", aguidFileTypes.GetSize());
288     ok(IsEqualGUID(aguidFileTypes[0], GUID_NULL), "Expected aguidFileTypes[0] to be GUID_NULL.\n");
289     ok(IsEqualGUID(aguidFileTypes[1], Gdiplus::ImageFormatBMP), "Expected aguidFileTypes[1] to be Gdiplus::ImageFormatBMP.\n");
290     ok(IsEqualGUID(aguidFileTypes[2], Gdiplus::ImageFormatJPEG), "Expected aguidFileTypes[2] to be Gdiplus::ImageFormatJPEG.\n");
291     ok(IsEqualGUID(aguidFileTypes[3], Gdiplus::ImageFormatGIF), "Expected aguidFileTypes[3] to be Gdiplus::ImageFormatGIF.\n");
292     ok(IsEqualGUID(aguidFileTypes[4], Gdiplus::ImageFormatEMF), "Expected aguidFileTypes[4] to be Gdiplus::ImageFormatEMF.\n");
293     ok(IsEqualGUID(aguidFileTypes[5], Gdiplus::ImageFormatWMF), "Expected aguidFileTypes[5] to be Gdiplus::ImageFormatWMF.\n");
294     ok(IsEqualGUID(aguidFileTypes[6], Gdiplus::ImageFormatTIFF), "Expected aguidFileTypes[6] to be Gdiplus::ImageFormatTIFF.\n");
295     ok(IsEqualGUID(aguidFileTypes[7], Gdiplus::ImageFormatPNG), "Expected aguidFileTypes[7] to be Gdiplus::ImageFormatPNG.\n");
296     ok(IsEqualGUID(aguidFileTypes[8], Gdiplus::ImageFormatIcon), "Expected aguidFileTypes[8] to be Gdiplus::ImageFormatIcon.\n");
297 
298     psz = strImporters.GetString();
299 #ifdef UNICODE
300     WideCharToMultiByte(CP_ACP, 0, psz, -1, szBuff, 512, NULL, NULL);
301     ok(lstrcmpA(szBuff, "All Image Files|*.BMP;*.DIB;*.RLE;*.JPG;*.JPEG;*.JPE;*.JFIF;*.GIF;*.EMF;*.WMF;*.TIF;*.TIFF;*.PNG;*.ICO|BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|GIF (*.GIF)|*.GIF|EMF (*.EMF)|*.EMF|WMF (*.WMF)|*.WMF|TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|PNG (*.PNG)|*.PNG|ICO (*.ICO)|*.ICO||") == 0,
302        "The importer filter string is bad, was: %s\n", szBuff);
303 #else
304     ok(lstrcmpA(psz, "All Image Files|*.BMP;*.DIB;*.RLE;*.JPG;*.JPEG;*.JPE;*.JFIF;*.GIF;*.EMF;*.WMF;*.TIF;*.TIFF;*.PNG;*.ICO|BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|GIF (*.GIF)|*.GIF|EMF (*.EMF)|*.EMF|WMF (*.WMF)|*.WMF|TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|PNG (*.PNG)|*.PNG|ICO (*.ICO)|*.ICO||") == 0,
305        "The importer filter string is bad, was: %s\n", psz);
306 #endif
307 
308     CSimpleString strExporters(mgr);
309     aguidFileTypes.RemoveAll();
310     hr = CImage::GetExporterFilterString(strExporters,
311                                          aguidFileTypes,
312                                          TEXT("All Image Files"), 0);
313     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
314     ok(aguidFileTypes.GetSize() == 9, "Expected aguidFileTypes.GetSize() to be 8, was %d.", aguidFileTypes.GetSize());
315     ok(IsEqualGUID(aguidFileTypes[0], GUID_NULL), "Expected aguidFileTypes[0] to be GUID_NULL.\n");
316     ok(IsEqualGUID(aguidFileTypes[1], Gdiplus::ImageFormatBMP), "Expected aguidFileTypes[1] to be Gdiplus::ImageFormatBMP.\n");
317     ok(IsEqualGUID(aguidFileTypes[2], Gdiplus::ImageFormatJPEG), "Expected aguidFileTypes[2] to be Gdiplus::ImageFormatJPEG.\n");
318     ok(IsEqualGUID(aguidFileTypes[3], Gdiplus::ImageFormatGIF), "Expected aguidFileTypes[3] to be Gdiplus::ImageFormatGIF.\n");
319     ok(IsEqualGUID(aguidFileTypes[4], Gdiplus::ImageFormatEMF), "Expected aguidFileTypes[4] to be Gdiplus::ImageFormatEMF.\n");
320     ok(IsEqualGUID(aguidFileTypes[5], Gdiplus::ImageFormatWMF), "Expected aguidFileTypes[5] to be Gdiplus::ImageFormatWMF.\n");
321     ok(IsEqualGUID(aguidFileTypes[6], Gdiplus::ImageFormatTIFF), "Expected aguidFileTypes[6] to be Gdiplus::ImageFormatTIFF.\n");
322     ok(IsEqualGUID(aguidFileTypes[7], Gdiplus::ImageFormatPNG), "Expected aguidFileTypes[7] to be Gdiplus::ImageFormatPNG.\n");
323     ok(IsEqualGUID(aguidFileTypes[8], Gdiplus::ImageFormatIcon), "Expected aguidFileTypes[8] to be Gdiplus::ImageFormatIcon.\n");
324 
325     psz = strExporters.GetString();
326 #ifdef UNICODE
327     WideCharToMultiByte(CP_ACP, 0, psz, -1, szBuff, 512, NULL, NULL);
328     ok(lstrcmpA(szBuff, "All Image Files|*.BMP;*.DIB;*.RLE;*.JPG;*.JPEG;*.JPE;*.JFIF;*.GIF;*.EMF;*.WMF;*.TIF;*.TIFF;*.PNG;*.ICO|BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|GIF (*.GIF)|*.GIF|EMF (*.EMF)|*.EMF|WMF (*.WMF)|*.WMF|TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|PNG (*.PNG)|*.PNG|ICO (*.ICO)|*.ICO||") == 0,
329        "The exporter filter string is bad, was: %s\n", szBuff);
330 #else
331     ok(lstrcmpA(psz, "All Image Files|*.BMP;*.DIB;*.RLE;*.JPG;*.JPEG;*.JPE;*.JFIF;*.GIF;*.EMF;*.WMF;*.TIF;*.TIFF;*.PNG;*.ICO|BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|GIF (*.GIF)|*.GIF|EMF (*.EMF)|*.EMF|WMF (*.WMF)|*.WMF|TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|PNG (*.PNG)|*.PNG|ICO (*.ICO)|*.ICO||") == 0,
332        "The exporter filter string is bad, was: %s\n", psz);
333 #endif
334 
335 #ifndef __REACTOS__
336     printf("CImage: %i tests executed (0 marked as todo, %i failures), 0 skipped.\n", g_tests_executed, g_tests_failed);
337     return g_tests_failed;
338 #endif
339 }
340