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 HAVE_APITEST
12     #include <apitest.h>
13 #else
14     #include "atltest.h"
15 #endif
16 
17 const TCHAR* szFiles[] = {
18     TEXT("ant.png"),
19     TEXT("ant.tif"),
20     TEXT("ant.gif"),
21     TEXT("ant.jpg"),
22     TEXT("ant.bmp"),
23 };
24 
25 static TCHAR szTempPath[MAX_PATH];
26 TCHAR* file_name(const TCHAR* file)
27 {
28     static TCHAR buffer[MAX_PATH];
29     lstrcpy(buffer, szTempPath);
30     lstrcat(buffer, TEXT("\\"));
31     lstrcat(buffer, file);
32     return buffer;
33 }
34 
35 static void write_bitmap(HINSTANCE hInst, int id, TCHAR* file)
36 {
37     HRSRC rsrc;
38 
39     rsrc = FindResource(hInst, MAKEINTRESOURCE(id), RT_BITMAP);
40     ok(rsrc != NULL, "Expected to find an image resource\n");
41     if (rsrc)
42     {
43         void *rsrc_data;
44         HANDLE hfile;
45         BOOL ret;
46         HGLOBAL glob = LoadResource(hInst, rsrc);
47         DWORD rsrc_size = SizeofResource(hInst, rsrc);
48 
49         rsrc_data = LockResource(glob);
50 
51         hfile = CreateFile(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
52         ok(hfile != INVALID_HANDLE_VALUE, "Unable to open temp file: %lu\n", GetLastError());
53         if (hfile != INVALID_HANDLE_VALUE)
54         {
55             BITMAPFILEHEADER bfh = { 0 };
56             DWORD dwWritten;
57 
58             bfh.bfType = 'MB';
59             bfh.bfSize = rsrc_size + sizeof(BITMAPFILEHEADER);
60             bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
61             bfh.bfReserved1 = bfh.bfReserved2 = 0;
62             ret = WriteFile(hfile, &bfh, sizeof(bfh), &dwWritten, NULL);
63             ok(ret, "Unable to write temp file: %lu\n", GetLastError());
64             ret = WriteFile(hfile, rsrc_data, rsrc_size, &dwWritten, NULL);
65             ok(ret, "Unable to write temp file: %lu\n", GetLastError());
66             CloseHandle(hfile);
67         }
68         UnlockResource(rsrc_data);
69     }
70 }
71 
72 typedef Gdiplus::GpStatus (WINAPI *STARTUP)(ULONG_PTR *, const Gdiplus::GdiplusStartupInput *, Gdiplus::GdiplusStartupOutput *);
73 typedef void (WINAPI *SHUTDOWN)(ULONG_PTR);
74 typedef Gdiplus::GpStatus (WINGDIPAPI *CREATEBITMAPFROMFILE)(GDIPCONST WCHAR*, Gdiplus::GpBitmap **);
75 typedef Gdiplus::GpStatus (WINGDIPAPI *GETPIXELFORMAT)(Gdiplus::GpImage *image, Gdiplus::PixelFormat *format);
76 typedef Gdiplus::GpStatus (WINGDIPAPI *DISPOSEIMAGE)(Gdiplus::GpImage *);
77 
78 static HINSTANCE               hinstGdiPlus;
79 static ULONG_PTR               gdiplusToken;
80 
81 static STARTUP                 Startup;
82 static SHUTDOWN                Shutdown;
83 static CREATEBITMAPFROMFILE    CreateBitmapFromFile;
84 static GETPIXELFORMAT          GetImagePixelFormat;
85 static DISPOSEIMAGE            DisposeImage;
86 
87 template <typename TYPE>
88 TYPE AddrOf(const char *name)
89 {
90     FARPROC proc = ::GetProcAddress(hinstGdiPlus, name);
91     return reinterpret_cast<TYPE>(proc);
92 }
93 
94 static void init_gdip()
95 {
96     hinstGdiPlus = ::LoadLibraryA("gdiplus.dll");
97     Startup = AddrOf<STARTUP>("GdiplusStartup");
98     Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown");
99     CreateBitmapFromFile = AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile");
100     GetImagePixelFormat = AddrOf<GETPIXELFORMAT>("GdipGetImagePixelFormat");
101     DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage");
102 }
103 
104 static void determine_file_bpp(TCHAR* tfile, Gdiplus::PixelFormat expect_pf)
105 {
106     using namespace Gdiplus;
107     GpBitmap *pBitmap = NULL;
108 
109 #ifdef UNICODE
110     WCHAR* file = tfile;
111 #else
112     WCHAR file[MAX_PATH];
113     ::MultiByteToWideChar(CP_ACP, 0, tfile, -1, file, MAX_PATH);
114 #endif
115 
116     if (Startup == NULL)
117         init_gdip();
118 
119     Gdiplus::GdiplusStartupInput gdiplusStartupInput;
120     Startup(&gdiplusToken, &gdiplusStartupInput, NULL);
121 
122 
123     Gdiplus::GpStatus status = CreateBitmapFromFile(file, &pBitmap);
124     ok(status == Gdiplus::Ok, "Expected status to be %i, was: %i\n", (int)Gdiplus::Ok, (int)status);
125     ok(pBitmap != NULL, "Expected a valid bitmap\n");
126     if (pBitmap)
127     {
128         PixelFormat pf;
129         GetImagePixelFormat(pBitmap, &pf);
130         ok(pf == expect_pf, "Expected PixelFormat to be 0x%x, was: 0x%x\n", (int)expect_pf, (int)pf);
131 
132         DisposeImage(pBitmap);
133     }
134     Shutdown(gdiplusToken);
135 }
136 
137 static void Test_LoadSaveImage(void)
138 {
139     HRESULT hr;
140     TCHAR* file;
141     BOOL bOK;
142     int width, height, bpp;
143     size_t n;
144     CImage image1, image2;
145     COLORREF color;
146     HDC hDC;
147 
148     HINSTANCE hInst = GetModuleHandle(NULL);
149     GetTempPath(MAX_PATH, szTempPath);
150 
151     image1.LoadFromResource(hInst, IDB_ANT);
152     ok(!image1.IsNull(), "Expected image1 is not null\n");
153 
154     width = image1.GetWidth();
155     ok(width == 48, "Expected width to be 48, was: %d\n", width);
156     height = image1.GetHeight();
157     ok(height == 48, "Expected height to be 48, was: %d\n", height);
158     bpp = image1.GetBPP();
159     ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
160 
161     image2.LoadFromResource(hInst, IDB_CROSS);
162     ok(!image2.IsNull(), "Expected image2 is not null\n");
163     image2.SetTransparentColor(RGB(255, 255, 255));
164 
165     width = image2.GetWidth();
166     ok(width == 32, "Expected width to be 32, was: %d\n", width);
167     height = image2.GetHeight();
168     ok(height == 32, "Expected height to be 32, was: %d\n", height);
169     bpp = image2.GetBPP();
170     ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
171 
172     color = image1.GetPixel(5, 5);
173     ok(color == RGB(166, 202, 240), "Expected color to be 166, 202, 240; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
174 
175     hDC = image1.GetDC();
176     bOK = image2.Draw(hDC, 0, 0);
177     image1.ReleaseDC();
178     ok(bOK != FALSE, "Expected bDraw to be TRUE, was: %d\n", bOK);
179     image2.Destroy();
180 
181     color = image1.GetPixel(5, 5);
182     ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
183 
184     file = file_name(TEXT("ant.bmp"));
185     write_bitmap(hInst, IDB_ANT, file);
186 
187     init_gdip();
188 
189     determine_file_bpp(file, PixelFormat8bppIndexed);
190 
191     hr = image2.Load(file);
192     ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx\n", hr);
193     ok(!image2.IsNull(), "Expected image1 is not null\n");
194     bOK = DeleteFile(file);
195     ok(bOK, "Expected bOK to be TRUE, was: %d\n", bOK);
196 
197     width = image2.GetWidth();
198     ok_int(width, 48);
199     height = image2.GetHeight();
200     ok_int(height, 48);
201     bpp = image2.GetBPP();
202     ok(bpp == 32 || bpp == 8, "bpp was %d\n", bpp);
203 
204     for (n = 0; n < _countof(szFiles); ++n)
205     {
206         file = file_name(szFiles[n]);
207         image2.Destroy();
208 
209         if (n == 0)
210             hr = image1.Save(file, Gdiplus::ImageFormatPNG);
211         else
212             hr = image1.Save(file);
213         ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
214 
215         bOK = (GetFileAttributes(file) != 0xFFFFFFFF);
216         ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
217 
218         hr = image2.Load(file);
219         ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
220 
221         width = image2.GetWidth();
222         ok(width == 48, "Expected width to be 48, was: %d (for %i)\n", width, n);
223         height = image2.GetHeight();
224         ok(height == 48, "Expected height to be 48, was: %d (for %i)\n", height, n);
225         bpp = image2.GetBPP();
226         if (n == 3)
227         {
228             ok(bpp == 24 || bpp == 32, "Expected bpp to be 24 or 32, was: %d (for %i)\n", bpp, n);
229             determine_file_bpp(file, PixelFormat24bppRGB);
230         }
231         else
232         {
233             determine_file_bpp(file, PixelFormat8bppIndexed);
234         }
235         color = image1.GetPixel(5, 5);
236         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);
237 
238         bOK = DeleteFile(file);
239         ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
240     }
241 }
242 
243 static INT FindGUID(REFGUID rguid, const CSimpleArray<GUID>& guids)
244 {
245     for (INT i = 0; i < guids.GetSize(); ++i)
246     {
247         if (memcmp(&rguid, &guids[i], sizeof(GUID)) == 0)
248             return i;
249     }
250     return -1;
251 }
252 
253 static INT FindFilterItem(const TCHAR *filter, const TCHAR *item)
254 {
255     INT iFilter = 0;
256     DWORD cbItem = lstrlen(item) * sizeof(TCHAR);
257     BOOL bSep = TRUE;
258 
259     for (; *filter; ++filter)
260     {
261         if (bSep && memcmp(item, filter, cbItem) == 0)
262             return (iFilter + 1) / 2;
263 
264         bSep = (*filter == TEXT('|'));
265         if (bSep)
266             ++iFilter;
267     }
268 
269     return -1;
270 }
271 
272 static void Test_Importer(void)
273 {
274     HRESULT hr;
275     ATL::IAtlStringMgr *mgr = CAtlStringMgr::GetInstance();
276     CSimpleArray<GUID> aguidFileTypes;
277     INT iNULL, iBMP, iJPEG, iGIF, iPNG, iTIFF, iEMF, iWMF;
278 
279     // Try importer with "All Image Files"
280     CSimpleString strImporters(mgr);
281     aguidFileTypes.RemoveAll();
282     hr = CImage::GetImporterFilterString(strImporters, aguidFileTypes, TEXT("All Image Files"), 0);
283     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
284     ok(aguidFileTypes.GetSize() >= 8,
285        "Expected aguidFileTypes.GetSize() to be >= 8, was %d.", aguidFileTypes.GetSize());
286 
287     iNULL = FindGUID(GUID_NULL, aguidFileTypes);
288     iBMP = FindGUID(Gdiplus::ImageFormatBMP, aguidFileTypes);
289     iJPEG = FindGUID(Gdiplus::ImageFormatJPEG, aguidFileTypes);
290     iGIF = FindGUID(Gdiplus::ImageFormatGIF, aguidFileTypes);
291     iPNG = FindGUID(Gdiplus::ImageFormatPNG, aguidFileTypes);
292     iTIFF = FindGUID(Gdiplus::ImageFormatTIFF, aguidFileTypes);
293     iEMF = FindGUID(Gdiplus::ImageFormatEMF, aguidFileTypes);
294     iWMF = FindGUID(Gdiplus::ImageFormatWMF, aguidFileTypes);
295 
296     ok_int(iNULL, 0);
297     ok(iBMP > 0, "iBMP was %d\n", iBMP);
298     ok(iJPEG > 0, "iJPEG was %d\n", iJPEG);
299     ok(iGIF > 0, "iGIF was %d\n", iGIF);
300     ok(iPNG > 0, "iPNG was %d\n", iPNG);
301     ok(iTIFF > 0, "iTIFF was %d\n", iTIFF);
302     ok(iEMF > 0, "iEMF was %d\n", iEMF);
303     ok(iWMF > 0, "iWMF was %d\n", iWMF);
304 
305     ok_int(memcmp(strImporters, TEXT("All Image Files|"), sizeof(TEXT("All Image Files|")) - sizeof(TCHAR)), 0);
306     ok_int(iBMP, FindFilterItem(strImporters, TEXT("BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|")));
307     ok_int(iJPEG, FindFilterItem(strImporters, TEXT("JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|")));
308     ok_int(iGIF, FindFilterItem(strImporters, TEXT("GIF (*.GIF)|*.GIF|")));
309     ok_int(iPNG, FindFilterItem(strImporters, TEXT("PNG (*.PNG)|*.PNG|")));
310     ok_int(iTIFF, FindFilterItem(strImporters, TEXT("TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|")));
311 
312     // Try importer without "All Image Files"
313     aguidFileTypes.RemoveAll();
314     strImporters.Empty();
315     hr = CImage::GetImporterFilterString(strImporters, aguidFileTypes, NULL, 0);
316     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
317     ok(aguidFileTypes.GetSize() >= 7,
318        "Expected aguidFileTypes.GetSize() to be >= 7, was %d.", aguidFileTypes.GetSize());
319 
320     iNULL = FindGUID(GUID_NULL, aguidFileTypes);
321     iBMP = FindGUID(Gdiplus::ImageFormatBMP, aguidFileTypes);
322     iJPEG = FindGUID(Gdiplus::ImageFormatJPEG, aguidFileTypes);
323     iGIF = FindGUID(Gdiplus::ImageFormatGIF, aguidFileTypes);
324     iPNG = FindGUID(Gdiplus::ImageFormatPNG, aguidFileTypes);
325     iTIFF = FindGUID(Gdiplus::ImageFormatTIFF, aguidFileTypes);
326     iEMF = FindGUID(Gdiplus::ImageFormatEMF, aguidFileTypes);
327     iWMF = FindGUID(Gdiplus::ImageFormatWMF, aguidFileTypes);
328 
329     ok_int(iNULL, -1);
330     ok_int(iBMP, 0);
331     ok(iJPEG > 0, "iJPEG was %d\n", iJPEG);
332     ok(iGIF > 0, "iGIF was %d\n", iGIF);
333     ok(iPNG > 0, "iPNG was %d\n", iPNG);
334     ok(iTIFF > 0, "iTIFF was %d\n", iTIFF);
335     ok(iEMF > 0, "iEMF was %d\n", iEMF);
336     ok(iWMF > 0, "iWMF was %d\n", iWMF);
337 
338     ok_int(iBMP, FindFilterItem(strImporters, TEXT("BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|")));
339     ok_int(iJPEG, FindFilterItem(strImporters, TEXT("JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|")));
340     ok_int(iGIF, FindFilterItem(strImporters, TEXT("GIF (*.GIF)|*.GIF|")));
341     ok_int(iPNG, FindFilterItem(strImporters, TEXT("PNG (*.PNG)|*.PNG|")));
342     ok_int(iTIFF, FindFilterItem(strImporters, TEXT("TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|")));
343 }
344 
345 static void Test_Exporter(void)
346 {
347     HRESULT hr;
348     ATL::IAtlStringMgr *mgr = CAtlStringMgr::GetInstance();
349     CSimpleArray<GUID> aguidFileTypes;
350     INT iNULL, iBMP, iJPEG, iGIF, iPNG, iTIFF;
351 
352     // Try exporter with "All Image Files"
353     CSimpleString strExporters(mgr);
354     aguidFileTypes.RemoveAll();
355     hr = CImage::GetExporterFilterString(strExporters, aguidFileTypes, TEXT("All Image Files"), 0);
356     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
357     ok(aguidFileTypes.GetSize() >= 6,
358        "Expected aguidFileTypes.GetSize() to be >= 6, was %d.", aguidFileTypes.GetSize());
359 
360     iNULL = FindGUID(GUID_NULL, aguidFileTypes);
361     iBMP = FindGUID(Gdiplus::ImageFormatBMP, aguidFileTypes);
362     iJPEG = FindGUID(Gdiplus::ImageFormatJPEG, aguidFileTypes);
363     iGIF = FindGUID(Gdiplus::ImageFormatGIF, aguidFileTypes);
364     iPNG = FindGUID(Gdiplus::ImageFormatPNG, aguidFileTypes);
365     iTIFF = FindGUID(Gdiplus::ImageFormatTIFF, aguidFileTypes);
366 
367     ok_int(iNULL, 0);
368     ok(iBMP > 0, "iBMP was %d\n", iBMP);
369     ok(iJPEG > 0, "iJPEG was %d\n", iJPEG);
370     ok(iGIF > 0, "iGIF was %d\n", iGIF);
371     ok(iPNG > 0, "iPNG was %d\n", iPNG);
372     ok(iTIFF > 0, "iTIFF was %d\n", iTIFF);
373 
374     ok_int(iBMP, FindFilterItem(strExporters, TEXT("BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|")));
375     ok_int(iJPEG, FindFilterItem(strExporters, TEXT("JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|")));
376     ok_int(iGIF, FindFilterItem(strExporters, TEXT("GIF (*.GIF)|*.GIF|")));
377     ok_int(iPNG, FindFilterItem(strExporters, TEXT("PNG (*.PNG)|*.PNG|")));
378     ok_int(iTIFF, FindFilterItem(strExporters, TEXT("TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|")));
379 
380     // Try exporter without "All Image Files"
381     strExporters.Empty();
382     aguidFileTypes.RemoveAll();
383     hr = CImage::GetExporterFilterString(strExporters, aguidFileTypes, NULL, 0);
384     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
385     ok(aguidFileTypes.GetSize() >= 5,
386        "Expected aguidFileTypes.GetSize() to be >= 5, was %d.", aguidFileTypes.GetSize());
387 
388     iNULL = FindGUID(GUID_NULL, aguidFileTypes);
389     iBMP = FindGUID(Gdiplus::ImageFormatBMP, aguidFileTypes);
390     iJPEG = FindGUID(Gdiplus::ImageFormatJPEG, aguidFileTypes);
391     iGIF = FindGUID(Gdiplus::ImageFormatGIF, aguidFileTypes);
392     iPNG = FindGUID(Gdiplus::ImageFormatPNG, aguidFileTypes);
393     iTIFF = FindGUID(Gdiplus::ImageFormatTIFF, aguidFileTypes);
394 
395     ok_int(iNULL, -1);
396     ok_int(iBMP, 0);
397     ok(iJPEG > 0, "iJPEG was %d\n", iJPEG);
398     ok(iGIF > 0, "iGIF was %d\n", iGIF);
399     ok(iPNG > 0, "iPNG was %d\n", iPNG);
400     ok(iTIFF > 0, "iTIFF was %d\n", iTIFF);
401 
402     ok_int(iBMP, FindFilterItem(strExporters, TEXT("BMP (*.BMP;*.DIB;*.RLE)|*.BMP;*.DIB;*.RLE|")));
403     ok_int(iJPEG, FindFilterItem(strExporters, TEXT("JPEG (*.JPG;*.JPEG;*.JPE;*.JFIF)|*.JPG;*.JPEG;*.JPE;*.JFIF|")));
404     ok_int(iGIF, FindFilterItem(strExporters, TEXT("GIF (*.GIF)|*.GIF|")));
405     ok_int(iPNG, FindFilterItem(strExporters, TEXT("PNG (*.PNG)|*.PNG|")));
406     ok_int(iTIFF, FindFilterItem(strExporters, TEXT("TIFF (*.TIF;*.TIFF)|*.TIF;*.TIFF|")));
407 }
408 
409 START_TEST(CImage)
410 {
411     Test_LoadSaveImage();
412     Test_Importer();
413     Test_Exporter();
414 }
415