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 
105 static void determine_file_bpp(TCHAR* tfile, Gdiplus::PixelFormat expect_pf)
106 {
107     using namespace Gdiplus;
108     GpBitmap *pBitmap = NULL;
109 
110 #ifdef UNICODE
111     WCHAR* file = tfile;
112 #else
113     WCHAR file[MAX_PATH];
114     ::MultiByteToWideChar(CP_ACP, 0, tfile, -1, file, MAX_PATH);
115 #endif
116 
117     if (Startup == NULL)
118         init_gdip();
119 
120     Gdiplus::GdiplusStartupInput gdiplusStartupInput;
121     Startup(&gdiplusToken, &gdiplusStartupInput, NULL);
122 
123 
124     Gdiplus::GpStatus status = CreateBitmapFromFile(file, &pBitmap);
125     ok(status == Gdiplus::Ok, "Expected status to be %i, was: %i\n", (int)Gdiplus::Ok, (int)status);
126     ok(pBitmap != NULL, "Expected a valid bitmap\n");
127     if (pBitmap)
128     {
129         PixelFormat pf;
130         GetImagePixelFormat(pBitmap, &pf);
131         ok(pf == expect_pf, "Expected PixelFormat to be 0x%x, was: 0x%x\n", (int)expect_pf, (int)pf);
132 
133         DisposeImage(pBitmap);
134     }
135     Shutdown(gdiplusToken);
136 }
137 
138 
139 START_TEST(CImage)
140 {
141     HRESULT hr;
142     TCHAR* file;
143     BOOL bOK;
144     int width, height, bpp;
145     size_t n;
146     CImage image1, image2;
147     COLORREF color;
148     HDC hDC;
149 
150 #if 0
151     width = image1.GetWidth();
152     height = image1.GetHeight();
153     bpp = image1.GetBPP();
154 #endif
155 
156     HINSTANCE hInst = GetModuleHandle(NULL);
157     GetTempPath(MAX_PATH, szTempPath);
158 
159     image1.LoadFromResource(hInst, IDB_ANT);
160     ok(!image1.IsNull(), "Expected image1 is not null\n");
161 
162     width = image1.GetWidth();
163     ok(width == 48, "Expected width to be 48, was: %d\n", width);
164     height = image1.GetHeight();
165     ok(height == 48, "Expected height to be 48, was: %d\n", height);
166     bpp = image1.GetBPP();
167     ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
168 
169 
170     image2.LoadFromResource(hInst, IDB_CROSS);
171     ok(!image2.IsNull(), "Expected image2 is not null\n");
172     image2.SetTransparentColor(RGB(255, 255, 255));
173 
174     width = image2.GetWidth();
175     ok(width == 32, "Expected width to be 32, was: %d\n", width);
176     height = image2.GetHeight();
177     ok(height == 32, "Expected height to be 32, was: %d\n", height);
178     bpp = image2.GetBPP();
179     ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp);
180 
181     color = image1.GetPixel(5, 5);
182     ok(color == RGB(166, 202, 240), "Expected color to be 166, 202, 240; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
183 
184     hDC = image1.GetDC();
185     bOK = image2.Draw(hDC, 0, 0);
186     image1.ReleaseDC();
187     ok(bOK != FALSE, "Expected bDraw to be TRUE, was: %d\n", bOK);
188     image2.Destroy();
189 
190     color = image1.GetPixel(5, 5);
191     ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color));
192 
193     file = file_name(TEXT("ant.bmp"));
194     write_bitmap(hInst, IDB_ANT, file);
195 
196     init_gdip();
197 
198     determine_file_bpp(file, PixelFormat8bppIndexed);
199 
200     hr = image2.Load(file);
201     ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx\n", hr);
202     ok(!image2.IsNull(), "Expected image1 is not null\n");
203     bOK = DeleteFile(file);
204     ok(bOK, "Expected bOK to be TRUE, was: %d\n", bOK);
205 
206     width = image2.GetWidth();
207     ok_int(width, 48);
208     height = image2.GetHeight();
209     ok_int(height, 48);
210     bpp = image2.GetBPP();
211     ok_int(bpp, 32);
212 
213     for (n = 0; n < _countof(szFiles); ++n)
214     {
215         file = file_name(szFiles[n]);
216         image2.Destroy();
217 
218         if (n == 0)
219             hr = image1.Save(file, Gdiplus::ImageFormatPNG);
220         else
221             hr = image1.Save(file);
222         ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
223 
224         bOK = (GetFileAttributes(file) != 0xFFFFFFFF);
225         ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
226 
227         hr = image2.Load(file);
228         ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n);
229 
230         width = image2.GetWidth();
231         ok(width == 48, "Expected width to be 48, was: %d (for %i)\n", width, n);
232         height = image2.GetHeight();
233         ok(height == 48, "Expected height to be 48, was: %d (for %i)\n", height, n);
234         bpp = image2.GetBPP();
235         if (n == 3)
236         {
237             ok(bpp == 32, "Expected bpp to be 32, was: %d (for %i)\n", bpp, n);
238             determine_file_bpp(file, PixelFormat24bppRGB);
239         }
240         else
241         {
242             ok(bpp == 32, "Expected bpp to be 32, was: %d (for %i)\n", bpp, n);
243             determine_file_bpp(file, PixelFormat8bppIndexed);
244         }
245         color = image1.GetPixel(5, 5);
246         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);
247 
248         bOK = DeleteFile(file);
249         ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n);
250     }
251 
252     ATL::IAtlStringMgr *mgr = CAtlStringMgr::GetInstance();
253     CSimpleArray<GUID> aguidFileTypes;
254 #ifdef UNICODE
255     CHAR szBuff[512];
256     const WCHAR *psz;
257 #else
258     const CHAR *psz;
259 #endif
260 
261     CSimpleString strImporters(mgr);
262     aguidFileTypes.RemoveAll();
263     hr = CImage::GetImporterFilterString(strImporters,
264                                          aguidFileTypes,
265                                          TEXT("All Image Files"), 0);
266     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
267     ok(aguidFileTypes.GetSize() == 9, "Expected aguidFileTypes.GetSize() to be 8, was %d.", aguidFileTypes.GetSize());
268     ok(IsEqualGUID(aguidFileTypes[0], GUID_NULL), "Expected aguidFileTypes[0] to be GUID_NULL.\n");
269     ok(IsEqualGUID(aguidFileTypes[1], Gdiplus::ImageFormatBMP), "Expected aguidFileTypes[1] to be Gdiplus::ImageFormatBMP.\n");
270     ok(IsEqualGUID(aguidFileTypes[2], Gdiplus::ImageFormatJPEG), "Expected aguidFileTypes[2] to be Gdiplus::ImageFormatJPEG.\n");
271     ok(IsEqualGUID(aguidFileTypes[3], Gdiplus::ImageFormatGIF), "Expected aguidFileTypes[3] to be Gdiplus::ImageFormatGIF.\n");
272     ok(IsEqualGUID(aguidFileTypes[4], Gdiplus::ImageFormatEMF), "Expected aguidFileTypes[4] to be Gdiplus::ImageFormatEMF.\n");
273     ok(IsEqualGUID(aguidFileTypes[5], Gdiplus::ImageFormatWMF), "Expected aguidFileTypes[5] to be Gdiplus::ImageFormatWMF.\n");
274     ok(IsEqualGUID(aguidFileTypes[6], Gdiplus::ImageFormatTIFF), "Expected aguidFileTypes[6] to be Gdiplus::ImageFormatTIFF.\n");
275     ok(IsEqualGUID(aguidFileTypes[7], Gdiplus::ImageFormatPNG), "Expected aguidFileTypes[7] to be Gdiplus::ImageFormatPNG.\n");
276     ok(IsEqualGUID(aguidFileTypes[8], Gdiplus::ImageFormatIcon), "Expected aguidFileTypes[8] to be Gdiplus::ImageFormatIcon.\n");
277 
278     psz = strImporters.GetString();
279 #ifdef UNICODE
280     WideCharToMultiByte(CP_ACP, 0, psz, -1, szBuff, 512, NULL, NULL);
281     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,
282        "The importer filter string is bad, was: %s\n", szBuff);
283 #else
284     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,
285        "The importer filter string is bad, was: %s\n", psz);
286 #endif
287 
288     CSimpleString strExporters(mgr);
289     aguidFileTypes.RemoveAll();
290     hr = CImage::GetExporterFilterString(strExporters,
291                                          aguidFileTypes,
292                                          TEXT("All Image Files"), 0);
293     ok(hr == S_OK, "Expected hr to be S_OK, was: %ld\n", hr);
294     ok(aguidFileTypes.GetSize() == 9, "Expected aguidFileTypes.GetSize() to be 8, was %d.", aguidFileTypes.GetSize());
295     ok(IsEqualGUID(aguidFileTypes[0], GUID_NULL), "Expected aguidFileTypes[0] to be GUID_NULL.\n");
296     ok(IsEqualGUID(aguidFileTypes[1], Gdiplus::ImageFormatBMP), "Expected aguidFileTypes[1] to be Gdiplus::ImageFormatBMP.\n");
297     ok(IsEqualGUID(aguidFileTypes[2], Gdiplus::ImageFormatJPEG), "Expected aguidFileTypes[2] to be Gdiplus::ImageFormatJPEG.\n");
298     ok(IsEqualGUID(aguidFileTypes[3], Gdiplus::ImageFormatGIF), "Expected aguidFileTypes[3] to be Gdiplus::ImageFormatGIF.\n");
299     ok(IsEqualGUID(aguidFileTypes[4], Gdiplus::ImageFormatEMF), "Expected aguidFileTypes[4] to be Gdiplus::ImageFormatEMF.\n");
300     ok(IsEqualGUID(aguidFileTypes[5], Gdiplus::ImageFormatWMF), "Expected aguidFileTypes[5] to be Gdiplus::ImageFormatWMF.\n");
301     ok(IsEqualGUID(aguidFileTypes[6], Gdiplus::ImageFormatTIFF), "Expected aguidFileTypes[6] to be Gdiplus::ImageFormatTIFF.\n");
302     ok(IsEqualGUID(aguidFileTypes[7], Gdiplus::ImageFormatPNG), "Expected aguidFileTypes[7] to be Gdiplus::ImageFormatPNG.\n");
303     ok(IsEqualGUID(aguidFileTypes[8], Gdiplus::ImageFormatIcon), "Expected aguidFileTypes[8] to be Gdiplus::ImageFormatIcon.\n");
304 
305     psz = strExporters.GetString();
306 #ifdef UNICODE
307     WideCharToMultiByte(CP_ACP, 0, psz, -1, szBuff, 512, NULL, NULL);
308     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,
309        "The exporter filter string is bad, was: %s\n", szBuff);
310 #else
311     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,
312        "The exporter filter string is bad, was: %s\n", psz);
313 #endif
314 }
315