1 /*
2  * Unit test suite for images
3  *
4  * Copyright (C) 2007 Google (Evan Stade)
5  * Copyright (C) 2012,2016 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "precomp.h"
23 
24 #include <assert.h>
25 #include <ole2.h>
26 
27 /* FIXME: They belong to gdipluseffects.h */
28 DEFINE_GUID(BlurEffectGuid, 0x633c80a4, 0x1843, 0x482b, 0x9e, 0xf2, 0xbe, 0x28, 0x34, 0xc5, 0xfd, 0xd4);
29 DEFINE_GUID(SharpenEffectGuid, 0x63cbf3ee, 0xc526, 0x402c, 0x8f, 0x71, 0x62, 0xc5, 0x40, 0xbf, 0x51, 0x42);
30 DEFINE_GUID(ColorMatrixEffectGuid, 0x718f2615, 0x7933, 0x40e3, 0xa5, 0x11, 0x5f, 0x68, 0xfe, 0x14, 0xdd, 0x74);
31 DEFINE_GUID(ColorLUTEffectGuid, 0xa7ce72a9, 0x0f7f, 0x40d7, 0xb3, 0xcc, 0xd0, 0xc0, 0x2d, 0x5c, 0x32, 0x12);
32 DEFINE_GUID(BrightnessContrastEffectGuid, 0xd3a1dbe1, 0x8ec4, 0x4c17, 0x9f, 0x4c, 0xea, 0x97, 0xad, 0x1c, 0x34, 0x3d);
33 DEFINE_GUID(HueSaturationLightnessEffectGuid, 0x8b2dd6c3, 0xeb07, 0x4d87, 0xa5, 0xf0, 0x71, 0x08, 0xe2, 0x6a, 0x9c, 0x5f);
34 DEFINE_GUID(LevelsEffectGuid, 0x99c354ec, 0x2a31, 0x4f3a, 0x8c, 0x34, 0x17, 0xa8, 0x03, 0xb3, 0x3a, 0x25);
35 DEFINE_GUID(TintEffectGuid, 0x1077af00, 0x2848, 0x4441, 0x94, 0x89, 0x44, 0xad, 0x4c, 0x2d, 0x7a, 0x2c);
36 DEFINE_GUID(ColorBalanceEffectGuid, 0x537e597d, 0x251e, 0x48da, 0x96, 0x64, 0x29, 0xca, 0x49, 0x6b, 0x70, 0xf8);
37 DEFINE_GUID(RedEyeCorrectionEffectGuid, 0x74d29d05, 0x69a4, 0x4266, 0x95, 0x49, 0x3c, 0xc5, 0x28, 0x36, 0xb6, 0x32);
38 DEFINE_GUID(ColorCurveEffectGuid, 0xdd6a0022, 0x58e4, 0x4a67, 0x9d, 0x9b, 0xd4, 0x8e, 0xb8, 0x81, 0xa5, 0x3d);
39 
40 static GpStatus (WINAPI *pGdipBitmapGetHistogramSize)(HistogramFormat,UINT*);
41 static GpStatus (WINAPI *pGdipBitmapGetHistogram)(GpBitmap*,HistogramFormat,UINT,UINT*,UINT*,UINT*,UINT*);
42 static GpStatus (WINAPI *pGdipImageSetAbort)(GpImage*,GdiplusAbort*);
43 
44 static GpStatus (WINGDIPAPI *pGdipInitializePalette)(ColorPalette*,PaletteType,INT,BOOL,GpBitmap*);
45 
46 #define expect(expected, got) ok((got) == (expected), "Expected %d, got %d\n", (UINT)(expected), (UINT)(got))
47 #define expectf(expected, got) ok(fabs((expected) - (got)) < 0.0001, "Expected %f, got %f\n", (expected), (got))
48 
49 static BOOL color_match(ARGB c1, ARGB c2, BYTE max_diff)
50 {
51     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
52     c1 >>= 8; c2 >>= 8;
53     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
54     c1 >>= 8; c2 >>= 8;
55     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
56     c1 >>= 8; c2 >>= 8;
57     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
58     return TRUE;
59 }
60 
61 static void expect_guid(REFGUID expected, REFGUID got, int line, BOOL todo)
62 {
63     WCHAR bufferW[39];
64     char buffer[39];
65     char buffer2[39];
66 
67     StringFromGUID2(got, bufferW, sizeof(bufferW)/sizeof(bufferW[0]));
68     WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer, sizeof(buffer), NULL, NULL);
69     StringFromGUID2(expected, bufferW, sizeof(bufferW)/sizeof(bufferW[0]));
70     WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer2, sizeof(buffer2), NULL, NULL);
71     todo_wine_if (todo)
72         ok_(__FILE__, line)(IsEqualGUID(expected, got), "Expected %s, got %s\n", buffer2, buffer);
73 }
74 
75 static void expect_rawformat(REFGUID expected, GpImage *img, int line, BOOL todo)
76 {
77     GUID raw;
78     GpStatus stat;
79 
80     stat = GdipGetImageRawFormat(img, &raw);
81     ok_(__FILE__, line)(stat == Ok, "GdipGetImageRawFormat failed with %d\n", stat);
82     if(stat != Ok) return;
83     expect_guid(expected, &raw, line, todo);
84 }
85 
86 static void test_bufferrawformat(void* buff, int size, REFGUID expected, int line, BOOL todo)
87 {
88     LPSTREAM stream;
89     HGLOBAL  hglob;
90     LPBYTE   data;
91     HRESULT  hres;
92     GpStatus stat;
93     GpImage *img;
94 
95     hglob = GlobalAlloc (0, size);
96     data = GlobalLock (hglob);
97     memcpy(data, buff, size);
98     GlobalUnlock(hglob); data = NULL;
99 
100     hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
101     ok_(__FILE__, line)(hres == S_OK, "Failed to create a stream\n");
102     if(hres != S_OK) return;
103 
104     stat = GdipLoadImageFromStream(stream, &img);
105     ok_(__FILE__, line)(stat == Ok, "Failed to create a Bitmap\n");
106     if(stat != Ok){
107         IStream_Release(stream);
108         return;
109     }
110 
111     expect_rawformat(expected, img, line, todo);
112 
113     GdipDisposeImage(img);
114     IStream_Release(stream);
115 }
116 
117 static void test_Scan0(void)
118 {
119     GpBitmap *bm;
120     GpStatus stat;
121     BYTE buff[360];
122 
123     bm = NULL;
124     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat24bppRGB, NULL, &bm);
125     expect(Ok, stat);
126     ok(NULL != bm, "Expected bitmap to be initialized\n");
127     if (stat == Ok)
128         GdipDisposeImage((GpImage*)bm);
129 
130     bm = (GpBitmap*)0xdeadbeef;
131     stat = GdipCreateBitmapFromScan0(10, -10, 10, PixelFormat24bppRGB, NULL, &bm);
132     expect(InvalidParameter, stat);
133     ok( !bm, "expected null bitmap\n" );
134 
135     bm = (GpBitmap*)0xdeadbeef;
136     stat = GdipCreateBitmapFromScan0(-10, 10, 10, PixelFormat24bppRGB, NULL, &bm);
137     expect(InvalidParameter, stat);
138     ok( !bm, "expected null bitmap\n" );
139 
140     bm = (GpBitmap*)0xdeadbeef;
141     stat = GdipCreateBitmapFromScan0(10, 0, 10, PixelFormat24bppRGB, NULL, &bm);
142     expect(InvalidParameter, stat);
143     ok( !bm, "expected null bitmap\n" );
144 
145     bm = NULL;
146     stat = GdipCreateBitmapFromScan0(10, 10, 12, PixelFormat24bppRGB, buff, &bm);
147     expect(Ok, stat);
148     ok(NULL != bm, "Expected bitmap to be initialized\n");
149     if (stat == Ok)
150         GdipDisposeImage((GpImage*)bm);
151 
152     bm = (GpBitmap*) 0xdeadbeef;
153     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat24bppRGB, buff, &bm);
154     expect(InvalidParameter, stat);
155     ok( !bm, "expected null bitmap\n" );
156 
157     bm = (GpBitmap*)0xdeadbeef;
158     stat = GdipCreateBitmapFromScan0(10, 10, 0, PixelFormat24bppRGB, buff, &bm);
159     expect(InvalidParameter, stat);
160     ok( bm == (GpBitmap*)0xdeadbeef, "expected deadbeef bitmap\n" );
161 
162     bm = NULL;
163     stat = GdipCreateBitmapFromScan0(10, 10, -8, PixelFormat24bppRGB, buff, &bm);
164     expect(Ok, stat);
165     ok(NULL != bm, "Expected bitmap to be initialized\n");
166     if (stat == Ok)
167         GdipDisposeImage((GpImage*)bm);
168 
169     bm = (GpBitmap*)0xdeadbeef;
170     stat = GdipCreateBitmapFromScan0(10, 10, -10, PixelFormat24bppRGB, buff, &bm);
171     expect(InvalidParameter, stat);
172     ok( !bm, "expected null bitmap\n" );
173 }
174 
175 static void test_FromGdiDib(void)
176 {
177     GpBitmap *bm;
178     GpStatus stat;
179     BYTE buff[400];
180     BYTE rbmi[sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)];
181     BITMAPINFO *bmi = (BITMAPINFO*)rbmi;
182     PixelFormat format;
183 
184     bm = NULL;
185 
186     memset(rbmi, 0, sizeof(rbmi));
187 
188     bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
189     bmi->bmiHeader.biWidth = 10;
190     bmi->bmiHeader.biHeight = 10;
191     bmi->bmiHeader.biPlanes = 1;
192     bmi->bmiHeader.biBitCount = 32;
193     bmi->bmiHeader.biCompression = BI_RGB;
194 
195     stat = GdipCreateBitmapFromGdiDib(NULL, buff, &bm);
196     expect(InvalidParameter, stat);
197 
198     stat = GdipCreateBitmapFromGdiDib(bmi, NULL, &bm);
199     expect(InvalidParameter, stat);
200 
201     stat = GdipCreateBitmapFromGdiDib(bmi, buff, NULL);
202     expect(InvalidParameter, stat);
203 
204     stat = GdipCreateBitmapFromGdiDib(bmi, buff, &bm);
205     expect(Ok, stat);
206     ok(NULL != bm, "Expected bitmap to be initialized\n");
207     if (stat == Ok)
208     {
209         stat = GdipGetImagePixelFormat((GpImage*)bm, &format);
210         expect(Ok, stat);
211         expect(PixelFormat32bppRGB, format);
212 
213         GdipDisposeImage((GpImage*)bm);
214     }
215 
216     bmi->bmiHeader.biBitCount = 24;
217     stat = GdipCreateBitmapFromGdiDib(bmi, buff, &bm);
218     expect(Ok, stat);
219     ok(NULL != bm, "Expected bitmap to be initialized\n");
220     if (stat == Ok)
221     {
222         stat = GdipGetImagePixelFormat((GpImage*)bm, &format);
223         expect(Ok, stat);
224         expect(PixelFormat24bppRGB, format);
225 
226         GdipDisposeImage((GpImage*)bm);
227     }
228 
229     bmi->bmiHeader.biBitCount = 16;
230     stat = GdipCreateBitmapFromGdiDib(bmi, buff, &bm);
231     expect(Ok, stat);
232     ok(NULL != bm, "Expected bitmap to be initialized\n");
233     if (stat == Ok)
234     {
235         stat = GdipGetImagePixelFormat((GpImage*)bm, &format);
236         expect(Ok, stat);
237         expect(PixelFormat16bppRGB555, format);
238 
239         GdipDisposeImage((GpImage*)bm);
240     }
241 
242     bmi->bmiHeader.biBitCount = 8;
243     stat = GdipCreateBitmapFromGdiDib(bmi, buff, &bm);
244     expect(Ok, stat);
245     ok(NULL != bm, "Expected bitmap to be initialized\n");
246     if (stat == Ok)
247     {
248         stat = GdipGetImagePixelFormat((GpImage*)bm, &format);
249         expect(Ok, stat);
250         expect(PixelFormat8bppIndexed, format);
251 
252         GdipDisposeImage((GpImage*)bm);
253     }
254 
255     bmi->bmiHeader.biBitCount = 4;
256     stat = GdipCreateBitmapFromGdiDib(bmi, buff, &bm);
257     expect(Ok, stat);
258     ok(NULL != bm, "Expected bitmap to be initialized\n");
259     if (stat == Ok)
260     {
261         stat = GdipGetImagePixelFormat((GpImage*)bm, &format);
262         expect(Ok, stat);
263         expect(PixelFormat4bppIndexed, format);
264 
265         GdipDisposeImage((GpImage*)bm);
266     }
267 
268     bmi->bmiHeader.biBitCount = 1;
269     stat = GdipCreateBitmapFromGdiDib(bmi, buff, &bm);
270     expect(Ok, stat);
271     ok(NULL != bm, "Expected bitmap to be initialized\n");
272     if (stat == Ok)
273     {
274         stat = GdipGetImagePixelFormat((GpImage*)bm, &format);
275         expect(Ok, stat);
276         expect(PixelFormat1bppIndexed, format);
277 
278         GdipDisposeImage((GpImage*)bm);
279     }
280 
281     bmi->bmiHeader.biBitCount = 0;
282     stat = GdipCreateBitmapFromGdiDib(bmi, buff, &bm);
283     expect(InvalidParameter, stat);
284 }
285 
286 static void test_GetImageDimension(void)
287 {
288     GpBitmap *bm;
289     GpStatus stat;
290     const REAL WIDTH = 10.0, HEIGHT = 20.0;
291     REAL w,h;
292 
293     bm = (GpBitmap*)0xdeadbeef;
294     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB,NULL, &bm);
295     expect(Ok,stat);
296     ok((GpBitmap*)0xdeadbeef != bm, "Expected bitmap to not be 0xdeadbeef\n");
297     ok(NULL != bm, "Expected bitmap to not be NULL\n");
298 
299     stat = GdipGetImageDimension(NULL,&w,&h);
300     expect(InvalidParameter, stat);
301 
302     stat = GdipGetImageDimension((GpImage*)bm,NULL,&h);
303     expect(InvalidParameter, stat);
304 
305     stat = GdipGetImageDimension((GpImage*)bm,&w,NULL);
306     expect(InvalidParameter, stat);
307 
308     w = -1;
309     h = -1;
310     stat = GdipGetImageDimension((GpImage*)bm,&w,&h);
311     expect(Ok, stat);
312     expectf(WIDTH,  w);
313     expectf(HEIGHT, h);
314     GdipDisposeImage((GpImage*)bm);
315 }
316 
317 static void test_GdipImageGetFrameDimensionsCount(void)
318 {
319     GpBitmap *bm;
320     GpStatus stat;
321     const REAL WIDTH = 10.0, HEIGHT = 20.0;
322     UINT w;
323     GUID dimension = {0};
324     UINT count;
325     ARGB color;
326 
327     bm = (GpBitmap*)0xdeadbeef;
328     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB,NULL, &bm);
329     expect(Ok,stat);
330     ok((GpBitmap*)0xdeadbeef != bm, "Expected bitmap to not be 0xdeadbeef\n");
331     ok(NULL != bm, "Expected bitmap to not be NULL\n");
332 
333     stat = GdipImageGetFrameDimensionsCount(NULL,&w);
334     expect(InvalidParameter, stat);
335 
336     stat = GdipImageGetFrameDimensionsCount((GpImage*)bm,NULL);
337     expect(InvalidParameter, stat);
338 
339     w = -1;
340     stat = GdipImageGetFrameDimensionsCount((GpImage*)bm,&w);
341     expect(Ok, stat);
342     expect(1, w);
343 
344     stat = GdipImageGetFrameDimensionsList((GpImage*)bm, &dimension, 1);
345     expect(Ok, stat);
346     expect_guid(&FrameDimensionPage, &dimension, __LINE__, FALSE);
347 
348     stat = GdipImageGetFrameDimensionsList((GpImage*)bm, &dimension, 2);
349     expect(InvalidParameter, stat);
350 
351     stat = GdipImageGetFrameDimensionsList((GpImage*)bm, &dimension, 0);
352     expect(InvalidParameter, stat);
353 
354     stat = GdipImageGetFrameCount(NULL, &dimension, &count);
355     expect(InvalidParameter, stat);
356 
357     /* WinXP crashes on this test */
358     if(0)
359     {
360         stat = GdipImageGetFrameCount((GpImage*)bm, &dimension, NULL);
361         expect(InvalidParameter, stat);
362     }
363 
364     stat = GdipImageGetFrameCount((GpImage*)bm, NULL, &count);
365     expect(Ok, stat);
366 
367     count = 12345;
368     stat = GdipImageGetFrameCount((GpImage*)bm, &dimension, &count);
369     expect(Ok, stat);
370     expect(1, count);
371 
372     GdipBitmapSetPixel(bm, 0, 0, 0xffffffff);
373 
374     stat = GdipImageSelectActiveFrame((GpImage*)bm, &dimension, 0);
375     expect(Ok, stat);
376 
377     /* SelectActiveFrame has no effect on image data of memory bitmaps */
378     color = 0xdeadbeef;
379     GdipBitmapGetPixel(bm, 0, 0, &color);
380     expect(0xffffffff, color);
381 
382     GdipDisposeImage((GpImage*)bm);
383 }
384 
385 static void test_LoadingImages(void)
386 {
387     GpStatus stat;
388     GpBitmap *bm;
389     GpImage *img;
390     static const WCHAR nonexistentW[] = {'n','o','n','e','x','i','s','t','e','n','t',0};
391 
392     stat = GdipCreateBitmapFromFile(0, 0);
393     expect(InvalidParameter, stat);
394 
395     bm = (GpBitmap *)0xdeadbeef;
396     stat = GdipCreateBitmapFromFile(0, &bm);
397     expect(InvalidParameter, stat);
398     ok(bm == (GpBitmap *)0xdeadbeef, "returned %p\n", bm);
399 
400     bm = (GpBitmap *)0xdeadbeef;
401     stat = GdipCreateBitmapFromFile(nonexistentW, &bm);
402     todo_wine expect(InvalidParameter, stat);
403     ok(!bm, "returned %p\n", bm);
404 
405     stat = GdipLoadImageFromFile(0, 0);
406     expect(InvalidParameter, stat);
407 
408     img = (GpImage *)0xdeadbeef;
409     stat = GdipLoadImageFromFile(0, &img);
410     expect(InvalidParameter, stat);
411     ok(img == (GpImage *)0xdeadbeef, "returned %p\n", img);
412 
413     img = (GpImage *)0xdeadbeef;
414     stat = GdipLoadImageFromFile(nonexistentW, &img);
415     todo_wine expect(OutOfMemory, stat);
416     ok(!img, "returned %p\n", img);
417 
418     stat = GdipLoadImageFromFileICM(0, 0);
419     expect(InvalidParameter, stat);
420 
421     img = (GpImage *)0xdeadbeef;
422     stat = GdipLoadImageFromFileICM(0, &img);
423     expect(InvalidParameter, stat);
424     ok(img == (GpImage *)0xdeadbeef, "returned %p\n", img);
425 
426     img = (GpImage *)0xdeadbeef;
427     stat = GdipLoadImageFromFileICM(nonexistentW, &img);
428     todo_wine expect(OutOfMemory, stat);
429     ok(!img, "returned %p\n", img);
430 }
431 
432 static void test_SavingImages(void)
433 {
434     GpStatus stat;
435     GpBitmap *bm;
436     UINT n;
437     UINT s;
438     const REAL WIDTH = 10.0, HEIGHT = 20.0;
439     REAL w, h;
440     ImageCodecInfo *codecs;
441     static const CHAR filenameA[] = "a.bmp";
442     static const WCHAR filename[] = { 'a','.','b','m','p',0 };
443 
444     codecs = NULL;
445 
446     stat = GdipSaveImageToFile(0, 0, 0, 0);
447     expect(InvalidParameter, stat);
448 
449     bm = NULL;
450     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
451     expect(Ok, stat);
452     if (!bm)
453         return;
454 
455     /* invalid params */
456     stat = GdipSaveImageToFile((GpImage*)bm, 0, 0, 0);
457     expect(InvalidParameter, stat);
458 
459     stat = GdipSaveImageToFile((GpImage*)bm, filename, 0, 0);
460     expect(InvalidParameter, stat);
461 
462     /* encoder tests should succeed -- already tested */
463     stat = GdipGetImageEncodersSize(&n, &s);
464     if (stat != Ok || n == 0) goto cleanup;
465 
466     codecs = GdipAlloc(s);
467     if (!codecs) goto cleanup;
468 
469     stat = GdipGetImageEncoders(n, s, codecs);
470     if (stat != Ok) goto cleanup;
471 
472     stat = GdipSaveImageToFile((GpImage*)bm, filename, &codecs[0].Clsid, 0);
473     expect(Ok, stat);
474 
475     GdipDisposeImage((GpImage*)bm);
476     bm = 0;
477 
478     /* re-load and check image stats */
479     stat = GdipLoadImageFromFile(filename, (GpImage**)&bm);
480     expect(Ok, stat);
481     if (stat != Ok) goto cleanup;
482 
483     stat = GdipGetImageDimension((GpImage*)bm, &w, &h);
484     if (stat != Ok) goto cleanup;
485 
486     expectf(WIDTH, w);
487     expectf(HEIGHT, h);
488 
489  cleanup:
490     GdipFree(codecs);
491     if (bm)
492         GdipDisposeImage((GpImage*)bm);
493     ok(DeleteFileA(filenameA), "Delete failed.\n");
494 }
495 
496 static void test_encoders(void)
497 {
498     GpStatus stat;
499     UINT n;
500     UINT s;
501     ImageCodecInfo *codecs;
502     int i;
503     int bmp_found;
504 
505     static const CHAR bmp_format[] = "BMP";
506 
507     stat = GdipGetImageEncodersSize(&n, &s);
508     expect(stat, Ok);
509 
510     codecs = GdipAlloc(s);
511     if (!codecs)
512         return;
513 
514     stat = GdipGetImageEncoders(n, s, NULL);
515     expect(GenericError, stat);
516 
517     stat = GdipGetImageEncoders(0, s, codecs);
518     expect(GenericError, stat);
519 
520     stat = GdipGetImageEncoders(n, s-1, codecs);
521     expect(GenericError, stat);
522 
523     stat = GdipGetImageEncoders(n, s+1, codecs);
524     expect(GenericError, stat);
525 
526     stat = GdipGetImageEncoders(n, s, codecs);
527     expect(stat, Ok);
528 
529     bmp_found = FALSE;
530     for (i = 0; i < n; i++)
531         {
532             CHAR desc[32];
533 
534             WideCharToMultiByte(CP_ACP, 0, codecs[i].FormatDescription, -1,
535                                 desc, 32, 0, 0);
536 
537             if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0,
538                                desc, -1,
539                                bmp_format, -1) == CSTR_EQUAL) {
540                 bmp_found = TRUE;
541                 break;
542             }
543         }
544     if (!bmp_found)
545         ok(FALSE, "No BMP codec found.\n");
546 
547     GdipFree(codecs);
548 }
549 
550 static void test_LockBits(void)
551 {
552     GpStatus stat;
553     GpBitmap *bm;
554     GpRect rect;
555     BitmapData bd;
556     const INT WIDTH = 10, HEIGHT = 20;
557     ARGB color;
558     int y;
559 
560     bm = NULL;
561     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
562     expect(Ok, stat);
563 
564     rect.X = 2;
565     rect.Y = 3;
566     rect.Width = 4;
567     rect.Height = 5;
568 
569     stat = GdipBitmapSetPixel(bm, 2, 3, 0xffc30000);
570     expect(Ok, stat);
571 
572     stat = GdipBitmapSetPixel(bm, 2, 8, 0xff480000);
573     expect(Ok, stat);
574 
575     /* read-only */
576     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead, PixelFormat24bppRGB, &bd);
577     expect(Ok, stat);
578 
579     if (stat == Ok) {
580         expect(0xc3, ((BYTE*)bd.Scan0)[2]);
581         expect(0x48, ((BYTE*)bd.Scan0)[2 + bd.Stride * 5]);
582 
583         ((char*)bd.Scan0)[2] = 0xff;
584 
585         stat = GdipBitmapUnlockBits(bm, &bd);
586         expect(Ok, stat);
587     }
588 
589     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
590     expect(Ok, stat);
591     expect(0xffff0000, color);
592 
593     stat = GdipBitmapSetPixel(bm, 2, 3, 0xffc30000);
594     expect(Ok, stat);
595 
596     /* read-only, with NULL rect -> whole bitmap lock */
597     stat = GdipBitmapLockBits(bm, NULL, ImageLockModeRead, PixelFormat24bppRGB, &bd);
598     expect(Ok, stat);
599     expect(bd.Width,  WIDTH);
600     expect(bd.Height, HEIGHT);
601 
602     if (stat == Ok) {
603         ((char*)bd.Scan0)[2 + 2*3 + 3*bd.Stride] = 0xff;
604 
605         stat = GdipBitmapUnlockBits(bm, &bd);
606         expect(Ok, stat);
607     }
608 
609     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
610     expect(Ok, stat);
611     expect(0xffff0000, color);
612 
613     /* read-only, consecutive */
614     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead, PixelFormat24bppRGB, &bd);
615     expect(Ok, stat);
616 
617     if (stat == Ok) {
618         stat = GdipBitmapUnlockBits(bm, &bd);
619         expect(Ok, stat);
620     }
621 
622     stat = GdipDisposeImage((GpImage*)bm);
623     expect(Ok, stat);
624     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
625     expect(Ok, stat);
626 
627     /* read x2 */
628     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead, PixelFormat24bppRGB, &bd);
629     expect(Ok, stat);
630     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead, PixelFormat24bppRGB, &bd);
631     expect(WrongState, stat);
632 
633     stat = GdipBitmapUnlockBits(bm, &bd);
634     expect(Ok, stat);
635 
636     stat = GdipDisposeImage((GpImage*)bm);
637     expect(Ok, stat);
638     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
639     expect(Ok, stat);
640 
641     stat = GdipBitmapSetPixel(bm, 2, 3, 0xffff0000);
642     expect(Ok, stat);
643 
644     stat = GdipBitmapSetPixel(bm, 2, 8, 0xffc30000);
645     expect(Ok, stat);
646 
647     /* write, no conversion */
648     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeWrite, PixelFormat24bppRGB, &bd);
649     expect(Ok, stat);
650 
651     if (stat == Ok) {
652         /* all bits are readable, inside the rect or not */
653         expect(0xff, ((BYTE*)bd.Scan0)[2]);
654         expect(0xc3, ((BYTE*)bd.Scan0)[2 + bd.Stride * 5]);
655 
656         stat = GdipBitmapUnlockBits(bm, &bd);
657         expect(Ok, stat);
658     }
659 
660     /* read, conversion */
661     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead, PixelFormat32bppARGB, &bd);
662     expect(Ok, stat);
663 
664     if (stat == Ok) {
665         expect(0xff, ((BYTE*)bd.Scan0)[2]);
666         if (0)
667             /* Areas outside the rectangle appear to be uninitialized */
668             ok(0xc3 != ((BYTE*)bd.Scan0)[2 + bd.Stride * 5], "original image bits are readable\n");
669 
670         ((BYTE*)bd.Scan0)[2] = 0xc3;
671 
672         stat = GdipBitmapUnlockBits(bm, &bd);
673         expect(Ok, stat);
674     }
675 
676     /* writes do not work in read mode if there was a conversion */
677     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
678     expect(Ok, stat);
679     expect(0xffff0000, color);
680 
681     /* read/write, conversion */
682     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead|ImageLockModeWrite, PixelFormat32bppARGB, &bd);
683     expect(Ok, stat);
684 
685     if (stat == Ok) {
686         expect(0xff, ((BYTE*)bd.Scan0)[2]);
687         ((BYTE*)bd.Scan0)[1] = 0x88;
688         if (0)
689             /* Areas outside the rectangle appear to be uninitialized */
690             ok(0xc3 != ((BYTE*)bd.Scan0)[2 + bd.Stride * 5], "original image bits are readable\n");
691 
692         stat = GdipBitmapUnlockBits(bm, &bd);
693         expect(Ok, stat);
694     }
695 
696     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
697     expect(Ok, stat);
698     expect(0xffff8800, color);
699 
700     /* write, conversion */
701     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &bd);
702     expect(Ok, stat);
703 
704     if (stat == Ok) {
705         if (0)
706         {
707             /* This is completely uninitialized. */
708             ok(0xff != ((BYTE*)bd.Scan0)[2], "original image bits are readable\n");
709             ok(0xc3 != ((BYTE*)bd.Scan0)[2 + bd.Stride * 5], "original image bits are readable\n");
710         }
711 
712         /* Initialize the buffer so the unlock doesn't access undefined memory */
713         for (y=0; y<5; y++)
714             memset(((BYTE*)bd.Scan0) + bd.Stride * y, 0, 12);
715 
716         ((BYTE*)bd.Scan0)[0] = 0x12;
717         ((BYTE*)bd.Scan0)[1] = 0x34;
718         ((BYTE*)bd.Scan0)[2] = 0x56;
719 
720         stat = GdipBitmapUnlockBits(bm, &bd);
721         expect(Ok, stat);
722     }
723 
724     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
725     expect(Ok, stat);
726     expect(0xff563412, color);
727 
728     stat = GdipBitmapGetPixel(bm, 2, 8, &color);
729     expect(Ok, stat);
730     expect(0xffc30000, color);
731 
732     stat = GdipDisposeImage((GpImage*)bm);
733     expect(Ok, stat);
734     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
735     expect(Ok, stat);
736 
737     /* write, no modification */
738     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeWrite, PixelFormat24bppRGB, &bd);
739     expect(Ok, stat);
740 
741     if (stat == Ok) {
742         stat = GdipBitmapUnlockBits(bm, &bd);
743         expect(Ok, stat);
744     }
745 
746     /* write, consecutive */
747     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeWrite, PixelFormat24bppRGB, &bd);
748     expect(Ok, stat);
749 
750     if (stat == Ok) {
751         stat = GdipBitmapUnlockBits(bm, &bd);
752         expect(Ok, stat);
753     }
754 
755     stat = GdipDisposeImage((GpImage*)bm);
756     expect(Ok, stat);
757     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
758     expect(Ok, stat);
759 
760     /* write, modify */
761     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeWrite, PixelFormat24bppRGB, &bd);
762     expect(Ok, stat);
763 
764     if (stat == Ok) {
765         if (bd.Scan0)
766             ((char*)bd.Scan0)[2] = 0xff;
767 
768         stat = GdipBitmapUnlockBits(bm, &bd);
769         expect(Ok, stat);
770     }
771 
772     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
773     expect(Ok, stat);
774     expect(0xffff0000, color);
775 
776     stat = GdipDisposeImage((GpImage*)bm);
777     expect(Ok, stat);
778 
779     /* dispose locked */
780     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
781     expect(Ok, stat);
782     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead, PixelFormat24bppRGB, &bd);
783     expect(Ok, stat);
784     stat = GdipDisposeImage((GpImage*)bm);
785     expect(Ok, stat);
786 }
787 
788 static void test_LockBits_UserBuf(void)
789 {
790     GpStatus stat;
791     GpBitmap *bm;
792     GpRect rect;
793     BitmapData bd;
794     const INT WIDTH = 10, HEIGHT = 20;
795     DWORD bits[200];
796     ARGB color;
797 
798     bm = NULL;
799     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat32bppARGB, NULL, &bm);
800     expect(Ok, stat);
801 
802     memset(bits, 0xaa, sizeof(bits));
803 
804     rect.X = 2;
805     rect.Y = 3;
806     rect.Width = 4;
807     rect.Height = 5;
808 
809     bd.Width = 4;
810     bd.Height = 6;
811     bd.Stride = WIDTH * 4;
812     bd.PixelFormat = PixelFormat32bppARGB;
813     bd.Scan0 = &bits[2+3*WIDTH];
814     bd.Reserved = 0xaaaaaaaa;
815 
816     /* read-only */
817     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead|ImageLockModeUserInputBuf, PixelFormat32bppARGB, &bd);
818     expect(Ok, stat);
819 
820     expect(0xaaaaaaaa, bits[0]);
821     expect(0, bits[2+3*WIDTH]);
822 
823     bits[2+3*WIDTH] = 0xdeadbeef;
824 
825     if (stat == Ok) {
826         stat = GdipBitmapUnlockBits(bm, &bd);
827         expect(Ok, stat);
828     }
829 
830     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
831     expect(Ok, stat);
832     expect(0, color);
833 
834     /* write-only */
835     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeWrite|ImageLockModeUserInputBuf, PixelFormat32bppARGB, &bd);
836     expect(Ok, stat);
837 
838     expect(0xdeadbeef, bits[2+3*WIDTH]);
839     bits[2+3*WIDTH] = 0x12345678;
840 
841     if (stat == Ok) {
842         stat = GdipBitmapUnlockBits(bm, &bd);
843         expect(Ok, stat);
844     }
845 
846     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
847     expect(Ok, stat);
848     expect(0x12345678, color);
849 
850     bits[2+3*WIDTH] = 0;
851 
852     /* read/write */
853     stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead|ImageLockModeWrite|ImageLockModeUserInputBuf, PixelFormat32bppARGB, &bd);
854     expect(Ok, stat);
855 
856     expect(0x12345678, bits[2+3*WIDTH]);
857     bits[2+3*WIDTH] = 0xdeadbeef;
858 
859     if (stat == Ok) {
860         stat = GdipBitmapUnlockBits(bm, &bd);
861         expect(Ok, stat);
862     }
863 
864     stat = GdipBitmapGetPixel(bm, 2, 3, &color);
865     expect(Ok, stat);
866     expect(0xdeadbeef, color);
867 
868     stat = GdipDisposeImage((GpImage*)bm);
869     expect(Ok, stat);
870 }
871 
872 struct BITMAPINFOWITHBITFIELDS
873 {
874     BITMAPINFOHEADER bmiHeader;
875     DWORD masks[3];
876 };
877 
878 union BITMAPINFOUNION
879 {
880     BITMAPINFO bi;
881     struct BITMAPINFOWITHBITFIELDS bf;
882 };
883 
884 static void test_GdipCreateBitmapFromHBITMAP(void)
885 {
886     GpBitmap* gpbm = NULL;
887     HBITMAP hbm = NULL;
888     HPALETTE hpal = NULL;
889     GpStatus stat;
890     BYTE buff[1000];
891     LOGPALETTE* LogPal = NULL;
892     REAL width, height;
893     const REAL WIDTH1 = 5;
894     const REAL HEIGHT1 = 15;
895     const REAL WIDTH2 = 10;
896     const REAL HEIGHT2 = 20;
897     HDC hdc;
898     union BITMAPINFOUNION bmi;
899     BYTE *bits;
900     PixelFormat format;
901 
902     stat = GdipCreateBitmapFromHBITMAP(NULL, NULL, NULL);
903     expect(InvalidParameter, stat);
904 
905     hbm = CreateBitmap(WIDTH1, HEIGHT1, 1, 1, NULL);
906     stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, NULL);
907     expect(InvalidParameter, stat);
908 
909     stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm);
910     expect(Ok, stat);
911     expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height));
912     expectf(WIDTH1,  width);
913     expectf(HEIGHT1, height);
914     if (stat == Ok)
915         GdipDisposeImage((GpImage*)gpbm);
916     DeleteObject(hbm);
917 
918     memset(buff, 0, sizeof(buff));
919     hbm = CreateBitmap(WIDTH2, HEIGHT2, 1, 1, &buff);
920     stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm);
921     expect(Ok, stat);
922     /* raw format */
923     expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)gpbm, __LINE__, FALSE);
924 
925     expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height));
926     expectf(WIDTH2,  width);
927     expectf(HEIGHT2, height);
928     if (stat == Ok)
929         GdipDisposeImage((GpImage*)gpbm);
930     DeleteObject(hbm);
931 
932     hdc = CreateCompatibleDC(0);
933     ok(hdc != NULL, "CreateCompatibleDC failed\n");
934     bmi.bi.bmiHeader.biSize = sizeof(bmi.bi.bmiHeader);
935     bmi.bi.bmiHeader.biHeight = HEIGHT1;
936     bmi.bi.bmiHeader.biWidth = WIDTH1;
937     bmi.bi.bmiHeader.biBitCount = 24;
938     bmi.bi.bmiHeader.biPlanes = 1;
939     bmi.bi.bmiHeader.biCompression = BI_RGB;
940     bmi.bi.bmiHeader.biClrUsed = 0;
941 
942     hbm = CreateDIBSection(hdc, &bmi.bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
943     ok(hbm != NULL, "CreateDIBSection failed\n");
944 
945     bits[0] = 0;
946 
947     stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm);
948     expect(Ok, stat);
949     expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height));
950     expectf(WIDTH1,  width);
951     expectf(HEIGHT1, height);
952     if (stat == Ok)
953     {
954         /* test whether writing to the bitmap affects the original */
955         stat = GdipBitmapSetPixel(gpbm, 0, 0, 0xffffffff);
956         expect(Ok, stat);
957 
958         expect(0, bits[0]);
959 
960         GdipDisposeImage((GpImage*)gpbm);
961     }
962 
963     LogPal = GdipAlloc(sizeof(LOGPALETTE));
964     ok(LogPal != NULL, "unable to allocate LOGPALETTE\n");
965     LogPal->palVersion = 0x300;
966     LogPal->palNumEntries = 1;
967     hpal = CreatePalette(LogPal);
968     ok(hpal != NULL, "CreatePalette failed\n");
969     GdipFree(LogPal);
970 
971     stat = GdipCreateBitmapFromHBITMAP(hbm, hpal, &gpbm);
972     expect(Ok, stat);
973 
974     if (stat == Ok)
975         GdipDisposeImage((GpImage*)gpbm);
976 
977     DeleteObject(hpal);
978     DeleteObject(hbm);
979 
980     /* 16-bit 555 dib, rgb */
981     bmi.bi.bmiHeader.biBitCount = 16;
982     bmi.bi.bmiHeader.biCompression = BI_RGB;
983 
984     hbm = CreateDIBSection(hdc, &bmi.bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
985     ok(hbm != NULL, "CreateDIBSection failed\n");
986 
987     bits[0] = 0;
988 
989     stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm);
990     expect(Ok, stat);
991 
992     if (stat == Ok)
993     {
994         stat = GdipGetImageDimension((GpImage*) gpbm, &width, &height);
995         expect(Ok, stat);
996         expectf(WIDTH1,  width);
997         expectf(HEIGHT1, height);
998 
999         stat = GdipGetImagePixelFormat((GpImage*) gpbm, &format);
1000         expect(Ok, stat);
1001         expect(PixelFormat16bppRGB555, format);
1002 
1003         GdipDisposeImage((GpImage*)gpbm);
1004     }
1005     DeleteObject(hbm);
1006 
1007     /* 16-bit 555 dib, with bitfields */
1008     bmi.bi.bmiHeader.biSize = sizeof(bmi);
1009     bmi.bi.bmiHeader.biCompression = BI_BITFIELDS;
1010     bmi.bf.masks[0] = 0x7c00;
1011     bmi.bf.masks[1] = 0x3e0;
1012     bmi.bf.masks[2] = 0x1f;
1013 
1014     hbm = CreateDIBSection(hdc, &bmi.bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1015     ok(hbm != NULL, "CreateDIBSection failed\n");
1016 
1017     bits[0] = 0;
1018 
1019     stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm);
1020     expect(Ok, stat);
1021 
1022     if (stat == Ok)
1023     {
1024         stat = GdipGetImageDimension((GpImage*) gpbm, &width, &height);
1025         expect(Ok, stat);
1026         expectf(WIDTH1,  width);
1027         expectf(HEIGHT1, height);
1028 
1029         stat = GdipGetImagePixelFormat((GpImage*) gpbm, &format);
1030         expect(Ok, stat);
1031         expect(PixelFormat16bppRGB555, format);
1032 
1033         GdipDisposeImage((GpImage*)gpbm);
1034     }
1035     DeleteObject(hbm);
1036 
1037     /* 16-bit 565 dib, with bitfields */
1038     bmi.bf.masks[0] = 0xf800;
1039     bmi.bf.masks[1] = 0x7e0;
1040     bmi.bf.masks[2] = 0x1f;
1041 
1042     hbm = CreateDIBSection(hdc, &bmi.bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1043     ok(hbm != NULL, "CreateDIBSection failed\n");
1044 
1045     bits[0] = 0;
1046 
1047     stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm);
1048     expect(Ok, stat);
1049 
1050     if (stat == Ok)
1051     {
1052         stat = GdipGetImageDimension((GpImage*) gpbm, &width, &height);
1053         expect(Ok, stat);
1054         expectf(WIDTH1,  width);
1055         expectf(HEIGHT1, height);
1056 
1057         stat = GdipGetImagePixelFormat((GpImage*) gpbm, &format);
1058         expect(Ok, stat);
1059         expect(PixelFormat16bppRGB565, format);
1060 
1061         GdipDisposeImage((GpImage*)gpbm);
1062     }
1063     DeleteObject(hbm);
1064 
1065     DeleteDC(hdc);
1066 }
1067 
1068 static void test_GdipGetImageFlags(void)
1069 {
1070     GpImage *img;
1071     GpStatus stat;
1072     UINT flags;
1073 
1074     img = (GpImage*)0xdeadbeef;
1075 
1076     stat = GdipGetImageFlags(NULL, NULL);
1077     expect(InvalidParameter, stat);
1078 
1079     stat = GdipGetImageFlags(NULL, &flags);
1080     expect(InvalidParameter, stat);
1081 
1082     stat = GdipGetImageFlags(img, NULL);
1083     expect(InvalidParameter, stat);
1084 
1085     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat1bppIndexed, NULL, (GpBitmap**)&img);
1086     expect(Ok, stat);
1087     stat = GdipGetImageFlags(img, &flags);
1088     expect(Ok, stat);
1089     expect(ImageFlagsHasAlpha, flags);
1090     GdipDisposeImage(img);
1091 
1092     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat4bppIndexed, NULL, (GpBitmap**)&img);
1093     expect(Ok, stat);
1094     stat = GdipGetImageFlags(img, &flags);
1095     expect(Ok, stat);
1096     expect(ImageFlagsHasAlpha, flags);
1097     GdipDisposeImage(img);
1098 
1099     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat8bppIndexed, NULL, (GpBitmap**)&img);
1100     expect(Ok, stat);
1101     stat = GdipGetImageFlags(img, &flags);
1102     expect(Ok, stat);
1103     expect(ImageFlagsHasAlpha, flags);
1104     GdipDisposeImage(img);
1105 
1106     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat16bppGrayScale, NULL, (GpBitmap**)&img);
1107     expect(Ok, stat);
1108     stat = GdipGetImageFlags(img, &flags);
1109     expect(Ok, stat);
1110     expect(ImageFlagsNone, flags);
1111     GdipDisposeImage(img);
1112 
1113     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat16bppRGB555, NULL, (GpBitmap**)&img);
1114     expect(Ok, stat);
1115     stat = GdipGetImageFlags(img, &flags);
1116     expect(Ok, stat);
1117     expect(ImageFlagsNone, flags);
1118     GdipDisposeImage(img);
1119 
1120     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat16bppRGB565, NULL, (GpBitmap**)&img);
1121     expect(Ok, stat);
1122     stat = GdipGetImageFlags(img, &flags);
1123     expect(Ok, stat);
1124     expect(ImageFlagsNone, flags);
1125     GdipDisposeImage(img);
1126 
1127     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat16bppARGB1555, NULL, (GpBitmap**)&img);
1128     expect(Ok, stat);
1129     stat = GdipGetImageFlags(img, &flags);
1130     expect(Ok, stat);
1131     expect(ImageFlagsHasAlpha, flags);
1132     GdipDisposeImage(img);
1133 
1134     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat24bppRGB, NULL, (GpBitmap**)&img);
1135     expect(Ok, stat);
1136     stat = GdipGetImageFlags(img, &flags);
1137     expect(Ok, stat);
1138     expect(ImageFlagsNone, flags);
1139     GdipDisposeImage(img);
1140 
1141     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat32bppRGB, NULL, (GpBitmap**)&img);
1142     expect(Ok, stat);
1143     stat = GdipGetImageFlags(img, &flags);
1144     expect(Ok, stat);
1145     expect(ImageFlagsNone, flags);
1146     GdipDisposeImage(img);
1147 
1148     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat32bppARGB, NULL, (GpBitmap**)&img);
1149     expect(Ok, stat);
1150     stat = GdipGetImageFlags(img, &flags);
1151     expect(Ok, stat);
1152     expect(ImageFlagsHasAlpha, flags);
1153     GdipDisposeImage(img);
1154 
1155     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat32bppPARGB, NULL, (GpBitmap**)&img);
1156     expect(Ok, stat);
1157     stat = GdipGetImageFlags(img, &flags);
1158     expect(Ok, stat);
1159     expect(ImageFlagsHasAlpha, flags);
1160     GdipDisposeImage(img);
1161 
1162     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat48bppRGB, NULL, (GpBitmap**)&img);
1163     expect(Ok, stat);
1164     if (stat == Ok)
1165     {
1166         stat = GdipGetImageFlags(img, &flags);
1167         expect(Ok, stat);
1168         expect(ImageFlagsNone, flags);
1169         GdipDisposeImage(img);
1170     }
1171 
1172     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat64bppARGB, NULL, (GpBitmap**)&img);
1173     expect(Ok, stat);
1174     if (stat == Ok)
1175     {
1176         expect(Ok, stat);
1177         stat = GdipGetImageFlags(img, &flags);
1178         expect(Ok, stat);
1179         expect(ImageFlagsHasAlpha, flags);
1180         GdipDisposeImage(img);
1181     }
1182 
1183     stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat64bppPARGB, NULL, (GpBitmap**)&img);
1184     expect(Ok, stat);
1185     if (stat == Ok)
1186     {
1187         expect(Ok, stat);
1188         stat = GdipGetImageFlags(img, &flags);
1189         expect(Ok, stat);
1190         expect(ImageFlagsHasAlpha, flags);
1191         GdipDisposeImage(img);
1192     }
1193 }
1194 
1195 static void test_GdipCloneImage(void)
1196 {
1197     GpStatus stat;
1198     GpRectF rectF;
1199     GpUnit unit;
1200     GpBitmap *bm;
1201     GpImage *image_src, *image_dest = NULL;
1202     const INT WIDTH = 10, HEIGHT = 20;
1203 
1204     /* Create an image, clone it, delete the original, make sure the copy works */
1205     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
1206     expect(Ok, stat);
1207     expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)bm, __LINE__, FALSE);
1208 
1209     image_src = ((GpImage*)bm);
1210     stat = GdipCloneImage(image_src, &image_dest);
1211     expect(Ok, stat);
1212     expect_rawformat(&ImageFormatMemoryBMP, image_dest, __LINE__, FALSE);
1213 
1214     stat = GdipDisposeImage((GpImage*)bm);
1215     expect(Ok, stat);
1216     stat = GdipGetImageBounds(image_dest, &rectF, &unit);
1217     expect(Ok, stat);
1218 
1219     /* Treat FP values carefully */
1220     expectf((REAL)WIDTH, rectF.Width);
1221     expectf((REAL)HEIGHT, rectF.Height);
1222 
1223     stat = GdipDisposeImage(image_dest);
1224     expect(Ok, stat);
1225 }
1226 
1227 static void test_testcontrol(void)
1228 {
1229     GpStatus stat;
1230     DWORD param;
1231 
1232     param = 0;
1233     stat = GdipTestControl(TestControlGetBuildNumber, &param);
1234     expect(Ok, stat);
1235     ok(param != 0, "Build number expected, got %u\n", param);
1236 }
1237 
1238 static void test_fromhicon(void)
1239 {
1240     static const BYTE bmp_bits[1024];
1241     HBITMAP hbmMask, hbmColor;
1242     ICONINFO info;
1243     HICON hIcon;
1244     GpStatus stat;
1245     GpBitmap *bitmap = NULL;
1246     UINT dim;
1247     ImageType type;
1248     PixelFormat format;
1249 
1250     /* NULL */
1251     stat = GdipCreateBitmapFromHICON(NULL, NULL);
1252     expect(InvalidParameter, stat);
1253     stat = GdipCreateBitmapFromHICON(NULL, &bitmap);
1254     expect(InvalidParameter, stat);
1255 
1256     /* color icon 1 bit */
1257     hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits);
1258     ok(hbmMask != 0, "CreateBitmap failed\n");
1259     hbmColor = CreateBitmap(16, 16, 1, 1, bmp_bits);
1260     ok(hbmColor != 0, "CreateBitmap failed\n");
1261     info.fIcon = TRUE;
1262     info.xHotspot = 8;
1263     info.yHotspot = 8;
1264     info.hbmMask = hbmMask;
1265     info.hbmColor = hbmColor;
1266     hIcon = CreateIconIndirect(&info);
1267     ok(hIcon != 0, "CreateIconIndirect failed\n");
1268     DeleteObject(hbmMask);
1269     DeleteObject(hbmColor);
1270 
1271     stat = GdipCreateBitmapFromHICON(hIcon, &bitmap);
1272     ok(stat == Ok ||
1273        broken(stat == InvalidParameter), /* Win98 */
1274        "Expected Ok, got %.8x\n", stat);
1275     if(stat == Ok){
1276        /* check attributes */
1277        stat = GdipGetImageHeight((GpImage*)bitmap, &dim);
1278        expect(Ok, stat);
1279        expect(16, dim);
1280        stat = GdipGetImageWidth((GpImage*)bitmap, &dim);
1281        expect(Ok, stat);
1282        expect(16, dim);
1283        stat = GdipGetImageType((GpImage*)bitmap, &type);
1284        expect(Ok, stat);
1285        expect(ImageTypeBitmap, type);
1286        stat = GdipGetImagePixelFormat((GpImage*)bitmap, &format);
1287        expect(Ok, stat);
1288        expect(PixelFormat32bppARGB, format);
1289        /* raw format */
1290        expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)bitmap, __LINE__, FALSE);
1291        GdipDisposeImage((GpImage*)bitmap);
1292     }
1293     DestroyIcon(hIcon);
1294 
1295     /* color icon 8 bpp */
1296     hbmMask = CreateBitmap(16, 16, 1, 8, bmp_bits);
1297     ok(hbmMask != 0, "CreateBitmap failed\n");
1298     hbmColor = CreateBitmap(16, 16, 1, 8, bmp_bits);
1299     ok(hbmColor != 0, "CreateBitmap failed\n");
1300     info.fIcon = TRUE;
1301     info.xHotspot = 8;
1302     info.yHotspot = 8;
1303     info.hbmMask = hbmMask;
1304     info.hbmColor = hbmColor;
1305     hIcon = CreateIconIndirect(&info);
1306     ok(hIcon != 0, "CreateIconIndirect failed\n");
1307     DeleteObject(hbmMask);
1308     DeleteObject(hbmColor);
1309 
1310     stat = GdipCreateBitmapFromHICON(hIcon, &bitmap);
1311     expect(Ok, stat);
1312     if(stat == Ok){
1313         /* check attributes */
1314         stat = GdipGetImageHeight((GpImage*)bitmap, &dim);
1315         expect(Ok, stat);
1316         expect(16, dim);
1317         stat = GdipGetImageWidth((GpImage*)bitmap, &dim);
1318         expect(Ok, stat);
1319         expect(16, dim);
1320         stat = GdipGetImageType((GpImage*)bitmap, &type);
1321         expect(Ok, stat);
1322         expect(ImageTypeBitmap, type);
1323         stat = GdipGetImagePixelFormat((GpImage*)bitmap, &format);
1324 	expect(Ok, stat);
1325         expect(PixelFormat32bppARGB, format);
1326         /* raw format */
1327         expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)bitmap, __LINE__, FALSE);
1328         GdipDisposeImage((GpImage*)bitmap);
1329     }
1330     DestroyIcon(hIcon);
1331 }
1332 
1333 /* 1x1 pixel png */
1334 static const unsigned char pngimage[285] = {
1335 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
1336 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
1337 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
1338 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
1339 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
1340 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
1341 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
1342 };
1343 /* 1x1 pixel gif */
1344 static const unsigned char gifimage[35] = {
1345 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
1346 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
1347 0x01,0x00,0x3b
1348 };
1349 /* 1x1 pixel transparent gif */
1350 static const unsigned char transparentgif[] = {
1351 0x47,0x49,0x46,0x38,0x39,0x61,0x01,0x00,0x01,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,
1352 0x00,0x00,0x00,0x21,0xf9,0x04,0x01,0x00,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,
1353 0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,0x01,0x00,0x3b
1354 };
1355 /* 1x1 pixel bmp */
1356 static const unsigned char bmpimage[66] = {
1357 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
1358 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
1359 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
1360 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
1361 0x00,0x00
1362 };
1363 /* 1x1 pixel jpg */
1364 static const unsigned char jpgimage[285] = {
1365 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
1366 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
1367 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
1368 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
1369 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
1370 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
1371 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
1372 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
1373 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
1374 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
1375 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
1376 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1377 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
1378 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
1379 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1380 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
1381 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
1382 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
1383 };
1384 /* 1x1 pixel tiff */
1385 static const unsigned char tiffimage[] = {
1386 0x49,0x49,0x2a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0xfe,0x00,
1387 0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x01,0x00,
1388 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,
1389 0x00,0x00,0x02,0x01,0x03,0x00,0x03,0x00,0x00,0x00,0xd2,0x00,0x00,0x00,0x03,0x01,
1390 0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x01,0x03,0x00,0x01,0x00,
1391 0x00,0x00,0x02,0x00,0x00,0x00,0x0d,0x01,0x02,0x00,0x1b,0x00,0x00,0x00,0xd8,0x00,
1392 0x00,0x00,0x11,0x01,0x04,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x12,0x01,
1393 0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x15,0x01,0x03,0x00,0x01,0x00,
1394 0x00,0x00,0x03,0x00,0x00,0x00,0x16,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x40,0x00,
1395 0x00,0x00,0x17,0x01,0x04,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x1a,0x01,
1396 0x05,0x00,0x01,0x00,0x00,0x00,0xf4,0x00,0x00,0x00,0x1b,0x01,0x05,0x00,0x01,0x00,
1397 0x00,0x00,0xfc,0x00,0x00,0x00,0x1c,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,
1398 0x00,0x00,0x28,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
1399 0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x6d,0x65,
1400 0x68,0x2f,0x44,0x65,0x73,0x6b,0x74,0x6f,0x70,0x2f,0x74,0x65,0x73,0x74,0x2e,0x74,
1401 0x69,0x66,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,
1402 0x00,0x00,0x00,0x01
1403 };
1404 /* 320x320 twip wmf */
1405 static const unsigned char wmfimage[180] = {
1406 0xd7,0xcd,0xc6,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x40,0x01,0xa0,0x05,
1407 0x00,0x00,0x00,0x00,0xb1,0x52,0x01,0x00,0x09,0x00,0x00,0x03,0x4f,0x00,0x00,0x00,
1408 0x0f,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0b,0x02,0x00,0x00,
1409 0x00,0x00,0x05,0x00,0x00,0x00,0x0c,0x02,0x40,0x01,0x40,0x01,0x04,0x00,0x00,0x00,
1410 0x02,0x01,0x01,0x00,0x04,0x00,0x00,0x00,0x04,0x01,0x0d,0x00,0x08,0x00,0x00,0x00,
1411 0xfa,0x02,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
1412 0x2d,0x01,0x00,0x00,0x07,0x00,0x00,0x00,0xfc,0x02,0x01,0x00,0x00,0x00,0x00,0x00,
1413 0x00,0x00,0x04,0x00,0x00,0x00,0x2d,0x01,0x01,0x00,0x07,0x00,0x00,0x00,0xfc,0x02,
1414 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x2d,0x01,0x02,0x00,
1415 0x07,0x00,0x00,0x00,0x1b,0x04,0x40,0x01,0x40,0x01,0x00,0x00,0x00,0x00,0x04,0x00,
1416 0x00,0x00,0xf0,0x01,0x00,0x00,0x04,0x00,0x00,0x00,0xf0,0x01,0x01,0x00,0x03,0x00,
1417 0x00,0x00,0x00,0x00
1418 };
1419 static void test_getrawformat(void)
1420 {
1421     test_bufferrawformat((void*)pngimage, sizeof(pngimage), &ImageFormatPNG,  __LINE__, FALSE);
1422     test_bufferrawformat((void*)gifimage, sizeof(gifimage), &ImageFormatGIF,  __LINE__, FALSE);
1423     test_bufferrawformat((void*)bmpimage, sizeof(bmpimage), &ImageFormatBMP,  __LINE__, FALSE);
1424     test_bufferrawformat((void*)jpgimage, sizeof(jpgimage), &ImageFormatJPEG, __LINE__, FALSE);
1425     test_bufferrawformat((void*)tiffimage, sizeof(tiffimage), &ImageFormatTIFF, __LINE__, FALSE);
1426     test_bufferrawformat((void*)wmfimage, sizeof(wmfimage), &ImageFormatWMF, __LINE__, FALSE);
1427 }
1428 
1429 static void test_loadwmf(void)
1430 {
1431     LPSTREAM stream;
1432     HGLOBAL  hglob;
1433     LPBYTE   data;
1434     HRESULT  hres;
1435     GpStatus stat;
1436     GpImage *img;
1437     GpRectF bounds;
1438     GpUnit unit;
1439     REAL res = 12345.0;
1440     MetafileHeader header;
1441 
1442     hglob = GlobalAlloc (0, sizeof(wmfimage));
1443     data = GlobalLock (hglob);
1444     memcpy(data, wmfimage, sizeof(wmfimage));
1445     GlobalUnlock(hglob); data = NULL;
1446 
1447     hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
1448     ok(hres == S_OK, "Failed to create a stream\n");
1449     if(hres != S_OK) return;
1450 
1451     stat = GdipLoadImageFromStream(stream, &img);
1452     ok(stat == Ok, "Failed to create a Bitmap\n");
1453     if(stat != Ok){
1454         IStream_Release(stream);
1455         return;
1456     }
1457 
1458     IStream_Release(stream);
1459 
1460     stat = GdipGetImageBounds(img, &bounds, &unit);
1461     expect(Ok, stat);
1462     expect(UnitPixel, unit);
1463     expectf(0.0, bounds.X);
1464     expectf(0.0, bounds.Y);
1465     expectf(320.0, bounds.Width);
1466     expectf(320.0, bounds.Height);
1467 
1468     stat = GdipGetImageHorizontalResolution(img, &res);
1469     expect(Ok, stat);
1470     expectf(1440.0, res);
1471 
1472     stat = GdipGetImageVerticalResolution(img, &res);
1473     expect(Ok, stat);
1474     expectf(1440.0, res);
1475 
1476     memset(&header, 0, sizeof(header));
1477     stat = GdipGetMetafileHeaderFromMetafile((GpMetafile*)img, &header);
1478     expect(Ok, stat);
1479     if (stat == Ok)
1480     {
1481         expect(MetafileTypeWmfPlaceable, header.Type);
1482         todo_wine expect(sizeof(wmfimage)-sizeof(WmfPlaceableFileHeader), header.Size);
1483         todo_wine expect(0x300, header.Version);
1484         expect(0, header.EmfPlusFlags);
1485         expectf(1440.0, header.DpiX);
1486         expectf(1440.0, header.DpiY);
1487         expect(0, header.X);
1488         expect(0, header.Y);
1489         expect(320, header.Width);
1490         expect(320, header.Height);
1491         expect(1, U(header).WmfHeader.mtType);
1492         expect(0, header.EmfPlusHeaderSize);
1493         expect(0, header.LogicalDpiX);
1494         expect(0, header.LogicalDpiY);
1495     }
1496 
1497     GdipDisposeImage(img);
1498 }
1499 
1500 static void test_createfromwmf(void)
1501 {
1502     HMETAFILE hwmf;
1503     GpImage *img;
1504     GpStatus stat;
1505     GpRectF bounds;
1506     GpUnit unit;
1507     REAL res = 12345.0;
1508     MetafileHeader header;
1509 
1510     hwmf = SetMetaFileBitsEx(sizeof(wmfimage)-sizeof(WmfPlaceableFileHeader),
1511         wmfimage+sizeof(WmfPlaceableFileHeader));
1512     ok(hwmf != 0, "SetMetaFileBitsEx failed\n");
1513 
1514     stat = GdipCreateMetafileFromWmf(hwmf, TRUE,
1515         (WmfPlaceableFileHeader*)wmfimage, (GpMetafile**)&img);
1516     expect(Ok, stat);
1517 
1518     stat = GdipGetImageBounds(img, &bounds, &unit);
1519     expect(Ok, stat);
1520     expect(UnitPixel, unit);
1521     expectf(0.0, bounds.X);
1522     expectf(0.0, bounds.Y);
1523     expectf(320.0, bounds.Width);
1524     expectf(320.0, bounds.Height);
1525 
1526     stat = GdipGetImageHorizontalResolution(img, &res);
1527     expect(Ok, stat);
1528     expectf(1440.0, res);
1529 
1530     stat = GdipGetImageVerticalResolution(img, &res);
1531     expect(Ok, stat);
1532     expectf(1440.0, res);
1533 
1534     memset(&header, 0, sizeof(header));
1535     stat = GdipGetMetafileHeaderFromMetafile((GpMetafile*)img, &header);
1536     expect(Ok, stat);
1537     if (stat == Ok)
1538     {
1539         expect(MetafileTypeWmfPlaceable, header.Type);
1540         todo_wine expect(sizeof(wmfimage)-sizeof(WmfPlaceableFileHeader), header.Size);
1541         todo_wine expect(0x300, header.Version);
1542         expect(0, header.EmfPlusFlags);
1543         expectf(1440.0, header.DpiX);
1544         expectf(1440.0, header.DpiY);
1545         expect(0, header.X);
1546         expect(0, header.Y);
1547         expect(320, header.Width);
1548         expect(320, header.Height);
1549         expect(1, U(header).WmfHeader.mtType);
1550         expect(0, header.EmfPlusHeaderSize);
1551         expect(0, header.LogicalDpiX);
1552         expect(0, header.LogicalDpiY);
1553     }
1554 
1555     GdipDisposeImage(img);
1556 }
1557 
1558 static void test_createfromwmf_noplaceable(void)
1559 {
1560     HMETAFILE hwmf;
1561     GpImage *img;
1562     GpStatus stat;
1563 
1564     hwmf = SetMetaFileBitsEx(sizeof(wmfimage)-sizeof(WmfPlaceableFileHeader),
1565         wmfimage+sizeof(WmfPlaceableFileHeader));
1566     ok(hwmf != 0, "SetMetaFileBitsEx failed\n");
1567 
1568     stat = GdipCreateMetafileFromWmf(hwmf, TRUE, NULL, (GpMetafile**)&img);
1569     expect(Ok, stat);
1570 
1571     GdipDisposeImage(img);
1572 }
1573 
1574 static void test_resolution(void)
1575 {
1576     GpStatus stat;
1577     GpBitmap *bitmap;
1578     GpGraphics *graphics;
1579     REAL res=-1.0;
1580     HDC screendc;
1581     int screenxres, screenyres;
1582 
1583     /* create Bitmap */
1584     stat = GdipCreateBitmapFromScan0(1, 1, 32, PixelFormat24bppRGB, NULL, &bitmap);
1585     expect(Ok, stat);
1586 
1587     /* test invalid values */
1588     stat = GdipGetImageHorizontalResolution(NULL, &res);
1589     expect(InvalidParameter, stat);
1590 
1591     stat = GdipGetImageHorizontalResolution((GpImage*)bitmap, NULL);
1592     expect(InvalidParameter, stat);
1593 
1594     stat = GdipGetImageVerticalResolution(NULL, &res);
1595     expect(InvalidParameter, stat);
1596 
1597     stat = GdipGetImageVerticalResolution((GpImage*)bitmap, NULL);
1598     expect(InvalidParameter, stat);
1599 
1600     stat = GdipBitmapSetResolution(NULL, 96.0, 96.0);
1601     expect(InvalidParameter, stat);
1602 
1603     stat = GdipBitmapSetResolution(bitmap, 0.0, 0.0);
1604     expect(InvalidParameter, stat);
1605 
1606     /* defaults to screen resolution */
1607     screendc = GetDC(0);
1608 
1609     screenxres = GetDeviceCaps(screendc, LOGPIXELSX);
1610     screenyres = GetDeviceCaps(screendc, LOGPIXELSY);
1611 
1612     ReleaseDC(0, screendc);
1613 
1614     stat = GdipGetImageHorizontalResolution((GpImage*)bitmap, &res);
1615     expect(Ok, stat);
1616     expectf((REAL)screenxres, res);
1617 
1618     stat = GdipGetImageVerticalResolution((GpImage*)bitmap, &res);
1619     expect(Ok, stat);
1620     expectf((REAL)screenyres, res);
1621 
1622     stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
1623     expect(Ok, stat);
1624     stat = GdipGetDpiX(graphics, &res);
1625     expect(Ok, stat);
1626     expectf((REAL)screenxres, res);
1627     stat = GdipGetDpiY(graphics, &res);
1628     expect(Ok, stat);
1629     expectf((REAL)screenyres, res);
1630 
1631     /* test changing the resolution */
1632     stat = GdipBitmapSetResolution(bitmap, screenxres*2.0, screenyres*3.0);
1633     expect(Ok, stat);
1634 
1635     stat = GdipGetImageHorizontalResolution((GpImage*)bitmap, &res);
1636     expect(Ok, stat);
1637     expectf(screenxres*2.0, res);
1638 
1639     stat = GdipGetImageVerticalResolution((GpImage*)bitmap, &res);
1640     expect(Ok, stat);
1641     expectf(screenyres*3.0, res);
1642 
1643     stat = GdipGetDpiX(graphics, &res);
1644     expect(Ok, stat);
1645     expectf((REAL)screenxres, res);
1646     stat = GdipGetDpiY(graphics, &res);
1647     expect(Ok, stat);
1648     expectf((REAL)screenyres, res);
1649 
1650     stat = GdipDeleteGraphics(graphics);
1651     expect(Ok, stat);
1652 
1653     stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
1654     expect(Ok, stat);
1655     stat = GdipGetDpiX(graphics, &res);
1656     expect(Ok, stat);
1657     expectf(screenxres*2.0, res);
1658     stat = GdipGetDpiY(graphics, &res);
1659     expect(Ok, stat);
1660     expectf(screenyres*3.0, res);
1661     stat = GdipDeleteGraphics(graphics);
1662     expect(Ok, stat);
1663 
1664     stat = GdipDisposeImage((GpImage*)bitmap);
1665     expect(Ok, stat);
1666 }
1667 
1668 static void test_createhbitmap(void)
1669 {
1670     GpStatus stat;
1671     GpBitmap *bitmap;
1672     HBITMAP hbitmap, oldhbitmap;
1673     BITMAP bm;
1674     int ret;
1675     HDC hdc;
1676     COLORREF pixel;
1677     BYTE bits[640];
1678     BitmapData lockeddata;
1679 
1680     memset(bits, 0x68, 640);
1681 
1682     /* create Bitmap */
1683     stat = GdipCreateBitmapFromScan0(10, 20, 32, PixelFormat24bppRGB, bits, &bitmap);
1684     expect(Ok, stat);
1685 
1686     /* test NULL values */
1687     stat = GdipCreateHBITMAPFromBitmap(NULL, &hbitmap, 0);
1688     expect(InvalidParameter, stat);
1689 
1690     stat = GdipCreateHBITMAPFromBitmap(bitmap, NULL, 0);
1691     expect(InvalidParameter, stat);
1692 
1693     /* create HBITMAP */
1694     stat = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0);
1695     expect(Ok, stat);
1696 
1697     if (stat == Ok)
1698     {
1699         ret = GetObjectA(hbitmap, sizeof(BITMAP), &bm);
1700         expect(sizeof(BITMAP), ret);
1701 
1702         expect(0, bm.bmType);
1703         expect(10, bm.bmWidth);
1704         expect(20, bm.bmHeight);
1705         expect(40, bm.bmWidthBytes);
1706         expect(1, bm.bmPlanes);
1707         expect(32, bm.bmBitsPixel);
1708         ok(bm.bmBits != NULL, "got DDB, expected DIB\n");
1709 
1710         if (bm.bmBits)
1711         {
1712             DWORD val = *(DWORD*)bm.bmBits;
1713             ok(val == 0xff686868, "got %x, expected 0xff686868\n", val);
1714         }
1715 
1716         hdc = CreateCompatibleDC(NULL);
1717 
1718         oldhbitmap = SelectObject(hdc, hbitmap);
1719         pixel = GetPixel(hdc, 5, 5);
1720         SelectObject(hdc, oldhbitmap);
1721 
1722         DeleteDC(hdc);
1723 
1724         expect(0x686868, pixel);
1725 
1726         DeleteObject(hbitmap);
1727     }
1728 
1729     stat = GdipDisposeImage((GpImage*)bitmap);
1730     expect(Ok, stat);
1731 
1732     /* make (1,0) have no alpha and (2,0) a different blue value. */
1733     bits[7] = 0x00;
1734     bits[8] = 0x40;
1735 
1736     /* create alpha Bitmap */
1737     stat = GdipCreateBitmapFromScan0(8, 20, 32, PixelFormat32bppARGB, bits, &bitmap);
1738     expect(Ok, stat);
1739 
1740     /* create HBITMAP */
1741     stat = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0);
1742     expect(Ok, stat);
1743 
1744     if (stat == Ok)
1745     {
1746         ret = GetObjectA(hbitmap, sizeof(BITMAP), &bm);
1747         expect(sizeof(BITMAP), ret);
1748 
1749         expect(0, bm.bmType);
1750         expect(8, bm.bmWidth);
1751         expect(20, bm.bmHeight);
1752         expect(32, bm.bmWidthBytes);
1753         expect(1, bm.bmPlanes);
1754         expect(32, bm.bmBitsPixel);
1755         ok(bm.bmBits != NULL, "got DDB, expected DIB\n");
1756 
1757         if (bm.bmBits)
1758         {
1759             DWORD val = *(DWORD*)bm.bmBits;
1760             ok(val == 0x682a2a2a, "got %x, expected 0x682a2a2a\n", val);
1761             val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1);
1762             ok(val == 0x0, "got %x, expected 0x682a2a2a\n", val);
1763         }
1764 
1765         hdc = CreateCompatibleDC(NULL);
1766 
1767         oldhbitmap = SelectObject(hdc, hbitmap);
1768         pixel = GetPixel(hdc, 5, 5);
1769         expect(0x2a2a2a, pixel);
1770         pixel = GetPixel(hdc, 1, 0);
1771         expect(0x0, pixel);
1772 
1773         SelectObject(hdc, oldhbitmap);
1774 
1775         DeleteDC(hdc);
1776 
1777 
1778         DeleteObject(hbitmap);
1779     }
1780 
1781     /* create HBITMAP with bkgnd colour */
1782     stat = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0xff00ff);
1783     expect(Ok, stat);
1784 
1785     if (stat == Ok)
1786     {
1787         ret = GetObjectA(hbitmap, sizeof(BITMAP), &bm);
1788         expect(sizeof(BITMAP), ret);
1789 
1790         expect(0, bm.bmType);
1791         expect(8, bm.bmWidth);
1792         expect(20, bm.bmHeight);
1793         expect(32, bm.bmWidthBytes);
1794         expect(1, bm.bmPlanes);
1795         expect(32, bm.bmBitsPixel);
1796         ok(bm.bmBits != NULL, "got DDB, expected DIB\n");
1797 
1798         if (bm.bmBits)
1799         {
1800             DWORD val = *(DWORD*)bm.bmBits;
1801             ok(val == 0x68c12ac1, "got %x, expected 0x682a2a2a\n", val);
1802             val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1);
1803             ok(val == 0xff00ff, "got %x, expected 0x682a2a2a\n", val);
1804         }
1805 
1806         hdc = CreateCompatibleDC(NULL);
1807 
1808         oldhbitmap = SelectObject(hdc, hbitmap);
1809         pixel = GetPixel(hdc, 5, 5);
1810         expect(0xc12ac1, pixel);
1811         pixel = GetPixel(hdc, 1, 0);
1812         expect(0xff00ff, pixel);
1813         pixel = GetPixel(hdc, 2, 0);
1814         expect(0xb12ac1, pixel);
1815 
1816         SelectObject(hdc, oldhbitmap);
1817         DeleteDC(hdc);
1818         DeleteObject(hbitmap);
1819     }
1820 
1821     /* create HBITMAP with bkgnd colour with alpha and show it behaves with no alpha. */
1822     stat = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0x80ff00ff);
1823     expect(Ok, stat);
1824 
1825     if (stat == Ok)
1826     {
1827         ret = GetObjectA(hbitmap, sizeof(BITMAP), &bm);
1828         expect(sizeof(BITMAP), ret);
1829 
1830         expect(0, bm.bmType);
1831         expect(8, bm.bmWidth);
1832         expect(20, bm.bmHeight);
1833         expect(32, bm.bmWidthBytes);
1834         expect(1, bm.bmPlanes);
1835         expect(32, bm.bmBitsPixel);
1836         ok(bm.bmBits != NULL, "got DDB, expected DIB\n");
1837 
1838         if (bm.bmBits)
1839         {
1840             DWORD val = *(DWORD*)bm.bmBits;
1841             ok(val == 0x68c12ac1, "got %x, expected 0x682a2a2a\n", val);
1842             val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1);
1843             ok(val == 0xff00ff, "got %x, expected 0x682a2a2a\n", val);
1844         }
1845 
1846         hdc = CreateCompatibleDC(NULL);
1847 
1848         oldhbitmap = SelectObject(hdc, hbitmap);
1849         pixel = GetPixel(hdc, 5, 5);
1850         expect(0xc12ac1, pixel);
1851         pixel = GetPixel(hdc, 1, 0);
1852         expect(0xff00ff, pixel);
1853         pixel = GetPixel(hdc, 2, 0);
1854         expect(0xb12ac1, pixel);
1855 
1856         SelectObject(hdc, oldhbitmap);
1857         DeleteDC(hdc);
1858         DeleteObject(hbitmap);
1859     }
1860 
1861     stat = GdipDisposeImage((GpImage*)bitmap);
1862     expect(Ok, stat);
1863 
1864     /* create HBITMAP from locked data */
1865     memset(bits, 0x68, 640);
1866     stat = GdipCreateBitmapFromScan0(10, 20, 32, PixelFormat24bppRGB, bits, &bitmap);
1867     expect(Ok, stat);
1868 
1869     memset(&lockeddata, 0, sizeof(lockeddata));
1870     stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead | ImageLockModeWrite,
1871             PixelFormat32bppRGB, &lockeddata);
1872     expect(Ok, stat);
1873     ((DWORD*)lockeddata.Scan0)[0] = 0xff242424;
1874     stat = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0);
1875     expect(Ok, stat);
1876     stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
1877     expect(Ok, stat);
1878     stat = GdipDisposeImage((GpImage*)bitmap);
1879     expect(Ok, stat);
1880 
1881     hdc = CreateCompatibleDC(NULL);
1882     oldhbitmap = SelectObject(hdc, hbitmap);
1883     pixel = GetPixel(hdc, 0, 0);
1884     expect(0x686868, pixel);
1885     SelectObject(hdc, oldhbitmap);
1886     DeleteDC(hdc);
1887 }
1888 
1889 static void test_getthumbnail(void)
1890 {
1891     GpStatus stat;
1892     GpImage *bitmap1, *bitmap2;
1893     UINT width, height;
1894 
1895     stat = GdipGetImageThumbnail(NULL, 0, 0, &bitmap2, NULL, NULL);
1896     expect(InvalidParameter, stat);
1897 
1898     stat = GdipCreateBitmapFromScan0(128, 128, 0, PixelFormat32bppRGB, NULL, (GpBitmap**)&bitmap1);
1899     expect(Ok, stat);
1900 
1901     stat = GdipGetImageThumbnail(bitmap1, 0, 0, NULL, NULL, NULL);
1902     expect(InvalidParameter, stat);
1903 
1904     stat = GdipGetImageThumbnail(bitmap1, 0, 0, &bitmap2, NULL, NULL);
1905     expect(Ok, stat);
1906 
1907     if (stat == Ok)
1908     {
1909         stat = GdipGetImageWidth(bitmap2, &width);
1910         expect(Ok, stat);
1911         expect(120, width);
1912 
1913         stat = GdipGetImageHeight(bitmap2, &height);
1914         expect(Ok, stat);
1915         expect(120, height);
1916 
1917         GdipDisposeImage(bitmap2);
1918     }
1919 
1920     GdipDisposeImage(bitmap1);
1921 
1922 
1923     stat = GdipCreateBitmapFromScan0(64, 128, 0, PixelFormat32bppRGB, NULL, (GpBitmap**)&bitmap1);
1924     expect(Ok, stat);
1925 
1926     stat = GdipGetImageThumbnail(bitmap1, 32, 32, &bitmap2, NULL, NULL);
1927     expect(Ok, stat);
1928 
1929     if (stat == Ok)
1930     {
1931         stat = GdipGetImageWidth(bitmap2, &width);
1932         expect(Ok, stat);
1933         expect(32, width);
1934 
1935         stat = GdipGetImageHeight(bitmap2, &height);
1936         expect(Ok, stat);
1937         expect(32, height);
1938 
1939         GdipDisposeImage(bitmap2);
1940     }
1941 
1942     stat = GdipGetImageThumbnail(bitmap1, 0, 0, &bitmap2, NULL, NULL);
1943     expect(Ok, stat);
1944 
1945     if (stat == Ok)
1946     {
1947         stat = GdipGetImageWidth(bitmap2, &width);
1948         expect(Ok, stat);
1949         expect(120, width);
1950 
1951         stat = GdipGetImageHeight(bitmap2, &height);
1952         expect(Ok, stat);
1953         expect(120, height);
1954 
1955         GdipDisposeImage(bitmap2);
1956     }
1957 
1958     GdipDisposeImage(bitmap1);
1959 }
1960 
1961 static void test_getsetpixel(void)
1962 {
1963     GpStatus stat;
1964     GpBitmap *bitmap;
1965     ARGB color;
1966     BYTE bits[16] = {0x00,0x00,0x00,0x00, 0x00,0xff,0xff,0x00,
1967                      0xff,0x00,0x00,0x00, 0xff,0xff,0xff,0x00};
1968 
1969     stat = GdipCreateBitmapFromScan0(2, 2, 8, PixelFormat32bppRGB, bits, &bitmap);
1970     expect(Ok, stat);
1971 
1972     /* null parameters */
1973     stat = GdipBitmapGetPixel(NULL, 1, 1, &color);
1974     expect(InvalidParameter, stat);
1975 
1976     stat = GdipBitmapGetPixel(bitmap, 1, 1, NULL);
1977     expect(InvalidParameter, stat);
1978 
1979     stat = GdipBitmapSetPixel(NULL, 1, 1, 0);
1980     expect(InvalidParameter, stat);
1981 
1982     /* out of bounds */
1983     stat = GdipBitmapGetPixel(bitmap, -1, 1, &color);
1984     expect(InvalidParameter, stat);
1985 
1986     stat = GdipBitmapSetPixel(bitmap, -1, 1, 0);
1987     expect(InvalidParameter, stat);
1988 
1989     stat = GdipBitmapGetPixel(bitmap, 1, -1, &color);
1990     ok(stat == InvalidParameter ||
1991        broken(stat == Ok), /* Older gdiplus */
1992        "Expected InvalidParameter, got %.8x\n", stat);
1993 
1994 if (0) /* crashes some gdiplus implementations */
1995 {
1996     stat = GdipBitmapSetPixel(bitmap, 1, -1, 0);
1997     ok(stat == InvalidParameter ||
1998        broken(stat == Ok), /* Older gdiplus */
1999        "Expected InvalidParameter, got %.8x\n", stat);
2000 }
2001 
2002     stat = GdipBitmapGetPixel(bitmap, 2, 1, &color);
2003     expect(InvalidParameter, stat);
2004 
2005     stat = GdipBitmapSetPixel(bitmap, 2, 1, 0);
2006     expect(InvalidParameter, stat);
2007 
2008     stat = GdipBitmapGetPixel(bitmap, 1, 2, &color);
2009     expect(InvalidParameter, stat);
2010 
2011     stat = GdipBitmapSetPixel(bitmap, 1, 2, 0);
2012     expect(InvalidParameter, stat);
2013 
2014     /* valid use */
2015     stat = GdipBitmapGetPixel(bitmap, 1, 1, &color);
2016     expect(Ok, stat);
2017     expect(0xffffffff, color);
2018 
2019     stat = GdipBitmapGetPixel(bitmap, 0, 1, &color);
2020     expect(Ok, stat);
2021     expect(0xff0000ff, color);
2022 
2023     stat = GdipBitmapSetPixel(bitmap, 1, 1, 0xff676869);
2024     expect(Ok, stat);
2025 
2026     stat = GdipBitmapSetPixel(bitmap, 0, 0, 0xff474849);
2027     expect(Ok, stat);
2028 
2029     stat = GdipBitmapGetPixel(bitmap, 1, 1, &color);
2030     expect(Ok, stat);
2031     expect(0xff676869, color);
2032 
2033     stat = GdipBitmapGetPixel(bitmap, 0, 0, &color);
2034     expect(Ok, stat);
2035     expect(0xff474849, color);
2036 
2037     stat = GdipDisposeImage((GpImage*)bitmap);
2038     expect(Ok, stat);
2039 }
2040 
2041 static void check_halftone_palette(ColorPalette *palette)
2042 {
2043     static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
2044     UINT i;
2045 
2046     for (i=0; i<palette->Count; i++)
2047     {
2048         ARGB expected=0xff000000;
2049         if (i<8)
2050         {
2051             if (i&1) expected |= 0x800000;
2052             if (i&2) expected |= 0x8000;
2053             if (i&4) expected |= 0x80;
2054         }
2055         else if (i == 8)
2056         {
2057             expected = 0xffc0c0c0;
2058         }
2059         else if (i < 16)
2060         {
2061             if (i&1) expected |= 0xff0000;
2062             if (i&2) expected |= 0xff00;
2063             if (i&4) expected |= 0xff;
2064         }
2065         else if (i < 40)
2066         {
2067             expected = 0x00000000;
2068         }
2069         else
2070         {
2071             expected |= halftone_values[(i-40)%6];
2072             expected |= halftone_values[((i-40)/6)%6] << 8;
2073             expected |= halftone_values[((i-40)/36)%6] << 16;
2074         }
2075         ok(expected == palette->Entries[i], "Expected %.8x, got %.8x, i=%u/%u\n",
2076             expected, palette->Entries[i], i, palette->Count);
2077     }
2078 }
2079 
2080 static void test_palette(void)
2081 {
2082     GpStatus stat;
2083     GpBitmap *bitmap;
2084     INT size;
2085     BYTE buffer[1040];
2086     ColorPalette *palette=(ColorPalette*)buffer;
2087     ARGB *entries = palette->Entries;
2088     ARGB color=0;
2089 
2090     /* test initial palette from non-indexed bitmap */
2091     stat = GdipCreateBitmapFromScan0(2, 2, 8, PixelFormat32bppRGB, NULL, &bitmap);
2092     expect(Ok, stat);
2093 
2094     stat = GdipGetImagePaletteSize((GpImage*)bitmap, &size);
2095     expect(Ok, stat);
2096     expect(sizeof(UINT)*2+sizeof(ARGB), size);
2097 
2098     stat = GdipGetImagePalette((GpImage*)bitmap, palette, size);
2099     expect(Ok, stat);
2100     expect(0, palette->Count);
2101 
2102     /* test setting palette on not-indexed bitmap */
2103     palette->Count = 3;
2104 
2105     stat = GdipSetImagePalette((GpImage*)bitmap, palette);
2106     expect(Ok, stat);
2107 
2108     stat = GdipGetImagePaletteSize((GpImage*)bitmap, &size);
2109     expect(Ok, stat);
2110     expect(sizeof(UINT)*2+sizeof(ARGB)*3, size);
2111 
2112     stat = GdipGetImagePalette((GpImage*)bitmap, palette, size);
2113     expect(Ok, stat);
2114     expect(3, palette->Count);
2115 
2116     GdipDisposeImage((GpImage*)bitmap);
2117 
2118     /* test initial palette on 1-bit bitmap */
2119     stat = GdipCreateBitmapFromScan0(2, 2, 4, PixelFormat1bppIndexed, NULL, &bitmap);
2120     expect(Ok, stat);
2121 
2122     stat = GdipGetImagePaletteSize((GpImage*)bitmap, &size);
2123     expect(Ok, stat);
2124     expect(sizeof(UINT)*2+sizeof(ARGB)*2, size);
2125 
2126     stat = GdipGetImagePalette((GpImage*)bitmap, palette, size);
2127     expect(Ok, stat);
2128     expect(PaletteFlagsGrayScale, palette->Flags);
2129     expect(2, palette->Count);
2130 
2131     expect(0xff000000, entries[0]);
2132     expect(0xffffffff, entries[1]);
2133 
2134     /* test getting/setting pixels */
2135     stat = GdipBitmapGetPixel(bitmap, 0, 0, &color);
2136     expect(Ok, stat);
2137     expect(0xff000000, color);
2138 
2139     stat = GdipBitmapSetPixel(bitmap, 0, 1, 0xffffffff);
2140     ok((stat == Ok) ||
2141        broken(stat == InvalidParameter) /* pre-win7 */, "stat=%.8x\n", stat);
2142 
2143     if (stat == Ok)
2144     {
2145         stat = GdipBitmapGetPixel(bitmap, 0, 1, &color);
2146         expect(Ok, stat);
2147         expect(0xffffffff, color);
2148     }
2149 
2150     GdipDisposeImage((GpImage*)bitmap);
2151 
2152     /* test initial palette on 4-bit bitmap */
2153     stat = GdipCreateBitmapFromScan0(2, 2, 4, PixelFormat4bppIndexed, NULL, &bitmap);
2154     expect(Ok, stat);
2155 
2156     stat = GdipGetImagePaletteSize((GpImage*)bitmap, &size);
2157     expect(Ok, stat);
2158     expect(sizeof(UINT)*2+sizeof(ARGB)*16, size);
2159 
2160     stat = GdipGetImagePalette((GpImage*)bitmap, palette, size);
2161     expect(Ok, stat);
2162     expect(0, palette->Flags);
2163     expect(16, palette->Count);
2164 
2165     check_halftone_palette(palette);
2166 
2167     /* test getting/setting pixels */
2168     stat = GdipBitmapGetPixel(bitmap, 0, 0, &color);
2169     expect(Ok, stat);
2170     expect(0xff000000, color);
2171 
2172     stat = GdipBitmapSetPixel(bitmap, 0, 1, 0xffff00ff);
2173     ok((stat == Ok) ||
2174        broken(stat == InvalidParameter) /* pre-win7 */, "stat=%.8x\n", stat);
2175 
2176     if (stat == Ok)
2177     {
2178         stat = GdipBitmapGetPixel(bitmap, 0, 1, &color);
2179         expect(Ok, stat);
2180         expect(0xffff00ff, color);
2181     }
2182 
2183     GdipDisposeImage((GpImage*)bitmap);
2184 
2185     /* test initial palette on 8-bit bitmap */
2186     stat = GdipCreateBitmapFromScan0(2, 2, 8, PixelFormat8bppIndexed, NULL, &bitmap);
2187     expect(Ok, stat);
2188 
2189     stat = GdipGetImagePaletteSize((GpImage*)bitmap, &size);
2190     expect(Ok, stat);
2191     expect(sizeof(UINT)*2+sizeof(ARGB)*256, size);
2192 
2193     stat = GdipGetImagePalette((GpImage*)bitmap, palette, size);
2194     expect(Ok, stat);
2195     expect(PaletteFlagsHalftone, palette->Flags);
2196     expect(256, palette->Count);
2197 
2198     check_halftone_palette(palette);
2199 
2200     /* test getting/setting pixels */
2201     stat = GdipBitmapGetPixel(bitmap, 0, 0, &color);
2202     expect(Ok, stat);
2203     expect(0xff000000, color);
2204 
2205     stat = GdipBitmapSetPixel(bitmap, 0, 1, 0xffcccccc);
2206     ok((stat == Ok) ||
2207        broken(stat == InvalidParameter) /* pre-win7 */, "stat=%.8x\n", stat);
2208 
2209     if (stat == Ok)
2210     {
2211         stat = GdipBitmapGetPixel(bitmap, 0, 1, &color);
2212         expect(Ok, stat);
2213         expect(0xffcccccc, color);
2214     }
2215 
2216     /* test setting/getting a different palette */
2217     entries[1] = 0xffcccccc;
2218 
2219     stat = GdipSetImagePalette((GpImage*)bitmap, palette);
2220     expect(Ok, stat);
2221 
2222     entries[1] = 0;
2223 
2224     stat = GdipGetImagePaletteSize((GpImage*)bitmap, &size);
2225     expect(Ok, stat);
2226     expect(sizeof(UINT)*2+sizeof(ARGB)*256, size);
2227 
2228     stat = GdipGetImagePalette((GpImage*)bitmap, palette, size);
2229     expect(Ok, stat);
2230     expect(PaletteFlagsHalftone, palette->Flags);
2231     expect(256, palette->Count);
2232     expect(0xffcccccc, entries[1]);
2233 
2234     /* test count < 256 */
2235     palette->Flags = 12345;
2236     palette->Count = 3;
2237 
2238     stat = GdipSetImagePalette((GpImage*)bitmap, palette);
2239     expect(Ok, stat);
2240 
2241     entries[1] = 0;
2242     entries[3] = 0xdeadbeef;
2243 
2244     stat = GdipGetImagePaletteSize((GpImage*)bitmap, &size);
2245     expect(Ok, stat);
2246     expect(sizeof(UINT)*2+sizeof(ARGB)*3, size);
2247 
2248     stat = GdipGetImagePalette((GpImage*)bitmap, palette, size);
2249     expect(Ok, stat);
2250     expect(12345, palette->Flags);
2251     expect(3, palette->Count);
2252     expect(0xffcccccc, entries[1]);
2253     expect(0xdeadbeef, entries[3]);
2254 
2255     /* test count > 256 */
2256     palette->Count = 257;
2257 
2258     stat = GdipSetImagePalette((GpImage*)bitmap, palette);
2259     ok(stat == InvalidParameter ||
2260        broken(stat == Ok), /* Old gdiplus behavior */
2261        "Expected %.8x, got %.8x\n", InvalidParameter, stat);
2262 
2263     GdipDisposeImage((GpImage*)bitmap);
2264 }
2265 
2266 static void test_colormatrix(void)
2267 {
2268     GpStatus stat;
2269     ColorMatrix colormatrix, graymatrix;
2270     GpImageAttributes *imageattr;
2271     const ColorMatrix identity = {{
2272         {1.0,0.0,0.0,0.0,0.0},
2273         {0.0,1.0,0.0,0.0,0.0},
2274         {0.0,0.0,1.0,0.0,0.0},
2275         {0.0,0.0,0.0,1.0,0.0},
2276         {0.0,0.0,0.0,0.0,1.0}}};
2277     const ColorMatrix double_red = {{
2278         {2.0,0.0,0.0,0.0,0.0},
2279         {0.0,1.0,0.0,0.0,0.0},
2280         {0.0,0.0,1.0,0.0,0.0},
2281         {0.0,0.0,0.0,1.0,0.0},
2282         {0.0,0.0,0.0,0.0,1.0}}};
2283     const ColorMatrix asymmetric = {{
2284         {0.0,1.0,0.0,0.0,0.0},
2285         {0.0,0.0,1.0,0.0,0.0},
2286         {0.0,0.0,0.0,1.0,0.0},
2287         {1.0,0.0,0.0,0.0,0.0},
2288         {0.0,0.0,0.0,0.0,1.0}}};
2289     GpBitmap *bitmap1, *bitmap2;
2290     GpGraphics *graphics;
2291     ARGB color;
2292 
2293     colormatrix = identity;
2294     graymatrix = identity;
2295 
2296     stat = GdipSetImageAttributesColorMatrix(NULL, ColorAdjustTypeDefault,
2297         TRUE, &colormatrix, &graymatrix, ColorMatrixFlagsDefault);
2298     expect(InvalidParameter, stat);
2299 
2300     stat = GdipCreateImageAttributes(&imageattr);
2301     expect(Ok, stat);
2302 
2303     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2304         TRUE, &colormatrix, NULL, ColorMatrixFlagsDefault);
2305     expect(Ok, stat);
2306 
2307     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2308         TRUE, NULL, NULL, ColorMatrixFlagsDefault);
2309     expect(InvalidParameter, stat);
2310 
2311     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2312         TRUE, &colormatrix, &graymatrix, ColorMatrixFlagsDefault);
2313     expect(Ok, stat);
2314 
2315     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2316         TRUE, &colormatrix, NULL, ColorMatrixFlagsSkipGrays);
2317     expect(Ok, stat);
2318 
2319     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2320         TRUE, &colormatrix, NULL, ColorMatrixFlagsAltGray);
2321     expect(InvalidParameter, stat);
2322 
2323     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2324         TRUE, &colormatrix, &graymatrix, ColorMatrixFlagsAltGray);
2325     expect(Ok, stat);
2326 
2327     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2328         TRUE, &colormatrix, &graymatrix, 3);
2329     expect(InvalidParameter, stat);
2330 
2331     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeCount,
2332         TRUE, &colormatrix, &graymatrix, ColorMatrixFlagsDefault);
2333     expect(InvalidParameter, stat);
2334 
2335     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeAny,
2336         TRUE, &colormatrix, &graymatrix, ColorMatrixFlagsDefault);
2337     expect(InvalidParameter, stat);
2338 
2339     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2340         FALSE, NULL, NULL, ColorMatrixFlagsDefault);
2341     expect(Ok, stat);
2342 
2343     /* Drawing a bitmap transforms the colors */
2344     colormatrix = double_red;
2345     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2346         TRUE, &colormatrix, NULL, ColorMatrixFlagsDefault);
2347     expect(Ok, stat);
2348 
2349     stat = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat32bppARGB, NULL, &bitmap1);
2350     expect(Ok, stat);
2351 
2352     stat = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat32bppARGB, NULL, &bitmap2);
2353     expect(Ok, stat);
2354 
2355     stat = GdipBitmapSetPixel(bitmap1, 0, 0, 0xff40ccee);
2356     expect(Ok, stat);
2357 
2358     stat = GdipGetImageGraphicsContext((GpImage*)bitmap2, &graphics);
2359     expect(Ok, stat);
2360 
2361     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
2362         UnitPixel, imageattr, NULL, NULL);
2363     expect(Ok, stat);
2364 
2365     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
2366     expect(Ok, stat);
2367     expect(0xff80ccee, color);
2368 
2369     colormatrix = asymmetric;
2370     stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault,
2371         TRUE, &colormatrix, NULL, ColorMatrixFlagsDefault);
2372     expect(Ok, stat);
2373 
2374     stat = GdipBitmapSetPixel(bitmap2, 0, 0, 0);
2375     expect(Ok, stat);
2376 
2377     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
2378         UnitPixel, imageattr, NULL, NULL);
2379     expect(Ok, stat);
2380 
2381     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
2382     expect(Ok, stat);
2383     ok(color_match(0xeeff40cc, color, 3), "expected 0xeeff40cc, got 0x%08x\n", color);
2384 
2385     stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
2386     expect(Ok, stat);
2387 
2388     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
2389         UnitPixel, imageattr, NULL, NULL);
2390     expect(Ok, stat);
2391 
2392     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
2393     expect(Ok, stat);
2394     ok(color_match(0xff40ccee, color, 1), "Expected ff40ccee, got %.8x\n", color);
2395 
2396     GdipDeleteGraphics(graphics);
2397     GdipDisposeImage((GpImage*)bitmap1);
2398     GdipDisposeImage((GpImage*)bitmap2);
2399     GdipDisposeImageAttributes(imageattr);
2400 }
2401 
2402 static void test_gamma(void)
2403 {
2404     GpStatus stat;
2405     GpImageAttributes *imageattr;
2406     GpBitmap *bitmap1, *bitmap2;
2407     GpGraphics *graphics;
2408     ARGB color;
2409 
2410     stat = GdipSetImageAttributesGamma(NULL, ColorAdjustTypeDefault, TRUE, 1.0);
2411     expect(InvalidParameter, stat);
2412 
2413     stat = GdipCreateImageAttributes(&imageattr);
2414     expect(Ok, stat);
2415 
2416     stat = GdipSetImageAttributesGamma(imageattr, ColorAdjustTypeDefault, TRUE, 1.0);
2417     expect(Ok, stat);
2418 
2419     stat = GdipSetImageAttributesGamma(imageattr, ColorAdjustTypeAny, TRUE, 1.0);
2420     expect(InvalidParameter, stat);
2421 
2422     stat = GdipSetImageAttributesGamma(imageattr, ColorAdjustTypeDefault, TRUE, -1.0);
2423     expect(InvalidParameter, stat);
2424 
2425     stat = GdipSetImageAttributesGamma(imageattr, ColorAdjustTypeDefault, TRUE, 0.0);
2426     expect(InvalidParameter, stat);
2427 
2428     stat = GdipSetImageAttributesGamma(imageattr, ColorAdjustTypeDefault, TRUE, 0.5);
2429     expect(Ok, stat);
2430 
2431     stat = GdipSetImageAttributesGamma(imageattr, ColorAdjustTypeDefault, FALSE, 0.0);
2432     expect(Ok, stat);
2433 
2434     /* Drawing a bitmap transforms the colors */
2435     stat = GdipSetImageAttributesGamma(imageattr, ColorAdjustTypeDefault, TRUE, 3.0);
2436     expect(Ok, stat);
2437 
2438     stat = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat32bppRGB, NULL, &bitmap1);
2439     expect(Ok, stat);
2440 
2441     stat = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat32bppRGB, NULL, &bitmap2);
2442     expect(Ok, stat);
2443 
2444     stat = GdipBitmapSetPixel(bitmap1, 0, 0, 0xff80ffff);
2445     expect(Ok, stat);
2446 
2447     stat = GdipGetImageGraphicsContext((GpImage*)bitmap2, &graphics);
2448     expect(Ok, stat);
2449 
2450     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
2451         UnitPixel, imageattr, NULL, NULL);
2452     expect(Ok, stat);
2453 
2454     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
2455     expect(Ok, stat);
2456     ok(color_match(0xff20ffff, color, 1), "Expected ff20ffff, got %.8x\n", color);
2457 
2458     stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
2459     expect(Ok, stat);
2460 
2461     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
2462         UnitPixel, imageattr, NULL, NULL);
2463     expect(Ok, stat);
2464 
2465     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
2466     expect(Ok, stat);
2467     ok(color_match(0xff80ffff, color, 1), "Expected ff80ffff, got %.8x\n", color);
2468 
2469     GdipDeleteGraphics(graphics);
2470     GdipDisposeImage((GpImage*)bitmap1);
2471     GdipDisposeImage((GpImage*)bitmap2);
2472     GdipDisposeImageAttributes(imageattr);
2473 }
2474 
2475 /* 1x1 pixel gif, 2 frames; first frame is white, second is black */
2476 static const unsigned char gifanimation[72] = {
2477 0x47,0x49,0x46,0x38,0x39,0x61,0x01,0x00,0x01,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
2478 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0xf9,0x04,0x00,0x0a,0x00,0xff,
2479 0x00,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x4c,0x01,0x00,
2480 0x21,0xf9,0x04,0x01,0x0a,0x00,0x01,0x00,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,
2481 0x00,0x00,0x02,0x02,0x44,0x01,0x00,0x3b
2482 };
2483 
2484 /* Generated with ImageMagick:
2485  * convert -transparent black -delay 100 -size 8x2 xc:black \
2486  *     -dispose none -page +0+0 -size 2x2 xc:red \
2487  *     -dispose background -page +2+0 -size 2x2 xc:blue \
2488  *     -dispose previous -page +4+0 -size 2x2 xc:green \
2489  *     -dispose undefined -page +6+0 -size 2x2 xc:gray \
2490  *     test.gif
2491  */
2492 static const unsigned char gifanimation2[] = {
2493     0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x08, 0x00,
2494     0x02, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
2495     0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x64,
2496     0x00, 0x00, 0x00, 0x21, 0xff, 0x0b, 0x4e, 0x45,
2497     0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e,
2498     0x30, 0x03, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00,
2499     0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
2500     0x02, 0x04, 0x84, 0x8f, 0x09, 0x05, 0x00, 0x21,
2501     0xf9, 0x04, 0x04, 0x64, 0x00, 0x00, 0x00, 0x2c,
2502     0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
2503     0x81, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
2504     0x00, 0x00, 0xff, 0x00, 0x00, 0x02, 0x03, 0x44,
2505     0x34, 0x05, 0x00, 0x21, 0xf9, 0x04, 0x08, 0x64,
2506     0x00, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, 0x00,
2507     0x02, 0x00, 0x02, 0x00, 0x81, 0x00, 0x00, 0xff,
2508     0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
2509     0xff, 0x02, 0x03, 0x44, 0x34, 0x05, 0x00, 0x21,
2510     0xf9, 0x04, 0x0c, 0x64, 0x00, 0x00, 0x00, 0x2c,
2511     0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
2512     0x81, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00,
2513     0x80, 0x00, 0x00, 0x80, 0x00, 0x02, 0x03, 0x44,
2514     0x34, 0x05, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x64,
2515     0x00, 0x00, 0x00, 0x2c, 0x06, 0x00, 0x00, 0x00,
2516     0x02, 0x00, 0x02, 0x00, 0x80, 0x7e, 0x7e, 0x7e,
2517     0x00, 0x00, 0x00, 0x02, 0x02, 0x84, 0x51, 0x00,
2518     0x3b
2519 };
2520 
2521 static ARGB gifanimation2_pixels[5][4] = {
2522     {0, 0, 0, 0},
2523     {0xffff0000, 0, 0, 0},
2524     {0xffff0000, 0xff0000ff, 0, 0},
2525     {0xffff0000, 0, 0xff008000, 0},
2526     {0xffff0000, 0, 0, 0xff7e7e7e}
2527 };
2528 
2529 static void test_multiframegif(void)
2530 {
2531     LPSTREAM stream;
2532     HGLOBAL hglob;
2533     LPBYTE data;
2534     HRESULT hres;
2535     GpStatus stat;
2536     GpBitmap *bmp;
2537     ARGB color;
2538     UINT count;
2539     GUID dimension;
2540     PixelFormat pixel_format;
2541     INT palette_size, i, j;
2542     char palette_buf[256];
2543     ColorPalette *palette;
2544     ARGB *palette_entries;
2545 
2546     /* Test frame functions with an animated GIF */
2547     hglob = GlobalAlloc (0, sizeof(gifanimation));
2548     data = GlobalLock (hglob);
2549     memcpy(data, gifanimation, sizeof(gifanimation));
2550     GlobalUnlock(hglob);
2551 
2552     hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
2553     ok(hres == S_OK, "Failed to create a stream\n");
2554     if(hres != S_OK) return;
2555 
2556     stat = GdipCreateBitmapFromStream(stream, &bmp);
2557     ok(stat == Ok, "Failed to create a Bitmap\n");
2558     if(stat != Ok){
2559         IStream_Release(stream);
2560         return;
2561     }
2562 
2563     stat = GdipGetImagePixelFormat((GpImage*)bmp, &pixel_format);
2564     expect(Ok, stat);
2565     expect(PixelFormat32bppARGB, pixel_format);
2566 
2567     stat = GdipGetImagePaletteSize((GpImage*)bmp, &palette_size);
2568     expect(Ok, stat);
2569     ok(palette_size == sizeof(ColorPalette) ||
2570             broken(palette_size == sizeof(ColorPalette)+sizeof(ARGB[3])),
2571             "palette_size = %d\n", palette_size);
2572 
2573     /* Bitmap starts at frame 0 */
2574     color = 0xdeadbeef;
2575     stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
2576     expect(Ok, stat);
2577     expect(0xffffffff, color);
2578 
2579     /* Check that we get correct metadata */
2580     stat = GdipImageGetFrameDimensionsCount((GpImage*)bmp,&count);
2581     expect(Ok, stat);
2582     expect(1, count);
2583 
2584     stat = GdipImageGetFrameDimensionsList((GpImage*)bmp, &dimension, 1);
2585     expect(Ok, stat);
2586     expect_guid(&FrameDimensionTime, &dimension, __LINE__, FALSE);
2587 
2588     count = 12345;
2589     stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
2590     expect(Ok, stat);
2591     expect(2, count);
2592 
2593     /* SelectActiveFrame overwrites our current data */
2594     stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 1);
2595     expect(Ok, stat);
2596 
2597     color = 0xdeadbeef;
2598     GdipBitmapGetPixel(bmp, 0, 0, &color);
2599     expect(Ok, stat);
2600     expect(0xff000000, color);
2601 
2602     stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 0);
2603     expect(Ok, stat);
2604 
2605     color = 0xdeadbeef;
2606     GdipBitmapGetPixel(bmp, 0, 0, &color);
2607     expect(Ok, stat);
2608     expect(0xffffffff, color);
2609 
2610     /* Write over the image data */
2611     stat = GdipBitmapSetPixel(bmp, 0, 0, 0xff000000);
2612     expect(Ok, stat);
2613 
2614     /* Switching to the same frame does not overwrite our changes */
2615     stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 0);
2616     expect(Ok, stat);
2617 
2618     stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
2619     expect(Ok, stat);
2620     expect(0xff000000, color);
2621 
2622     /* But switching to another frame and back does */
2623     stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 1);
2624     expect(Ok, stat);
2625 
2626     stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 0);
2627     expect(Ok, stat);
2628 
2629     stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
2630     expect(Ok, stat);
2631     expect(0xffffffff, color);
2632 
2633     /* rotate/flip discards the information about other frames */
2634     stat = GdipImageRotateFlip((GpImage*)bmp, Rotate90FlipNone);
2635     expect(Ok, stat);
2636 
2637     count = 12345;
2638     stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
2639     expect(Ok, stat);
2640     expect(1, count);
2641 
2642     expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)bmp, __LINE__, FALSE);
2643 
2644     GdipDisposeImage((GpImage*)bmp);
2645     IStream_Release(stream);
2646 
2647     /* Test with a non-animated gif */
2648     hglob = GlobalAlloc (0, sizeof(gifimage));
2649     data = GlobalLock (hglob);
2650     memcpy(data, gifimage, sizeof(gifimage));
2651     GlobalUnlock(hglob);
2652 
2653     hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
2654     ok(hres == S_OK, "Failed to create a stream\n");
2655     if(hres != S_OK) return;
2656 
2657     stat = GdipCreateBitmapFromStream(stream, &bmp);
2658     ok(stat == Ok, "Failed to create a Bitmap\n");
2659     if(stat != Ok){
2660         IStream_Release(stream);
2661         return;
2662     }
2663 
2664     stat = GdipGetImagePixelFormat((GpImage*)bmp, &pixel_format);
2665     expect(Ok, stat);
2666     expect(PixelFormat8bppIndexed, pixel_format);
2667 
2668     /* Check metadata */
2669     stat = GdipImageGetFrameDimensionsCount((GpImage*)bmp,&count);
2670     expect(Ok, stat);
2671     expect(1, count);
2672 
2673     stat = GdipImageGetFrameDimensionsList((GpImage*)bmp, &dimension, 1);
2674     expect(Ok, stat);
2675     expect_guid(&FrameDimensionTime, &dimension, __LINE__, FALSE);
2676 
2677     count = 12345;
2678     stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
2679     expect(Ok, stat);
2680     expect(1, count);
2681 
2682     GdipDisposeImage((GpImage*)bmp);
2683     IStream_Release(stream);
2684 
2685     /* Test with a non-animated transparent gif */
2686     hglob = GlobalAlloc (0, sizeof(transparentgif));
2687     data = GlobalLock (hglob);
2688     memcpy(data, transparentgif, sizeof(transparentgif));
2689     GlobalUnlock(hglob);
2690 
2691     hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
2692     ok(hres == S_OK, "Failed to create a stream\n");
2693 
2694     stat = GdipCreateBitmapFromStream(stream, &bmp);
2695     IStream_Release(stream);
2696     ok(stat == Ok, "Failed to create a Bitmap\n");
2697 
2698     stat = GdipGetImagePixelFormat((GpImage*)bmp, &pixel_format);
2699     expect(Ok, stat);
2700     expect(PixelFormat8bppIndexed, pixel_format);
2701 
2702     stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
2703     expect(Ok, stat);
2704     expect(0, color);
2705 
2706     stat = GdipGetImagePaletteSize((GpImage*)bmp, &palette_size);
2707     expect(Ok, stat);
2708     ok(palette_size == sizeof(ColorPalette)+sizeof(ARGB),
2709             "palette_size = %d\n", palette_size);
2710 
2711     memset(palette_buf, 0xfe, sizeof(palette_buf));
2712     palette = (ColorPalette*)palette_buf;
2713     stat = GdipGetImagePalette((GpImage*)bmp, palette,
2714             sizeof(ColorPalette)+sizeof(ARGB));
2715     palette_entries = palette->Entries;
2716     expect(Ok, stat);
2717     expect(PaletteFlagsHasAlpha, palette->Flags);
2718     expect(2, palette->Count);
2719     expect(0, palette_entries[0]);
2720     expect(0xff000000, palette_entries[1]);
2721 
2722     count = 12345;
2723     stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
2724     expect(Ok, stat);
2725     expect(1, count);
2726 
2727     GdipDisposeImage((GpImage*)bmp);
2728 
2729     /* Test frame dispose methods */
2730     hglob = GlobalAlloc (0, sizeof(gifanimation2));
2731     data = GlobalLock (hglob);
2732     memcpy(data, gifanimation2, sizeof(gifanimation2));
2733     GlobalUnlock(hglob);
2734 
2735     hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
2736     ok(hres == S_OK, "Failed to create a stream\n");
2737 
2738     stat = GdipCreateBitmapFromStream(stream, &bmp);
2739     ok(stat == Ok, "Failed to create a Bitmap\n");
2740     IStream_Release(stream);
2741 
2742     stat = GdipImageGetFrameDimensionsList((GpImage*)bmp, &dimension, 1);
2743     expect(Ok, stat);
2744     expect_guid(&FrameDimensionTime, &dimension, __LINE__, FALSE);
2745 
2746     stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
2747     expect(Ok, stat);
2748     expect(5, count);
2749 
2750     stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
2751     expect(Ok, stat);
2752     expect(0, color);
2753 
2754     stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 3);
2755     expect(Ok, stat);
2756     stat = GdipBitmapGetPixel(bmp, 2, 0, &color);
2757     expect(Ok, stat);
2758     ok(color==0 || broken(color==0xff0000ff), "color = %x\n", color);
2759     if(color != 0) {
2760         win_skip("broken animated gif support\n");
2761         GdipDisposeImage((GpImage*)bmp);
2762         return;
2763     }
2764 
2765     for(i=0; i<6; i++) {
2766         stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, i%5);
2767         expect(Ok, stat);
2768 
2769         for(j=0; j<4; j++) {
2770             stat = GdipBitmapGetPixel(bmp, j*2, 0, &color);
2771             expect(Ok, stat);
2772             ok(gifanimation2_pixels[i%5][j] == color, "at %d,%d got %x, expected %x\n", i, j, color, gifanimation2_pixels[i%5][j]);
2773         }
2774     }
2775 
2776     GdipDisposeImage((GpImage*)bmp);
2777 }
2778 
2779 static void test_rotateflip(void)
2780 {
2781     GpImage *bitmap;
2782     GpStatus stat;
2783     BYTE bits[24];
2784     static const BYTE orig_bits[24] = {
2785         0,0,0xff,    0,0xff,0,    0xff,0,0,    23,23,23,
2786         0xff,0xff,0, 0xff,0,0xff, 0,0xff,0xff, 23,23,23};
2787     UINT width, height;
2788     ARGB color;
2789 
2790     memcpy(bits, orig_bits, sizeof(bits));
2791     stat = GdipCreateBitmapFromScan0(3, 2, 12, PixelFormat24bppRGB, bits, (GpBitmap**)&bitmap);
2792     expect(Ok, stat);
2793 
2794     stat = GdipImageRotateFlip(bitmap, Rotate90FlipNone);
2795     expect(Ok, stat);
2796 
2797     stat = GdipGetImageWidth(bitmap, &width);
2798     expect(Ok, stat);
2799     stat = GdipGetImageHeight(bitmap, &height);
2800     expect(Ok, stat);
2801     expect(2, width);
2802     expect(3, height);
2803 
2804     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 0, &color);
2805     expect(Ok, stat);
2806     expect(0xff00ffff, color);
2807 
2808     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 1, 0, &color);
2809     expect(Ok, stat);
2810     expect(0xffff0000, color);
2811 
2812     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 2, &color);
2813     expect(Ok, stat);
2814     expect(0xffffff00, color);
2815 
2816     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 1, 2, &color);
2817     expect(Ok, stat);
2818     expect(0xff0000ff, color);
2819 
2820     expect(0, bits[0]);
2821     expect(0, bits[1]);
2822     expect(0xff, bits[2]);
2823 
2824     GdipDisposeImage(bitmap);
2825 
2826     memcpy(bits, orig_bits, sizeof(bits));
2827     stat = GdipCreateBitmapFromScan0(3, 2, 12, PixelFormat24bppRGB, bits, (GpBitmap**)&bitmap);
2828     expect(Ok, stat);
2829 
2830     stat = GdipImageRotateFlip(bitmap, RotateNoneFlipX);
2831     expect(Ok, stat);
2832 
2833     stat = GdipGetImageWidth(bitmap, &width);
2834     expect(Ok, stat);
2835     stat = GdipGetImageHeight(bitmap, &height);
2836     expect(Ok, stat);
2837     expect(3, width);
2838     expect(2, height);
2839 
2840     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 0, &color);
2841     expect(Ok, stat);
2842     expect(0xff0000ff, color);
2843 
2844     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 0, &color);
2845     expect(Ok, stat);
2846     expect(0xffff0000, color);
2847 
2848     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 1, &color);
2849     expect(Ok, stat);
2850     expect(0xffffff00, color);
2851 
2852     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 1, &color);
2853     expect(Ok, stat);
2854     expect(0xff00ffff, color);
2855 
2856     expect(0, bits[0]);
2857     expect(0, bits[1]);
2858     expect(0xff, bits[2]);
2859 
2860     GdipDisposeImage(bitmap);
2861 
2862     memcpy(bits, orig_bits, sizeof(bits));
2863     stat = GdipCreateBitmapFromScan0(3, 2, 12, PixelFormat24bppRGB, bits, (GpBitmap**)&bitmap);
2864     expect(Ok, stat);
2865 
2866     stat = GdipImageRotateFlip(bitmap, RotateNoneFlipY);
2867     expect(Ok, stat);
2868 
2869     stat = GdipGetImageWidth(bitmap, &width);
2870     expect(Ok, stat);
2871     stat = GdipGetImageHeight(bitmap, &height);
2872     expect(Ok, stat);
2873     expect(3, width);
2874     expect(2, height);
2875 
2876     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 0, &color);
2877     expect(Ok, stat);
2878     expect(0xff00ffff, color);
2879 
2880     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 0, &color);
2881     expect(Ok, stat);
2882     expect(0xffffff00, color);
2883 
2884     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 1, &color);
2885     expect(Ok, stat);
2886     expect(0xffff0000, color);
2887 
2888     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 1, &color);
2889     expect(Ok, stat);
2890     expect(0xff0000ff, color);
2891 
2892     expect(0, bits[0]);
2893     expect(0, bits[1]);
2894     expect(0xff, bits[2]);
2895 
2896     GdipDisposeImage(bitmap);
2897 }
2898 
2899 static void test_remaptable(void)
2900 {
2901     GpStatus stat;
2902     GpImageAttributes *imageattr;
2903     GpBitmap *bitmap1, *bitmap2;
2904     GpGraphics *graphics;
2905     ARGB color;
2906     ColorMap *map;
2907 
2908     map = GdipAlloc(sizeof(ColorMap));
2909 
2910     map->oldColor.Argb = 0xff00ff00;
2911     map->newColor.Argb = 0xffff00ff;
2912 
2913     stat = GdipSetImageAttributesRemapTable(NULL, ColorAdjustTypeDefault, TRUE, 1, map);
2914     expect(InvalidParameter, stat);
2915 
2916     stat = GdipCreateImageAttributes(&imageattr);
2917     expect(Ok, stat);
2918 
2919     stat = GdipSetImageAttributesRemapTable(imageattr, ColorAdjustTypeDefault, TRUE, 1, NULL);
2920     expect(InvalidParameter, stat);
2921 
2922     stat = GdipSetImageAttributesRemapTable(imageattr, ColorAdjustTypeCount, TRUE, 1, map);
2923     expect(InvalidParameter, stat);
2924 
2925     stat = GdipSetImageAttributesRemapTable(imageattr, ColorAdjustTypeAny, TRUE, 1, map);
2926     expect(InvalidParameter, stat);
2927 
2928     stat = GdipSetImageAttributesRemapTable(imageattr, ColorAdjustTypeDefault, TRUE, 0, map);
2929     expect(InvalidParameter, stat);
2930 
2931     stat = GdipSetImageAttributesRemapTable(imageattr, ColorAdjustTypeDefault, FALSE, 0, NULL);
2932     expect(Ok, stat);
2933 
2934     stat = GdipSetImageAttributesRemapTable(imageattr, ColorAdjustTypeDefault, TRUE, 1, map);
2935     expect(Ok, stat);
2936 
2937     stat = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat32bppRGB, NULL, &bitmap1);
2938     expect(Ok, stat);
2939 
2940     stat = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat32bppRGB, NULL, &bitmap2);
2941     expect(Ok, stat);
2942 
2943     stat = GdipBitmapSetPixel(bitmap1, 0, 0, 0xff00ff00);
2944     expect(Ok, stat);
2945 
2946     stat = GdipGetImageGraphicsContext((GpImage*)bitmap2, &graphics);
2947     expect(Ok, stat);
2948 
2949     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
2950 	UnitPixel, imageattr, NULL, NULL);
2951     expect(Ok, stat);
2952 
2953     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
2954     expect(Ok, stat);
2955     ok(color_match(0xffff00ff, color, 1), "Expected ffff00ff, got %.8x\n", color);
2956 
2957     stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
2958     expect(Ok, stat);
2959 
2960     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
2961         UnitPixel, imageattr, NULL, NULL);
2962     expect(Ok, stat);
2963 
2964     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
2965     expect(Ok, stat);
2966     ok(color_match(0xff00ff00, color, 1), "Expected ff00ff00, got %.8x\n", color);
2967 
2968     GdipDeleteGraphics(graphics);
2969     GdipDisposeImage((GpImage*)bitmap1);
2970     GdipDisposeImage((GpImage*)bitmap2);
2971     GdipDisposeImageAttributes(imageattr);
2972     GdipFree(map);
2973 }
2974 
2975 static void test_colorkey(void)
2976 {
2977     GpStatus stat;
2978     GpImageAttributes *imageattr;
2979     GpBitmap *bitmap1, *bitmap2;
2980     GpGraphics *graphics;
2981     ARGB color;
2982 
2983     stat = GdipSetImageAttributesColorKeys(NULL, ColorAdjustTypeDefault, TRUE, 0xff405060, 0xff708090);
2984     expect(InvalidParameter, stat);
2985 
2986     stat = GdipCreateImageAttributes(&imageattr);
2987     expect(Ok, stat);
2988 
2989     stat = GdipSetImageAttributesColorKeys(imageattr, ColorAdjustTypeCount, TRUE, 0xff405060, 0xff708090);
2990     expect(InvalidParameter, stat);
2991 
2992     stat = GdipSetImageAttributesColorKeys(imageattr, ColorAdjustTypeAny, TRUE, 0xff405060, 0xff708090);
2993     expect(InvalidParameter, stat);
2994 
2995     stat = GdipSetImageAttributesColorKeys(imageattr, ColorAdjustTypeDefault, TRUE, 0xff405060, 0xff708090);
2996     expect(Ok, stat);
2997 
2998     stat = GdipCreateBitmapFromScan0(2, 2, 0, PixelFormat32bppARGB, NULL, &bitmap1);
2999     expect(Ok, stat);
3000 
3001     stat = GdipCreateBitmapFromScan0(2, 2, 0, PixelFormat32bppARGB, NULL, &bitmap2);
3002     expect(Ok, stat);
3003 
3004     stat = GdipBitmapSetPixel(bitmap1, 0, 0, 0x20405060);
3005     expect(Ok, stat);
3006 
3007     stat = GdipBitmapSetPixel(bitmap1, 0, 1, 0x40506070);
3008     expect(Ok, stat);
3009 
3010     stat = GdipBitmapSetPixel(bitmap1, 1, 0, 0x60708090);
3011     expect(Ok, stat);
3012 
3013     stat = GdipBitmapSetPixel(bitmap1, 1, 1, 0xffffffff);
3014     expect(Ok, stat);
3015 
3016     stat = GdipGetImageGraphicsContext((GpImage*)bitmap2, &graphics);
3017     expect(Ok, stat);
3018 
3019     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,2,2, 0,0,2,2,
3020 	UnitPixel, imageattr, NULL, NULL);
3021     expect(Ok, stat);
3022 
3023     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
3024     expect(Ok, stat);
3025     ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color);
3026 
3027     stat = GdipBitmapGetPixel(bitmap2, 0, 1, &color);
3028     expect(Ok, stat);
3029     ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color);
3030 
3031     stat = GdipBitmapGetPixel(bitmap2, 1, 0, &color);
3032     expect(Ok, stat);
3033     ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color);
3034 
3035     stat = GdipBitmapGetPixel(bitmap2, 1, 1, &color);
3036     expect(Ok, stat);
3037     ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8x\n", color);
3038 
3039     stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
3040     expect(Ok, stat);
3041 
3042     stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,2,2, 0,0,2,2,
3043 	UnitPixel, imageattr, NULL, NULL);
3044     expect(Ok, stat);
3045 
3046     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
3047     expect(Ok, stat);
3048     ok(color_match(0x20405060, color, 1), "Expected 20405060, got %.8x\n", color);
3049 
3050     stat = GdipBitmapGetPixel(bitmap2, 0, 1, &color);
3051     expect(Ok, stat);
3052     ok(color_match(0x40506070, color, 1), "Expected 40506070, got %.8x\n", color);
3053 
3054     stat = GdipBitmapGetPixel(bitmap2, 1, 0, &color);
3055     expect(Ok, stat);
3056     ok(color_match(0x60708090, color, 1), "Expected 60708090, got %.8x\n", color);
3057 
3058     stat = GdipBitmapGetPixel(bitmap2, 1, 1, &color);
3059     expect(Ok, stat);
3060     ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8x\n", color);
3061 
3062 
3063     GdipDeleteGraphics(graphics);
3064     GdipDisposeImage((GpImage*)bitmap1);
3065     GdipDisposeImage((GpImage*)bitmap2);
3066     GdipDisposeImageAttributes(imageattr);
3067 }
3068 
3069 static void test_dispose(void)
3070 {
3071     GpStatus stat;
3072     GpImage *image;
3073     char invalid_image[256];
3074 
3075     stat = GdipDisposeImage(NULL);
3076     expect(InvalidParameter, stat);
3077 
3078     stat = GdipCreateBitmapFromScan0(2, 2, 0, PixelFormat32bppARGB, NULL, (GpBitmap**)&image);
3079     expect(Ok, stat);
3080 
3081     stat = GdipDisposeImage(image);
3082     expect(Ok, stat);
3083 
3084     stat = GdipDisposeImage(image);
3085     expect(ObjectBusy, stat);
3086 
3087     memset(invalid_image, 0, 256);
3088     stat = GdipDisposeImage((GpImage*)invalid_image);
3089     expect(ObjectBusy, stat);
3090 }
3091 
3092 static LONG obj_refcount(void *obj)
3093 {
3094     IUnknown_AddRef((IUnknown *)obj);
3095     return IUnknown_Release((IUnknown *)obj);
3096 }
3097 
3098 static GpImage *load_image(const BYTE *image_data, UINT image_size)
3099 {
3100     IStream *stream;
3101     HGLOBAL hmem;
3102     BYTE *data;
3103     HRESULT hr;
3104     GpStatus status;
3105     GpImage *image = NULL, *clone;
3106     ImageType image_type;
3107     LONG refcount, old_refcount;
3108 
3109     hmem = GlobalAlloc(0, image_size);
3110     data = GlobalLock(hmem);
3111     memcpy(data, image_data, image_size);
3112     GlobalUnlock(hmem);
3113 
3114     hr = CreateStreamOnHGlobal(hmem, TRUE, &stream);
3115     ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
3116     if (hr != S_OK) return NULL;
3117 
3118     refcount = obj_refcount(stream);
3119     ok(refcount == 1, "expected stream refcount 1, got %d\n", refcount);
3120 
3121     status = GdipLoadImageFromStream(stream, &image);
3122     if (status != Ok)
3123     {
3124         IStream_Release(stream);
3125         return NULL;
3126     }
3127 
3128     status = GdipGetImageType(image, &image_type);
3129     ok(status == Ok, "GdipGetImageType error %d\n", status);
3130 
3131     refcount = obj_refcount(stream);
3132     if (image_type == ImageTypeBitmap)
3133         ok(refcount > 1, "expected stream refcount > 1, got %d\n", refcount);
3134     else
3135         ok(refcount == 1, "expected stream refcount 1, got %d\n", refcount);
3136     old_refcount = refcount;
3137 
3138     status = GdipCloneImage(image, &clone);
3139     ok(status == Ok, "GdipCloneImage error %d\n", status);
3140     refcount = obj_refcount(stream);
3141     ok(refcount == old_refcount, "expected stream refcount %d, got %d\n", old_refcount, refcount);
3142     status = GdipDisposeImage(clone);
3143     ok(status == Ok, "GdipDisposeImage error %d\n", status);
3144     refcount = obj_refcount(stream);
3145     ok(refcount == old_refcount, "expected stream refcount %d, got %d\n", old_refcount, refcount);
3146 
3147     refcount = IStream_Release(stream);
3148     if (image_type == ImageTypeBitmap)
3149         ok(refcount >= 1, "expected stream refcount != 0\n");
3150     else
3151         ok(refcount == 0, "expected stream refcount 0, got %d\n", refcount);
3152 
3153     return image;
3154 }
3155 
3156 static void test_image_properties(void)
3157 {
3158     static const struct test_data
3159     {
3160         const BYTE *image_data;
3161         UINT image_size;
3162         ImageType image_type;
3163         UINT prop_count;
3164         UINT prop_count2; /* if win7 behaves differently */
3165         /* 1st property attributes */
3166         UINT prop_size;
3167         UINT prop_size2; /* if win7 behaves differently */
3168         UINT prop_id;
3169         UINT prop_id2; /* if win7 behaves differently */
3170     }
3171     td[] =
3172     {
3173         { pngimage, sizeof(pngimage), ImageTypeBitmap, 4, ~0, 1, 20, 0x5110, 0x132 },
3174         { jpgimage, sizeof(jpgimage), ImageTypeBitmap, 2, ~0, 128, 0, 0x5090, 0x5091 },
3175         { tiffimage, sizeof(tiffimage), ImageTypeBitmap, 16, 0, 4, 0, 0xfe, 0 },
3176         { bmpimage, sizeof(bmpimage), ImageTypeBitmap, 0, 0, 0, 0, 0, 0 },
3177         { wmfimage, sizeof(wmfimage), ImageTypeMetafile, 0, 0, 0, 0, 0, 0 }
3178     };
3179     GpStatus status;
3180     GpImage *image;
3181     UINT prop_count, prop_size, i;
3182     PROPID prop_id[16] = { 0 };
3183     ImageType image_type;
3184     union
3185     {
3186         PropertyItem data;
3187         char buf[256];
3188     } item;
3189 
3190     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3191     {
3192         image = load_image(td[i].image_data, td[i].image_size);
3193         if (!image)
3194         {
3195             trace("%u: failed to load image data\n", i);
3196             continue;
3197         }
3198 
3199         status = GdipGetImageType(image, &image_type);
3200         ok(status == Ok, "%u: GdipGetImageType error %d\n", i, status);
3201         ok(td[i].image_type == image_type, "%u: expected image_type %d, got %d\n",
3202            i, td[i].image_type, image_type);
3203 
3204         status = GdipGetPropertyCount(image, &prop_count);
3205         ok(status == Ok, "%u: GdipGetPropertyCount error %d\n", i, status);
3206         todo_wine_if(td[i].image_data == pngimage || td[i].image_data == jpgimage)
3207         ok(td[i].prop_count == prop_count || td[i].prop_count2 == prop_count,
3208            " %u: expected property count %u or %u, got %u\n",
3209            i, td[i].prop_count, td[i].prop_count2, prop_count);
3210 
3211         status = GdipGetPropertyItemSize(NULL, 0, &prop_size);
3212         expect(InvalidParameter, status);
3213         status = GdipGetPropertyItemSize(image, 0, NULL);
3214         expect(InvalidParameter, status);
3215         status = GdipGetPropertyItemSize(image, 0, &prop_size);
3216         if (image_type == ImageTypeMetafile)
3217             expect(NotImplemented, status);
3218         else
3219             expect(PropertyNotFound, status);
3220 
3221         status = GdipGetPropertyItem(NULL, 0, 0, &item.data);
3222         expect(InvalidParameter, status);
3223         status = GdipGetPropertyItem(image, 0, 0, NULL);
3224         expect(InvalidParameter, status);
3225         status = GdipGetPropertyItem(image, 0, 0, &item.data);
3226         if (image_type == ImageTypeMetafile)
3227             expect(NotImplemented, status);
3228         else
3229             expect(PropertyNotFound, status);
3230 
3231         /* FIXME: remove once Wine is fixed */
3232         if (td[i].prop_count != prop_count)
3233         {
3234             GdipDisposeImage(image);
3235             continue;
3236         }
3237 
3238         status = GdipGetPropertyIdList(NULL, prop_count, prop_id);
3239         expect(InvalidParameter, status);
3240         status = GdipGetPropertyIdList(image, prop_count, NULL);
3241         expect(InvalidParameter, status);
3242         status = GdipGetPropertyIdList(image, 0, prop_id);
3243         if (image_type == ImageTypeMetafile)
3244             expect(NotImplemented, status);
3245         else if (prop_count == 0)
3246             expect(Ok, status);
3247         else
3248             expect(InvalidParameter, status);
3249         status = GdipGetPropertyIdList(image, prop_count - 1, prop_id);
3250         if (image_type == ImageTypeMetafile)
3251             expect(NotImplemented, status);
3252         else
3253             expect(InvalidParameter, status);
3254         status = GdipGetPropertyIdList(image, prop_count + 1, prop_id);
3255         if (image_type == ImageTypeMetafile)
3256             expect(NotImplemented, status);
3257         else
3258             expect(InvalidParameter, status);
3259         status = GdipGetPropertyIdList(image, prop_count, prop_id);
3260         if (image_type == ImageTypeMetafile)
3261             expect(NotImplemented, status);
3262         else
3263         {
3264             expect(Ok, status);
3265             if (prop_count != 0)
3266                 ok(td[i].prop_id == prop_id[0] || td[i].prop_id2 == prop_id[0],
3267                    " %u: expected property id %#x or %#x, got %#x\n",
3268                    i, td[i].prop_id, td[i].prop_id2, prop_id[0]);
3269         }
3270 
3271         if (status == Ok)
3272         {
3273             status = GdipGetPropertyItemSize(image, prop_id[0], &prop_size);
3274             if (prop_count == 0)
3275                 expect(PropertyNotFound, status);
3276             else
3277             {
3278                 expect(Ok, status);
3279 
3280                 assert(sizeof(item) >= prop_size);
3281                 ok(prop_size > sizeof(PropertyItem), "%u: got too small prop_size %u\n",
3282                    i, prop_size);
3283                 ok(td[i].prop_size + sizeof(PropertyItem) == prop_size ||
3284                    td[i].prop_size2 + sizeof(PropertyItem) == prop_size,
3285                    " %u: expected property size %u or %u, got %u\n",
3286                    i, td[i].prop_size, td[i].prop_size2, prop_size);
3287 
3288                 status = GdipGetPropertyItem(image, prop_id[0], 0, &item.data);
3289                 ok(status == InvalidParameter || status == GenericError /* Win7 */,
3290                    "%u: expected InvalidParameter, got %d\n", i, status);
3291                 status = GdipGetPropertyItem(image, prop_id[0], prop_size - 1, &item.data);
3292                 ok(status == InvalidParameter || status == GenericError /* Win7 */,
3293                    "%u: expected InvalidParameter, got %d\n", i, status);
3294                 status = GdipGetPropertyItem(image, prop_id[0], prop_size + 1, &item.data);
3295                 ok(status == InvalidParameter || status == GenericError /* Win7 */,
3296                    "%u: expected InvalidParameter, got %d\n", i, status);
3297                 status = GdipGetPropertyItem(image, prop_id[0], prop_size, &item.data);
3298                 expect(Ok, status);
3299                 ok(prop_id[0] == item.data.id,
3300                    "%u: expected property id %#x, got %#x\n", i, prop_id[0], item.data.id);
3301             }
3302         }
3303 
3304         GdipDisposeImage(image);
3305     }
3306 }
3307 
3308 #define IFD_BYTE      1
3309 #define IFD_ASCII     2
3310 #define IFD_SHORT     3
3311 #define IFD_LONG      4
3312 #define IFD_RATIONAL  5
3313 #define IFD_SBYTE     6
3314 #define IFD_UNDEFINED 7
3315 #define IFD_SSHORT    8
3316 #define IFD_SLONG     9
3317 #define IFD_SRATIONAL 10
3318 #define IFD_FLOAT     11
3319 #define IFD_DOUBLE    12
3320 
3321 #ifndef PropertyTagTypeSByte
3322 #define PropertyTagTypeSByte  6
3323 #define PropertyTagTypeSShort 8
3324 #define PropertyTagTypeFloat  11
3325 #define PropertyTagTypeDouble 12
3326 #endif
3327 
3328 static UINT documented_type(UINT type)
3329 {
3330     switch (type)
3331     {
3332     case PropertyTagTypeSByte: return PropertyTagTypeByte;
3333     case PropertyTagTypeSShort: return PropertyTagTypeShort;
3334     case PropertyTagTypeFloat: return PropertyTagTypeUndefined;
3335     case PropertyTagTypeDouble: return PropertyTagTypeUndefined;
3336     default: return type;
3337     }
3338 }
3339 
3340 #include "pshpack2.h"
3341 struct IFD_entry
3342 {
3343     SHORT id;
3344     SHORT type;
3345     ULONG count;
3346     LONG  value;
3347 };
3348 
3349 struct IFD_rational
3350 {
3351     LONG numerator;
3352     LONG denominator;
3353 };
3354 
3355 static const struct tiff_data
3356 {
3357     USHORT byte_order;
3358     USHORT version;
3359     ULONG  dir_offset;
3360     USHORT number_of_entries;
3361     struct IFD_entry entry[40];
3362     ULONG next_IFD;
3363     struct IFD_rational xres;
3364     DOUBLE double_val;
3365     struct IFD_rational srational_val;
3366     char string[14];
3367     SHORT short_val[4];
3368     LONG long_val[2];
3369     FLOAT float_val[2];
3370     struct IFD_rational rational[3];
3371     BYTE pixel_data[4];
3372 } TIFF_data =
3373 {
3374 #ifdef WORDS_BIGENDIAN
3375     'M' | 'M' << 8,
3376 #else
3377     'I' | 'I' << 8,
3378 #endif
3379     42,
3380     FIELD_OFFSET(struct tiff_data, number_of_entries),
3381     31,
3382     {
3383         { 0xff,  IFD_SHORT, 1, 0 }, /* SUBFILETYPE */
3384         { 0x100, IFD_LONG, 1, 1 }, /* IMAGEWIDTH */
3385         { 0x101, IFD_LONG, 1, 1 }, /* IMAGELENGTH */
3386         { 0x102, IFD_SHORT, 1, 1 }, /* BITSPERSAMPLE */
3387         { 0x103, IFD_SHORT, 1, 1 }, /* COMPRESSION: XP doesn't accept IFD_LONG here */
3388         { 0x106, IFD_SHORT, 1, 1 }, /* PHOTOMETRIC */
3389         { 0x111, IFD_LONG, 1, FIELD_OFFSET(struct tiff_data, pixel_data) }, /* STRIPOFFSETS */
3390         { 0x115, IFD_SHORT, 1, 1 }, /* SAMPLESPERPIXEL */
3391         { 0x116, IFD_LONG, 1, 1 }, /* ROWSPERSTRIP */
3392         { 0x117, IFD_LONG, 1, 1 }, /* STRIPBYTECOUNT */
3393         { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_data, xres) },
3394         { 0x11b, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_data, xres) },
3395         { 0x128, IFD_SHORT, 1, 2 }, /* RESOLUTIONUNIT */
3396         { 0xf001, IFD_BYTE, 1, 0x11223344 },
3397         { 0xf002, IFD_BYTE, 4, 0x11223344 },
3398         { 0xf003, IFD_SBYTE, 1, 0x11223344 },
3399         { 0xf004, IFD_SSHORT, 1, 0x11223344 },
3400         { 0xf005, IFD_SSHORT, 2, 0x11223344 },
3401         { 0xf006, IFD_SLONG, 1, 0x11223344 },
3402         { 0xf007, IFD_FLOAT, 1, 0x11223344 },
3403         { 0xf008, IFD_DOUBLE, 1, FIELD_OFFSET(struct tiff_data, double_val) },
3404         { 0xf009, IFD_SRATIONAL, 1, FIELD_OFFSET(struct tiff_data, srational_val) },
3405         { 0xf00a, IFD_BYTE, 13, FIELD_OFFSET(struct tiff_data, string) },
3406         { 0xf00b, IFD_SSHORT, 4, FIELD_OFFSET(struct tiff_data, short_val) },
3407         { 0xf00c, IFD_SLONG, 2, FIELD_OFFSET(struct tiff_data, long_val) },
3408         { 0xf00e, IFD_ASCII, 13, FIELD_OFFSET(struct tiff_data, string) },
3409         { 0xf00f, IFD_ASCII, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
3410         { 0xf010, IFD_UNDEFINED, 13, FIELD_OFFSET(struct tiff_data, string) },
3411         { 0xf011, IFD_UNDEFINED, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
3412         /* Some gdiplus versions ignore these fields.
3413         { 0xf012, IFD_BYTE, 0, 0x11223344 },
3414         { 0xf013, IFD_SHORT, 0, 0x11223344 },
3415         { 0xf014, IFD_LONG, 0, 0x11223344 },
3416         { 0xf015, IFD_FLOAT, 0, 0x11223344 },*/
3417         { 0xf016, IFD_SRATIONAL, 3, FIELD_OFFSET(struct tiff_data, rational) },
3418         /* Win7 before SP1 doesn't recognize this field, everybody else does. */
3419         { 0xf017, IFD_FLOAT, 2, FIELD_OFFSET(struct tiff_data, float_val) },
3420     },
3421     0,
3422     { 900, 3 },
3423     1234567890.0987654321,
3424     { 0x1a2b3c4d, 0x5a6b7c8d },
3425     "Hello World!",
3426     { 0x0101, 0x0202, 0x0303, 0x0404 },
3427     { 0x11223344, 0x55667788 },
3428     { (FLOAT)1234.5678, (FLOAT)8765.4321 },
3429     { { 0x01020304, 0x05060708 }, { 0x10203040, 0x50607080 }, { 0x11223344, 0x55667788 } },
3430     { 0x11, 0x22, 0x33, 0 }
3431 };
3432 #include "poppack.h"
3433 
3434 static void test_tiff_properties(void)
3435 {
3436     static const struct test_data
3437     {
3438         ULONG type, id, length;
3439         const BYTE value[24];
3440     } td[31] =
3441     {
3442         { PropertyTagTypeShort, 0xff, 2, { 0 } },
3443         { PropertyTagTypeLong, 0x100, 4, { 1 } },
3444         { PropertyTagTypeLong, 0x101, 4, { 1 } },
3445         { PropertyTagTypeShort, 0x102, 2, { 1 } },
3446         { PropertyTagTypeShort, 0x103, 2, { 1 } },
3447         { PropertyTagTypeShort, 0x106, 2, { 1 } },
3448         { PropertyTagTypeLong, 0x111, 4, { 0x44,0x02 } },
3449         { PropertyTagTypeShort, 0x115, 2, { 1 } },
3450         { PropertyTagTypeLong, 0x116, 4, { 1 } },
3451         { PropertyTagTypeLong, 0x117, 4, { 1 } },
3452         { PropertyTagTypeRational, 0x11a, 8, { 0x84,0x03,0,0,0x03 } },
3453         { PropertyTagTypeRational, 0x11b, 8, { 0x84,0x03,0,0,0x03 } },
3454         { PropertyTagTypeShort, 0x128, 2, { 2 } },
3455         { PropertyTagTypeByte, 0xf001, 1, { 0x44 } },
3456         { PropertyTagTypeByte, 0xf002, 4, { 0x44,0x33,0x22,0x11 } },
3457         { PropertyTagTypeSByte, 0xf003, 1, { 0x44 } },
3458         { PropertyTagTypeSShort, 0xf004, 2, { 0x44,0x33 } },
3459         { PropertyTagTypeSShort, 0xf005, 4, { 0x44,0x33,0x22,0x11 } },
3460         { PropertyTagTypeSLONG, 0xf006, 4, { 0x44,0x33,0x22,0x11 } },
3461         { PropertyTagTypeFloat, 0xf007, 4, { 0x44,0x33,0x22,0x11 } },
3462         { PropertyTagTypeDouble, 0xf008, 8, { 0x2c,0x52,0x86,0xb4,0x80,0x65,0xd2,0x41 } },
3463         { PropertyTagTypeSRational, 0xf009, 8, { 0x4d, 0x3c, 0x2b, 0x1a, 0x8d, 0x7c, 0x6b, 0x5a } },
3464         { PropertyTagTypeByte, 0xf00a, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
3465         { PropertyTagTypeSShort, 0xf00b, 8, { 0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04 } },
3466         { PropertyTagTypeSLONG, 0xf00c, 8, { 0x44,0x33,0x22,0x11,0x88,0x77,0x66,0x55 } },
3467         { PropertyTagTypeASCII, 0xf00e, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
3468         { PropertyTagTypeASCII, 0xf00f, 5, { 'a','b','c','d' } },
3469         { PropertyTagTypeUndefined, 0xf010, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
3470         { PropertyTagTypeUndefined, 0xf011, 4, { 'a','b','c','d' } },
3471         { PropertyTagTypeSRational, 0xf016, 24,
3472           { 0x04,0x03,0x02,0x01,0x08,0x07,0x06,0x05,
3473             0x40,0x30,0x20,0x10,0x80,0x70,0x60,0x50,
3474             0x44,0x33,0x22,0x11,0x88,0x77,0x66,0x55 } },
3475         /* Win7 before SP1 doesn't recognize this field, everybody else does. */
3476         { PropertyTagTypeFloat, 0xf017, 8, { 0x2b,0x52,0x9a,0x44,0xba,0xf5,0x08,0x46 } },
3477     };
3478     GpStatus status;
3479     GpImage *image;
3480     GUID guid;
3481     UINT dim_count, frame_count, prop_count, prop_size, i;
3482     PROPID *prop_id;
3483     PropertyItem *prop_item;
3484 
3485     image = load_image((const BYTE *)&TIFF_data, sizeof(TIFF_data));
3486     if (!image)
3487     {
3488         win_skip("Failed to load TIFF image data. Might not be supported. Skipping.\n");
3489         return;
3490     }
3491 
3492     status = GdipImageGetFrameDimensionsCount(image, &dim_count);
3493     expect(Ok, status);
3494     expect(1, dim_count);
3495 
3496     status = GdipImageGetFrameDimensionsList(image, &guid, 1);
3497     expect(Ok, status);
3498     expect_guid(&FrameDimensionPage, &guid, __LINE__, FALSE);
3499 
3500     frame_count = 0xdeadbeef;
3501     status = GdipImageGetFrameCount(image, &guid, &frame_count);
3502     expect(Ok, status);
3503     expect(1, frame_count);
3504 
3505     prop_count = 0xdeadbeef;
3506     status = GdipGetPropertyCount(image, &prop_count);
3507     expect(Ok, status);
3508     ok(prop_count == sizeof(td)/sizeof(td[0]) ||
3509        broken(prop_count == sizeof(td)/sizeof(td[0]) - 1) /* Win7 SP0 */,
3510        "expected property count %u, got %u\n", (UINT)(sizeof(td)/sizeof(td[0])), prop_count);
3511 
3512     prop_id = HeapAlloc(GetProcessHeap(), 0, prop_count * sizeof(*prop_id));
3513 
3514     status = GdipGetPropertyIdList(image, prop_count, prop_id);
3515     expect(Ok, status);
3516 
3517     for (i = 0; i < prop_count; i++)
3518     {
3519         status = GdipGetPropertyItemSize(image, prop_id[i], &prop_size);
3520         expect(Ok, status);
3521         if (status != Ok) break;
3522         ok(prop_size > sizeof(*prop_item), "%u: too small item length %u\n", i, prop_size);
3523 
3524         prop_item = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, prop_size);
3525         status = GdipGetPropertyItem(image, prop_id[i], prop_size, prop_item);
3526         expect(Ok, status);
3527         ok(prop_item->value == prop_item + 1, "expected item->value %p, got %p\n", prop_item + 1, prop_item->value);
3528         ok(td[i].type == prop_item->type ||
3529            /* Win7 stopped using proper but not documented types, and it
3530               looks broken since TypeFloat and TypeDouble now reported as
3531               TypeUndefined, and signed types reported as unsigned. */
3532            broken(prop_item->type == documented_type(td[i].type)),
3533             "%u: expected type %u, got %u\n", i, td[i].type, prop_item->type);
3534         ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id);
3535         prop_size -= sizeof(*prop_item);
3536         ok(prop_item->length == prop_size, "%u: expected length %u, got %u\n", i, prop_size, prop_item->length);
3537         ok(td[i].length == prop_item->length || broken(td[i].id == 0xf00f && td[i].length == prop_item->length+1) /* XP */,
3538            "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length);
3539         ok(td[i].length == prop_size || broken(td[i].id == 0xf00f && td[i].length == prop_size+1) /* XP */,
3540            "%u: expected length %u, got %u\n", i, td[i].length, prop_size);
3541         if (td[i].length == prop_item->length)
3542         {
3543             int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0;
3544             ok(match || broken(td[i].length <= 4 && !match), "%u: data mismatch\n", i);
3545             if (!match)
3546             {
3547                 UINT j;
3548                 BYTE *data = prop_item->value;
3549                 trace("id %#x:", prop_item->id);
3550                 for (j = 0; j < prop_item->length; j++)
3551                     trace(" %02x", data[j]);
3552                 trace("\n");
3553             }
3554         }
3555         HeapFree(GetProcessHeap(), 0, prop_item);
3556     }
3557 
3558     HeapFree(GetProcessHeap(), 0, prop_id);
3559 
3560     GdipDisposeImage(image);
3561 }
3562 
3563 static void test_GdipGetAllPropertyItems(void)
3564 {
3565     static const struct test_data
3566     {
3567         ULONG type, id, length;
3568         BYTE value[32];
3569     } td[16] =
3570     {
3571         { PropertyTagTypeLong, 0xfe, 4, { 0 } },
3572         { PropertyTagTypeShort, 0x100, 2, { 1 } },
3573         { PropertyTagTypeShort, 0x101, 2, { 1 } },
3574         { PropertyTagTypeShort, 0x102, 6, { 8,0,8,0,8,0 } },
3575         { PropertyTagTypeShort, 0x103, 2, { 1 } },
3576         { PropertyTagTypeShort, 0x106, 2, { 2,0 } },
3577         { PropertyTagTypeASCII, 0x10d, 27, "/home/meh/Desktop/test.tif" },
3578         { PropertyTagTypeLong, 0x111, 4, { 8,0,0,0 } },
3579         { PropertyTagTypeShort, 0x112, 2, { 1 } },
3580         { PropertyTagTypeShort, 0x115, 2, { 3,0 } },
3581         { PropertyTagTypeShort, 0x116, 2, { 0x40,0 } },
3582         { PropertyTagTypeLong, 0x117, 4, { 3,0,0,0 } },
3583         { PropertyTagTypeRational, 0x11a, 8, { 0,0,0,72,0,0,0,1 } },
3584         { PropertyTagTypeRational, 0x11b, 8, { 0,0,0,72,0,0,0,1 } },
3585         { PropertyTagTypeShort, 0x11c, 2, { 1 } },
3586         { PropertyTagTypeShort, 0x128, 2, { 2 } }
3587     };
3588     GpStatus status;
3589     GpImage *image;
3590     GUID guid;
3591     UINT dim_count, frame_count, prop_count, prop_size, i;
3592     UINT total_size, total_count;
3593     PROPID *prop_id;
3594     PropertyItem *prop_item;
3595     const char *item_data;
3596 
3597     image = load_image(tiffimage, sizeof(tiffimage));
3598     ok(image != 0, "Failed to load TIFF image data\n");
3599     if (!image) return;
3600 
3601     dim_count = 0xdeadbeef;
3602     status = GdipImageGetFrameDimensionsCount(image, &dim_count);
3603     expect(Ok, status);
3604     expect(1, dim_count);
3605 
3606     status = GdipImageGetFrameDimensionsList(image, &guid, 1);
3607     expect(Ok, status);
3608     expect_guid(&FrameDimensionPage, &guid, __LINE__, FALSE);
3609 
3610     frame_count = 0xdeadbeef;
3611     status = GdipImageGetFrameCount(image, &guid, &frame_count);
3612     expect(Ok, status);
3613     expect(1, frame_count);
3614 
3615     prop_count = 0xdeadbeef;
3616     status = GdipGetPropertyCount(image, &prop_count);
3617     expect(Ok, status);
3618     ok(prop_count == sizeof(td)/sizeof(td[0]),
3619        "expected property count %u, got %u\n", (UINT)(sizeof(td)/sizeof(td[0])), prop_count);
3620 
3621     prop_id = HeapAlloc(GetProcessHeap(), 0, prop_count * sizeof(*prop_id));
3622 
3623     status = GdipGetPropertyIdList(image, prop_count, prop_id);
3624     expect(Ok, status);
3625 
3626     prop_size = 0;
3627     for (i = 0; i < prop_count; i++)
3628     {
3629         UINT size;
3630         status = GdipGetPropertyItemSize(image, prop_id[i], &size);
3631         expect(Ok, status);
3632         if (status != Ok) break;
3633         ok(size > sizeof(*prop_item), "%u: too small item length %u\n", i, size);
3634 
3635         prop_size += size;
3636 
3637         prop_item = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3638         status = GdipGetPropertyItem(image, prop_id[i], size, prop_item);
3639         expect(Ok, status);
3640         ok(prop_item->value == prop_item + 1, "expected item->value %p, got %p\n", prop_item + 1, prop_item->value);
3641         ok(td[i].type == prop_item->type,
3642             "%u: expected type %u, got %u\n", i, td[i].type, prop_item->type);
3643         ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id);
3644         size -= sizeof(*prop_item);
3645         ok(prop_item->length == size, "%u: expected length %u, got %u\n", i, size, prop_item->length);
3646         ok(td[i].length == prop_item->length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length);
3647         if (td[i].length == prop_item->length)
3648         {
3649             int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0;
3650             ok(match, "%u: data mismatch\n", i);
3651             if (!match)
3652             {
3653                 UINT j;
3654                 BYTE *data = prop_item->value;
3655                 trace("id %#x:", prop_item->id);
3656                 for (j = 0; j < prop_item->length; j++)
3657                     trace(" %02x", data[j]);
3658                 trace("\n");
3659             }
3660         }
3661         HeapFree(GetProcessHeap(), 0, prop_item);
3662     }
3663 
3664     HeapFree(GetProcessHeap(), 0, prop_id);
3665 
3666     status = GdipGetPropertySize(NULL, &total_size, &total_count);
3667     expect(InvalidParameter, status);
3668     status = GdipGetPropertySize(image, &total_size, NULL);
3669     expect(InvalidParameter, status);
3670     status = GdipGetPropertySize(image, NULL, &total_count);
3671     expect(InvalidParameter, status);
3672     status = GdipGetPropertySize(image, NULL, NULL);
3673     expect(InvalidParameter, status);
3674     total_size = 0xdeadbeef;
3675     total_count = 0xdeadbeef;
3676     status = GdipGetPropertySize(image, &total_size, &total_count);
3677     expect(Ok, status);
3678     ok(prop_count == total_count,
3679        "expected total property count %u, got %u\n", prop_count, total_count);
3680     ok(prop_size == total_size,
3681        "expected total property size %u, got %u\n", prop_size, total_size);
3682 
3683     prop_item = HeapAlloc(GetProcessHeap(), 0, prop_size);
3684 
3685     status = GdipGetAllPropertyItems(image, 0, prop_count, prop_item);
3686     expect(InvalidParameter, status);
3687     status = GdipGetAllPropertyItems(image, prop_size, 1, prop_item);
3688     expect(InvalidParameter, status);
3689     status = GdipGetAllPropertyItems(image, prop_size, prop_count, NULL);
3690     expect(InvalidParameter, status);
3691     status = GdipGetAllPropertyItems(image, prop_size, prop_count, NULL);
3692     expect(InvalidParameter, status);
3693     status = GdipGetAllPropertyItems(image, 0, 0, NULL);
3694     expect(InvalidParameter, status);
3695     status = GdipGetAllPropertyItems(image, prop_size + 1, prop_count, prop_item);
3696     expect(InvalidParameter, status);
3697     status = GdipGetAllPropertyItems(image, prop_size, prop_count, prop_item);
3698     expect(Ok, status);
3699 
3700     item_data = (const char *)(prop_item + prop_count);
3701     for (i = 0; i < prop_count; i++)
3702     {
3703         ok(prop_item[i].value == item_data, "%u: expected value %p, got %p\n",
3704            i, item_data, prop_item[i].value);
3705         ok(td[i].type == prop_item[i].type,
3706             "%u: expected type %u, got %u\n", i, td[i].type, prop_item[i].type);
3707         ok(td[i].id == prop_item[i].id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item[i].id);
3708         ok(td[i].length == prop_item[i].length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item[i].length);
3709         if (td[i].length == prop_item[i].length)
3710         {
3711             int match = memcmp(td[i].value, prop_item[i].value, td[i].length) == 0;
3712             ok(match, "%u: data mismatch\n", i);
3713             if (!match)
3714             {
3715                 UINT j;
3716                 BYTE *data = prop_item[i].value;
3717                 trace("id %#x:", prop_item[i].id);
3718                 for (j = 0; j < prop_item[i].length; j++)
3719                     trace(" %02x", data[j]);
3720                 trace("\n");
3721             }
3722         }
3723         item_data += prop_item[i].length;
3724     }
3725 
3726     HeapFree(GetProcessHeap(), 0, prop_item);
3727 
3728     GdipDisposeImage(image);
3729 }
3730 
3731 static void test_tiff_palette(void)
3732 {
3733     GpStatus status;
3734     GpImage *image;
3735     PixelFormat format;
3736     INT size;
3737     struct
3738     {
3739         ColorPalette pal;
3740         ARGB entry[256];
3741     } palette;
3742     ARGB *entries = palette.pal.Entries;
3743 
3744     /* 1bpp TIFF without palette */
3745     image = load_image((const BYTE *)&TIFF_data, sizeof(TIFF_data));
3746     if (!image)
3747     {
3748         win_skip("Failed to load TIFF image data. Might not be supported. Skipping.\n");
3749         return;
3750     }
3751 
3752     status = GdipGetImagePixelFormat(image, &format);
3753     expect(Ok, status);
3754     ok(format == PixelFormat1bppIndexed, "expected PixelFormat1bppIndexed, got %#x\n", format);
3755 
3756     status = GdipGetImagePaletteSize(image, &size);
3757     ok(status == Ok || broken(status == GenericError), /* XP */
3758        "GdipGetImagePaletteSize error %d\n", status);
3759     if (status == GenericError)
3760     {
3761         GdipDisposeImage(image);
3762         return;
3763     }
3764     expect(sizeof(ColorPalette) + sizeof(ARGB), size);
3765 
3766     status = GdipGetImagePalette(image, &palette.pal, size);
3767     expect(Ok, status);
3768     expect(0, palette.pal.Flags);
3769     expect(2, palette.pal.Count);
3770     if (palette.pal.Count == 2)
3771     {
3772         ok(entries[0] == 0xff000000, "expected 0xff000000, got %#x\n", entries[0]);
3773         ok(entries[1] == 0xffffffff, "expected 0xffffffff, got %#x\n", entries[1]);
3774     }
3775 
3776     GdipDisposeImage(image);
3777 }
3778 
3779 static void test_bitmapbits(void)
3780 {
3781     /* 8 x 2 bitmap */
3782     static const BYTE pixels_24[48] =
3783     {
3784         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0,
3785         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0,
3786         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0,
3787         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0
3788     };
3789     static const BYTE pixels_00[48] =
3790     {
3791         0,0,0, 0,0,0, 0,0,0, 0,0,0,
3792         0,0,0, 0,0,0, 0,0,0, 0,0,0,
3793         0,0,0, 0,0,0, 0,0,0, 0,0,0,
3794         0,0,0, 0,0,0, 0,0,0, 0,0,0
3795     };
3796     static const BYTE pixels_24_77[64] =
3797     {
3798         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0,
3799         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0,
3800         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3801         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0,
3802         0xff,0xff,0xff, 0,0,0, 0xff,0xff,0xff, 0,0,0,
3803         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77
3804     };
3805     static const BYTE pixels_77[64] =
3806     {
3807         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3808         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3809         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3810         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3811         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3812         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3813         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3814         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77
3815     };
3816     static const BYTE pixels_8[16] =
3817     {
3818         0x01,0,0x01,0,0x01,0,0x01,0,
3819         0x01,0,0x01,0,0x01,0,0x01,0
3820     };
3821     static const BYTE pixels_8_77[64] =
3822     {
3823         0x01,0,0x01,0,0x01,0,0x01,0,
3824         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3825         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3826         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3827         0x01,0,0x01,0,0x01,0,0x01,0,
3828         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3829         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3830         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77
3831     };
3832     static const BYTE pixels_1_77[64] =
3833     {
3834         0xaa,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3835         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3836         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3837         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3838         0xaa,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3839         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3840         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
3841         0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77
3842     };
3843     static const BYTE pixels_1[8] = {0xaa,0,0,0,0xaa,0,0,0};
3844     static const struct test_data
3845     {
3846         PixelFormat format;
3847         UINT bpp;
3848         ImageLockMode mode;
3849         UINT stride, size;
3850         const BYTE *pixels;
3851         const BYTE *pixels_unlocked;
3852     } td[] =
3853     {
3854         /* 0 */
3855         { PixelFormat24bppRGB, 24, 0xfff0, 24, 48, pixels_24, pixels_00 },
3856 
3857         { PixelFormat24bppRGB, 24, 0, 24, 48, pixels_24, pixels_00 },
3858         { PixelFormat24bppRGB, 24, ImageLockModeRead, 24, 48, pixels_24, pixels_00 },
3859         { PixelFormat24bppRGB, 24, ImageLockModeWrite, 24, 48, pixels_24, pixels_00 },
3860         { PixelFormat24bppRGB, 24, ImageLockModeRead|ImageLockModeWrite, 24, 48, pixels_24, pixels_00 },
3861         { PixelFormat24bppRGB, 24, ImageLockModeRead|ImageLockModeUserInputBuf, 32, 64, pixels_24_77, pixels_24 },
3862         { PixelFormat24bppRGB, 24, ImageLockModeWrite|ImageLockModeUserInputBuf, 32, 64, pixels_77, pixels_00 },
3863         { PixelFormat24bppRGB, 24, ImageLockModeUserInputBuf, 32, 64, pixels_77, pixels_24 },
3864         /* 8 */
3865         { PixelFormat8bppIndexed, 8, 0, 8, 16, pixels_8, pixels_24 },
3866         { PixelFormat8bppIndexed, 8, ImageLockModeRead, 8, 16, pixels_8, pixels_24 },
3867         { PixelFormat8bppIndexed, 8, ImageLockModeWrite, 8, 16, pixels_8, pixels_00 },
3868         { PixelFormat8bppIndexed, 8, ImageLockModeRead|ImageLockModeWrite, 8, 16, pixels_8, pixels_00 },
3869         { PixelFormat8bppIndexed, 8, ImageLockModeRead|ImageLockModeUserInputBuf, 32, 64, pixels_8_77, pixels_24 },
3870         { PixelFormat8bppIndexed, 8, ImageLockModeWrite|ImageLockModeUserInputBuf, 32, 64, pixels_77, pixels_00 },
3871         { PixelFormat8bppIndexed, 8, ImageLockModeUserInputBuf, 32, 64, pixels_77, pixels_24 },
3872         /* 15 */
3873         { PixelFormat1bppIndexed, 1, 0, 4, 8, pixels_1, pixels_24 },
3874         { PixelFormat1bppIndexed, 1, ImageLockModeRead, 4, 8, pixels_1, pixels_24 },
3875         { PixelFormat1bppIndexed, 1, ImageLockModeWrite, 4, 8, pixels_1, pixels_00 },
3876         { PixelFormat1bppIndexed, 1, ImageLockModeRead|ImageLockModeWrite, 4, 8, pixels_1, pixels_00 },
3877         { PixelFormat1bppIndexed, 1, ImageLockModeRead|ImageLockModeUserInputBuf, 32, 64, pixels_1_77, pixels_24 },
3878         { PixelFormat1bppIndexed, 1, ImageLockModeWrite|ImageLockModeUserInputBuf, 32, 64, pixels_77, pixels_00 },
3879         { PixelFormat1bppIndexed, 1, ImageLockModeUserInputBuf, 32, 64, pixels_77, pixels_24 },
3880     };
3881     BYTE buf[64];
3882     GpStatus status;
3883     GpBitmap *bitmap;
3884     UINT i;
3885     BitmapData data;
3886     struct
3887     {
3888         ColorPalette pal;
3889         ARGB entries[1];
3890     } palette;
3891     ARGB *entries = palette.pal.Entries;
3892 
3893     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3894     {
3895         BYTE pixels[sizeof(pixels_24)];
3896         memcpy(pixels, pixels_24, sizeof(pixels_24));
3897         status = GdipCreateBitmapFromScan0(8, 2, 24, PixelFormat24bppRGB, pixels, &bitmap);
3898         expect(Ok, status);
3899 
3900         /* associate known palette with pixel data */
3901         palette.pal.Flags = PaletteFlagsGrayScale;
3902         palette.pal.Count = 2;
3903         entries[0] = 0xff000000;
3904         entries[1] = 0xffffffff;
3905         status = GdipSetImagePalette((GpImage *)bitmap, &palette.pal);
3906         expect(Ok, status);
3907 
3908         memset(&data, 0xfe, sizeof(data));
3909         if (td[i].mode & ImageLockModeUserInputBuf)
3910         {
3911             memset(buf, 0x77, sizeof(buf));
3912             data.Scan0 = buf;
3913             data.Stride = 32;
3914         }
3915         status = GdipBitmapLockBits(bitmap, NULL, td[i].mode, td[i].format, &data);
3916         ok(status == Ok || broken(status == InvalidParameter) /* XP */, "%u: GdipBitmapLockBits error %d\n", i, status);
3917         if (status != Ok)
3918         {
3919             GdipDisposeImage((GpImage *)bitmap);
3920             continue;
3921         }
3922         ok(data.Width == 8, "%u: expected 8, got %d\n", i, data.Width);
3923         ok(data.Height == 2, "%u: expected 2, got %d\n", i, data.Height);
3924         ok(td[i].stride == data.Stride, "%u: expected %d, got %d\n", i, td[i].stride, data.Stride);
3925         ok(td[i].format == data.PixelFormat, "%u: expected %d, got %d\n", i, td[i].format, data.PixelFormat);
3926         ok(td[i].size == data.Height * data.Stride, "%u: expected %d, got %d\n", i, td[i].size, data.Height * data.Stride);
3927         if (td[i].mode & ImageLockModeUserInputBuf)
3928             ok(data.Scan0 == buf, "%u: got wrong buffer\n", i);
3929         if (td[i].size == data.Height * data.Stride)
3930         {
3931             UINT j, match, width_bytes = (data.Width * td[i].bpp) / 8;
3932 
3933             match = 1;
3934             for (j = 0; j < data.Height; j++)
3935             {
3936                 if (memcmp((const BYTE *)data.Scan0 + j * data.Stride, td[i].pixels + j * data.Stride, width_bytes) != 0)
3937                 {
3938                     match = 0;
3939                     break;
3940                 }
3941             }
3942             if ((td[i].mode & (ImageLockModeRead|ImageLockModeUserInputBuf)) || td[i].format == PixelFormat24bppRGB)
3943             {
3944                 ok(match,
3945                    "%u: data should match\n", i);
3946                 if (!match)
3947                 {
3948                     BYTE *bits = data.Scan0;
3949                     trace("%u: data mismatch for format %#x:", i, td[i].format);
3950                     for (j = 0; j < td[i].size; j++)
3951                         trace(" %02x", bits[j]);
3952                     trace("\n");
3953                 }
3954             }
3955             else
3956                 ok(!match, "%u: data shouldn't match\n", i);
3957 
3958             memset(data.Scan0, 0, td[i].size);
3959         }
3960 
3961         status = GdipBitmapUnlockBits(bitmap, &data);
3962         ok(status == Ok, "%u: GdipBitmapUnlockBits error %d\n", i, status);
3963 
3964         memset(&data, 0xfe, sizeof(data));
3965         status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB, &data);
3966         ok(status == Ok, "%u: GdipBitmapLockBits error %d\n", i, status);
3967         ok(data.Width == 8, "%u: expected 8, got %d\n", i, data.Width);
3968         ok(data.Height == 2, "%u: expected 2, got %d\n", i, data.Height);
3969         ok(data.Stride == 24, "%u: expected 24, got %d\n", i, data.Stride);
3970         ok(data.PixelFormat == PixelFormat24bppRGB, "%u: got wrong pixel format %d\n", i, data.PixelFormat);
3971         ok(data.Height * data.Stride == 48, "%u: expected 48, got %d\n", i, data.Height * data.Stride);
3972         if (data.Height * data.Stride == 48)
3973         {
3974             int match = memcmp(data.Scan0, td[i].pixels_unlocked, 48) == 0;
3975             ok(match, "%u: data should match\n", i);
3976             if (!match)
3977             {
3978                 UINT j;
3979                 BYTE *bits = data.Scan0;
3980                 trace("%u: data mismatch for format %#x:", i, td[i].format);
3981                 for (j = 0; j < 48; j++)
3982                     trace(" %02x", bits[j]);
3983                 trace("\n");
3984             }
3985         }
3986 
3987         status = GdipBitmapUnlockBits(bitmap, &data);
3988         ok(status == Ok, "%u: GdipBitmapUnlockBits error %d\n", i, status);
3989 
3990         status = GdipDisposeImage((GpImage *)bitmap);
3991         expect(Ok, status);
3992     }
3993 }
3994 
3995 static void test_DrawImage(void)
3996 {
3997     BYTE black_1x1[4] = { 0,0,0,0 };
3998     BYTE white_2x2[16] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
3999                            0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
4000     BYTE black_2x2[16] = { 0,0,0,0,0,0,0xff,0xff,
4001                            0,0,0,0,0,0,0xff,0xff };
4002     GpStatus status;
4003     union
4004     {
4005         GpBitmap *bitmap;
4006         GpImage *image;
4007     } u1, u2;
4008     GpGraphics *graphics;
4009     int match;
4010 
4011     status = GdipCreateBitmapFromScan0(1, 1, 4, PixelFormat24bppRGB, black_1x1, &u1.bitmap);
4012     expect(Ok, status);
4013     status = GdipBitmapSetResolution(u1.bitmap, 100.0, 100.0);
4014     expect(Ok, status);
4015 
4016     status = GdipCreateBitmapFromScan0(2, 2, 8, PixelFormat24bppRGB, white_2x2, &u2.bitmap);
4017     expect(Ok, status);
4018     status = GdipBitmapSetResolution(u2.bitmap, 300.0, 300.0);
4019     expect(Ok, status);
4020     status = GdipGetImageGraphicsContext(u2.image, &graphics);
4021     expect(Ok, status);
4022     status = GdipSetInterpolationMode(graphics, InterpolationModeNearestNeighbor);
4023     expect(Ok, status);
4024 
4025     status = GdipDrawImageI(graphics, u1.image, 0, 0);
4026     expect(Ok, status);
4027 
4028     match = memcmp(white_2x2, black_2x2, sizeof(black_2x2)) == 0;
4029     ok(match, "data should match\n");
4030     if (!match)
4031     {
4032         UINT i, size = sizeof(white_2x2);
4033         BYTE *bits = white_2x2;
4034         for (i = 0; i < size; i++)
4035             trace(" %02x", bits[i]);
4036         trace("\n");
4037     }
4038 
4039     status = GdipDeleteGraphics(graphics);
4040     expect(Ok, status);
4041     status = GdipDisposeImage(u1.image);
4042     expect(Ok, status);
4043     status = GdipDisposeImage(u2.image);
4044     expect(Ok, status);
4045 }
4046 
4047 static void test_DrawImage_SourceCopy(void)
4048 {
4049     DWORD dst_pixels[4] = { 0xffffffff, 0xffffffff,
4050                             0xffffffff, 0xffffffff };
4051     DWORD src_pixels[4] = { 0, 0xffff0000,
4052                             0, 0xff00ff };
4053 
4054     GpStatus status;
4055     union
4056     {
4057         GpBitmap *bitmap;
4058         GpImage *image;
4059     } u1, u2;
4060     GpGraphics *graphics;
4061 
4062     status = GdipCreateBitmapFromScan0(2, 2, 8, PixelFormat32bppARGB, (BYTE*)dst_pixels, &u1.bitmap);
4063     expect(Ok, status);
4064 
4065     status = GdipCreateBitmapFromScan0(2, 2, 8, PixelFormat32bppARGB, (BYTE*)src_pixels, &u2.bitmap);
4066     expect(Ok, status);
4067     status = GdipGetImageGraphicsContext(u1.image, &graphics);
4068     expect(Ok, status);
4069     status = GdipSetInterpolationMode(graphics, InterpolationModeNearestNeighbor);
4070     expect(Ok, status);
4071 
4072     status = GdipSetCompositingMode(graphics, CompositingModeSourceCopy);
4073     expect(Ok, status);
4074 
4075     status = GdipDrawImageI(graphics, u2.image, 0, 0);
4076     expect(Ok, status);
4077 
4078     todo_wine expect(0, dst_pixels[0]);
4079     expect(0xffff0000, dst_pixels[1]);
4080     todo_wine expect(0, dst_pixels[2]);
4081     todo_wine expect(0, dst_pixels[3]);
4082 
4083     status = GdipDeleteGraphics(graphics);
4084     expect(Ok, status);
4085     status = GdipDisposeImage(u1.image);
4086     expect(Ok, status);
4087     status = GdipDisposeImage(u2.image);
4088     expect(Ok, status);
4089 }
4090 
4091 static void test_GdipDrawImagePointRect(void)
4092 {
4093     BYTE black_1x1[4] = { 0,0,0,0 };
4094     BYTE white_2x2[16] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
4095                            0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
4096     BYTE black_2x2[16] = { 0,0,0,0,0,0,0xff,0xff,
4097                            0,0,0,0,0,0,0xff,0xff };
4098     GpStatus status;
4099     union
4100     {
4101         GpBitmap *bitmap;
4102         GpImage *image;
4103     } u1, u2;
4104     GpGraphics *graphics;
4105     int match;
4106 
4107     status = GdipCreateBitmapFromScan0(1, 1, 4, PixelFormat24bppRGB, black_1x1, &u1.bitmap);
4108     expect(Ok, status);
4109     status = GdipBitmapSetResolution(u1.bitmap, 100.0, 100.0);
4110     expect(Ok, status);
4111 
4112     status = GdipCreateBitmapFromScan0(2, 2, 8, PixelFormat24bppRGB, white_2x2, &u2.bitmap);
4113     expect(Ok, status);
4114     status = GdipBitmapSetResolution(u2.bitmap, 300.0, 300.0);
4115     expect(Ok, status);
4116     status = GdipGetImageGraphicsContext(u2.image, &graphics);
4117     expect(Ok, status);
4118     status = GdipSetInterpolationMode(graphics, InterpolationModeNearestNeighbor);
4119     expect(Ok, status);
4120 
4121     status = GdipDrawImagePointRectI(graphics, u1.image, 0, 0, 0, 0, 1, 1, UnitPixel);
4122     expect(Ok, status);
4123 
4124     match = memcmp(white_2x2, black_2x2, sizeof(black_2x2)) == 0;
4125     ok(match, "data should match\n");
4126     if (!match)
4127     {
4128         UINT i, size = sizeof(white_2x2);
4129         BYTE *bits = white_2x2;
4130         for (i = 0; i < size; i++)
4131             trace(" %02x", bits[i]);
4132         trace("\n");
4133     }
4134 
4135     status = GdipDeleteGraphics(graphics);
4136     expect(Ok, status);
4137     status = GdipDisposeImage(u1.image);
4138     expect(Ok, status);
4139     status = GdipDisposeImage(u2.image);
4140     expect(Ok, status);
4141 }
4142 
4143 static void test_image_format(void)
4144 {
4145     static const PixelFormat fmt[] =
4146     {
4147         PixelFormat1bppIndexed, PixelFormat4bppIndexed, PixelFormat8bppIndexed,
4148         PixelFormat16bppGrayScale, PixelFormat16bppRGB555, PixelFormat16bppRGB565,
4149         PixelFormat16bppARGB1555, PixelFormat24bppRGB, PixelFormat32bppRGB,
4150         PixelFormat32bppARGB, PixelFormat32bppPARGB, PixelFormat48bppRGB,
4151         PixelFormat64bppARGB, PixelFormat64bppPARGB, PixelFormat32bppCMYK
4152     };
4153     GpStatus status;
4154     GpBitmap *bitmap;
4155     GpImage *thumb;
4156     HBITMAP hbitmap;
4157     BITMAP bm;
4158     PixelFormat format;
4159     BitmapData data;
4160     UINT i, ret;
4161 
4162     for (i = 0; i < sizeof(fmt)/sizeof(fmt[0]); i++)
4163     {
4164         status = GdipCreateBitmapFromScan0(1, 1, 0, fmt[i], NULL, &bitmap);
4165         ok(status == Ok || broken(status == InvalidParameter) /* before win7 */,
4166            "GdipCreateBitmapFromScan0 error %d\n", status);
4167         if (status != Ok) continue;
4168 
4169         status = GdipGetImagePixelFormat((GpImage *)bitmap, &format);
4170         expect(Ok, status);
4171         expect(fmt[i], format);
4172 
4173         status = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0);
4174         if (fmt[i] == PixelFormat16bppGrayScale || fmt[i] == PixelFormat32bppCMYK)
4175             todo_wine expect(InvalidParameter, status);
4176         else
4177         {
4178             expect(Ok, status);
4179             ret = GetObjectW(hbitmap, sizeof(bm), &bm);
4180             expect(sizeof(bm), ret);
4181             expect(0, bm.bmType);
4182             expect(1, bm.bmWidth);
4183             expect(1, bm.bmHeight);
4184             expect(4, bm.bmWidthBytes);
4185             expect(1, bm.bmPlanes);
4186             expect(32, bm.bmBitsPixel);
4187             DeleteObject(hbitmap);
4188         }
4189 
4190         status = GdipGetImageThumbnail((GpImage *)bitmap, 0, 0, &thumb, NULL, NULL);
4191         if (fmt[i] == PixelFormat16bppGrayScale || fmt[i] == PixelFormat32bppCMYK)
4192             todo_wine
4193             ok(status == OutOfMemory || broken(status == InvalidParameter) /* before win7 */,
4194                "expected OutOfMemory, got %d\n", status);
4195         else
4196             expect(Ok, status);
4197         if (status == Ok)
4198         {
4199             status = GdipGetImagePixelFormat(thumb, &format);
4200             expect(Ok, status);
4201             ok(format == PixelFormat32bppPARGB || broken(format != PixelFormat32bppPARGB) /* before win7 */,
4202                "expected PixelFormat32bppPARGB, got %#x\n", format);
4203             status = GdipDisposeImage(thumb);
4204             expect(Ok, status);
4205         }
4206 
4207         status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppPARGB, &data);
4208         if (fmt[i] == PixelFormat16bppGrayScale || fmt[i] == PixelFormat32bppCMYK)
4209             todo_wine expect(InvalidParameter, status);
4210         else
4211         {
4212             expect(Ok, status);
4213             status = GdipBitmapUnlockBits(bitmap, &data);
4214             expect(Ok, status);
4215         }
4216 
4217         status = GdipDisposeImage((GpImage *)bitmap);
4218         expect(Ok, status);
4219     }
4220 }
4221 
4222 static void test_DrawImage_scale(void)
4223 {
4224     static const BYTE back_8x1[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
4225                                        0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4226     static const BYTE image_080[24] = { 0x40,0x40,0x40,0x80,0x80,0x80,0x40,0x40,0x40,0x40,0x40,0x40,
4227                                         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4228     static const BYTE image_100[24] = { 0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x40,
4229                                         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4230     static const BYTE image_120[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x80,0x40,0x40,0x40,
4231                                         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4232     static const BYTE image_150[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,
4233                                         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4234     static const BYTE image_180[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,
4235                                         0x80,0x80,0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4236     static const BYTE image_200[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,
4237                                         0x80,0x80,0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4238     static const BYTE image_250[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x80,
4239                                         0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x40 };
4240     static const BYTE image_120_half[24] = { 0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
4241                                         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4242     static const BYTE image_150_half[24] = { 0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
4243                                         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 };
4244     static const BYTE image_200_half[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,
4245                                         0x80,0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x40,0x40,0x40,0x40 };
4246     static const BYTE image_250_half[24] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x80,0x80,0x80,0x80,
4247                                         0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x40 };
4248     static const struct test_data
4249     {
4250         REAL scale_x;
4251         PixelOffsetMode pixel_offset_mode;
4252         const BYTE *image;
4253         BOOL todo;
4254     } td[] =
4255     {
4256         { 0.8, PixelOffsetModeNone, image_080 }, /* 0 */
4257         { 1.0, PixelOffsetModeNone, image_100 },
4258         { 1.2, PixelOffsetModeNone, image_120 },
4259         { 1.5, PixelOffsetModeNone, image_150 },
4260         { 1.8, PixelOffsetModeNone, image_180 },
4261         { 2.0, PixelOffsetModeNone, image_200 },
4262         { 2.5, PixelOffsetModeNone, image_250 },
4263 
4264         { 0.8, PixelOffsetModeHighSpeed, image_080 }, /* 7 */
4265         { 1.0, PixelOffsetModeHighSpeed, image_100 },
4266         { 1.2, PixelOffsetModeHighSpeed, image_120 },
4267         { 1.5, PixelOffsetModeHighSpeed, image_150 },
4268         { 1.8, PixelOffsetModeHighSpeed, image_180 },
4269         { 2.0, PixelOffsetModeHighSpeed, image_200 },
4270         { 2.5, PixelOffsetModeHighSpeed, image_250 },
4271 
4272         { 0.8, PixelOffsetModeHalf, image_080 }, /* 14 */
4273         { 1.0, PixelOffsetModeHalf, image_100 },
4274         { 1.2, PixelOffsetModeHalf, image_120_half, TRUE },
4275         { 1.5, PixelOffsetModeHalf, image_150_half, TRUE },
4276         { 1.8, PixelOffsetModeHalf, image_180 },
4277         { 2.0, PixelOffsetModeHalf, image_200_half, TRUE },
4278         { 2.5, PixelOffsetModeHalf, image_250_half, TRUE },
4279 
4280         { 0.8, PixelOffsetModeHighQuality, image_080 }, /* 21 */
4281         { 1.0, PixelOffsetModeHighQuality, image_100 },
4282         { 1.2, PixelOffsetModeHighQuality, image_120_half, TRUE },
4283         { 1.5, PixelOffsetModeHighQuality, image_150_half, TRUE },
4284         { 1.8, PixelOffsetModeHighQuality, image_180 },
4285         { 2.0, PixelOffsetModeHighQuality, image_200_half, TRUE },
4286         { 2.5, PixelOffsetModeHighQuality, image_250_half, TRUE },
4287     };
4288     BYTE src_2x1[6] = { 0x80,0x80,0x80,0x80,0x80,0x80 };
4289     BYTE dst_8x1[24];
4290     GpStatus status;
4291     union
4292     {
4293         GpBitmap *bitmap;
4294         GpImage *image;
4295     } u1, u2;
4296     GpGraphics *graphics;
4297     GpMatrix *matrix;
4298     int i, match;
4299 
4300     status = GdipCreateBitmapFromScan0(2, 1, 4, PixelFormat24bppRGB, src_2x1, &u1.bitmap);
4301     expect(Ok, status);
4302     status = GdipBitmapSetResolution(u1.bitmap, 100.0, 100.0);
4303     expect(Ok, status);
4304 
4305     status = GdipCreateBitmapFromScan0(8, 1, 24, PixelFormat24bppRGB, dst_8x1, &u2.bitmap);
4306     expect(Ok, status);
4307     status = GdipBitmapSetResolution(u2.bitmap, 100.0, 100.0);
4308     expect(Ok, status);
4309     status = GdipGetImageGraphicsContext(u2.image, &graphics);
4310     expect(Ok, status);
4311     status = GdipSetInterpolationMode(graphics, InterpolationModeNearestNeighbor);
4312     expect(Ok, status);
4313 
4314     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
4315     {
4316         status = GdipSetPixelOffsetMode(graphics, td[i].pixel_offset_mode);
4317         expect(Ok, status);
4318 
4319         status = GdipCreateMatrix2(td[i].scale_x, 0.0, 0.0, 1.0, 0.0, 0.0, &matrix);
4320         expect(Ok, status);
4321         status = GdipSetWorldTransform(graphics, matrix);
4322         expect(Ok, status);
4323         GdipDeleteMatrix(matrix);
4324 
4325         memcpy(dst_8x1, back_8x1, sizeof(dst_8x1));
4326         status = GdipDrawImageI(graphics, u1.image, 1, 0);
4327         expect(Ok, status);
4328 
4329         match = memcmp(dst_8x1, td[i].image, sizeof(dst_8x1)) == 0;
4330         todo_wine_if (!match && td[i].todo)
4331             ok(match, "%d: data should match\n", i);
4332         if (!match)
4333         {
4334             UINT i, size = sizeof(dst_8x1);
4335             const BYTE *bits = dst_8x1;
4336             for (i = 0; i < size; i++)
4337                 trace(" %02x", bits[i]);
4338             trace("\n");
4339         }
4340     }
4341 
4342     status = GdipDeleteGraphics(graphics);
4343     expect(Ok, status);
4344     status = GdipDisposeImage(u1.image);
4345     expect(Ok, status);
4346     status = GdipDisposeImage(u2.image);
4347     expect(Ok, status);
4348 }
4349 
4350 static const BYTE animatedgif[] = {
4351 'G','I','F','8','9','a',0x01,0x00,0x01,0x00,0xA1,0x02,0x00,
4352 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,
4353 /*0x21,0xFF,0x0B,'A','N','I','M','E','X','T','S','1','.','0',*/
4354 0x21,0xFF,0x0B,'N','E','T','S','C','A','P','E','2','.','0',
4355 0x03,0x01,0x05,0x00,0x00,
4356 0x21,0xFE,0x0C,'H','e','l','l','o',' ','W','o','r','l','d','!',0x00,
4357 0x21,0x01,0x0D,'a','n','i','m','a','t','i','o','n','.','g','i','f',0x00,
4358 0x21,0xF9,0x04,0xff,0x0A,0x00,0x08,0x00,
4359 0x2C,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,
4360 0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,
4361 0x02,0x02,0x4C,0x01,0x00,
4362 0x21,0xFE,0x08,'i','m','a','g','e',' ','#','1',0x00,
4363 0x21,0x01,0x0C,'p','l','a','i','n','t','e','x','t',' ','#','1',0x00,
4364 0x21,0xF9,0x04,0x00,0x14,0x00,0x01,0x00,
4365 0x2C,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,
4366 0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,
4367 0x02,0x02,0x44,0x01,0x00,
4368 0x21,0xFE,0x08,'i','m','a','g','e',' ','#','2',0x00,
4369 0x21,0x01,0x0C,'p','l','a','i','n','t','e','x','t',' ','#','2',0x00,0x3B
4370 };
4371 
4372 static void test_gif_properties(void)
4373 {
4374     static const struct test_data
4375     {
4376         ULONG type, id, length;
4377         const BYTE value[13];
4378     } td[] =
4379     {
4380         { PropertyTagTypeLong, PropertyTagFrameDelay, 8, { 10,0,0,0,20,0,0,0 } },
4381         { PropertyTagTypeASCII, PropertyTagExifUserComment, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
4382         { PropertyTagTypeShort, PropertyTagLoopCount, 2, { 5,0 } },
4383         { PropertyTagTypeByte, PropertyTagGlobalPalette, 12, { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c } },
4384         { PropertyTagTypeByte, PropertyTagIndexBackground, 1, { 2 } },
4385         { PropertyTagTypeByte, PropertyTagIndexTransparent, 1, { 8 } }
4386     };
4387     GpStatus status;
4388     GpImage *image;
4389     GUID guid;
4390     UINT dim_count, frame_count, prop_count, prop_size, i;
4391     UINT total_size, total_count;
4392     PROPID *prop_id;
4393     PropertyItem *prop_item;
4394     const char *item_data;
4395 
4396     image = load_image(animatedgif, sizeof(animatedgif));
4397     if (!image) /* XP fails to load this GIF image */
4398     {
4399         trace("Failed to load GIF image data\n");
4400         return;
4401     }
4402 
4403     status = GdipImageGetFrameDimensionsCount(image, &dim_count);
4404     expect(Ok, status);
4405     expect(1, dim_count);
4406 
4407     status = GdipImageGetFrameDimensionsList(image, &guid, 1);
4408     expect(Ok, status);
4409     expect_guid(&FrameDimensionTime, &guid, __LINE__, FALSE);
4410 
4411     status = GdipImageGetFrameCount(image, &guid, &frame_count);
4412     expect(Ok, status);
4413     expect(2, frame_count);
4414 
4415     status = GdipImageSelectActiveFrame(image, &guid, 1);
4416     expect(Ok, status);
4417 
4418     status = GdipGetPropertyCount(image, &prop_count);
4419     expect(Ok, status);
4420     ok(prop_count == sizeof(td)/sizeof(td[0]) || broken(prop_count == 1) /* before win7 */,
4421        "expected property count %u, got %u\n", (UINT)(sizeof(td)/sizeof(td[0])), prop_count);
4422 
4423     if (prop_count != sizeof(td)/sizeof(td[0]))
4424     {
4425         GdipDisposeImage(image);
4426         return;
4427     }
4428 
4429     prop_id = HeapAlloc(GetProcessHeap(), 0, prop_count * sizeof(*prop_id));
4430 
4431     status = GdipGetPropertyIdList(image, prop_count, prop_id);
4432     expect(Ok, status);
4433 
4434     prop_size = 0;
4435     for (i = 0; i < prop_count; i++)
4436     {
4437         UINT size;
4438         status = GdipGetPropertyItemSize(image, prop_id[i], &size);
4439         expect(Ok, status);
4440         if (status != Ok) break;
4441         ok(size > sizeof(*prop_item), "%u: too small item length %u\n", i, size);
4442 
4443         prop_size += size;
4444 
4445         prop_item = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
4446         status = GdipGetPropertyItem(image, prop_id[i], size, prop_item);
4447         expect(Ok, status);
4448         ok(prop_item->value == prop_item + 1, "expected item->value %p, got %p\n", prop_item + 1, prop_item->value);
4449         ok(td[i].type == prop_item->type,
4450             "%u: expected type %u, got %u\n", i, td[i].type, prop_item->type);
4451         ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id);
4452         size -= sizeof(*prop_item);
4453         ok(prop_item->length == size, "%u: expected length %u, got %u\n", i, size, prop_item->length);
4454         ok(td[i].length == prop_item->length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length);
4455         if (td[i].length == prop_item->length)
4456         {
4457             int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0;
4458             ok(match, "%u: data mismatch\n", i);
4459             if (!match)
4460             {
4461                 UINT j;
4462                 BYTE *data = prop_item->value;
4463                 trace("id %#x:", prop_item->id);
4464                 for (j = 0; j < prop_item->length; j++)
4465                     trace(" %02x", data[j]);
4466                 trace("\n");
4467             }
4468         }
4469         HeapFree(GetProcessHeap(), 0, prop_item);
4470     }
4471 
4472     HeapFree(GetProcessHeap(), 0, prop_id);
4473 
4474     status = GdipGetPropertySize(NULL, &total_size, &total_count);
4475     expect(InvalidParameter, status);
4476     status = GdipGetPropertySize(image, &total_size, NULL);
4477     expect(InvalidParameter, status);
4478     status = GdipGetPropertySize(image, NULL, &total_count);
4479     expect(InvalidParameter, status);
4480     status = GdipGetPropertySize(image, NULL, NULL);
4481     expect(InvalidParameter, status);
4482     total_size = 0xdeadbeef;
4483     total_count = 0xdeadbeef;
4484     status = GdipGetPropertySize(image, &total_size, &total_count);
4485     expect(Ok, status);
4486     ok(prop_count == total_count,
4487        "expected total property count %u, got %u\n", prop_count, total_count);
4488     ok(prop_size == total_size,
4489        "expected total property size %u, got %u\n", prop_size, total_size);
4490 
4491     prop_item = HeapAlloc(GetProcessHeap(), 0, prop_size);
4492 
4493     status = GdipGetAllPropertyItems(image, 0, prop_count, prop_item);
4494     expect(InvalidParameter, status);
4495     status = GdipGetAllPropertyItems(image, prop_size, 1, prop_item);
4496     expect(InvalidParameter, status);
4497     status = GdipGetAllPropertyItems(image, prop_size, prop_count, NULL);
4498     expect(InvalidParameter, status);
4499     status = GdipGetAllPropertyItems(image, prop_size, prop_count, NULL);
4500     expect(InvalidParameter, status);
4501     status = GdipGetAllPropertyItems(image, 0, 0, NULL);
4502     expect(InvalidParameter, status);
4503     status = GdipGetAllPropertyItems(image, prop_size + 1, prop_count, prop_item);
4504     expect(InvalidParameter, status);
4505     status = GdipGetAllPropertyItems(image, prop_size, prop_count, prop_item);
4506     expect(Ok, status);
4507 
4508     item_data = (const char *)(prop_item + prop_count);
4509     for (i = 0; i < prop_count; i++)
4510     {
4511         ok(prop_item[i].value == item_data, "%u: expected value %p, got %p\n",
4512            i, item_data, prop_item[i].value);
4513         ok(td[i].type == prop_item[i].type,
4514             "%u: expected type %u, got %u\n", i, td[i].type, prop_item[i].type);
4515         ok(td[i].id == prop_item[i].id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item[i].id);
4516         ok(td[i].length == prop_item[i].length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item[i].length);
4517         if (td[i].length == prop_item[i].length)
4518         {
4519             int match = memcmp(td[i].value, prop_item[i].value, td[i].length) == 0;
4520             ok(match, "%u: data mismatch\n", i);
4521             if (!match)
4522             {
4523                 UINT j;
4524                 BYTE *data = prop_item[i].value;
4525                 trace("id %#x:", prop_item[i].id);
4526                 for (j = 0; j < prop_item[i].length; j++)
4527                     trace(" %02x", data[j]);
4528                 trace("\n");
4529             }
4530         }
4531         item_data += prop_item[i].length;
4532     }
4533 
4534     HeapFree(GetProcessHeap(), 0, prop_item);
4535 
4536     GdipDisposeImage(image);
4537 }
4538 
4539 static void test_ARGB_conversion(void)
4540 {
4541     BYTE argb[8] = { 0x11,0x22,0x33,0x80, 0xff,0xff,0xff,0 };
4542     BYTE pargb[8] = { 0x09,0x11,0x1a,0x80, 0,0,0,0 };
4543     BYTE rgb32_xp[8] = { 0x11,0x22,0x33,0xff, 0xff,0xff,0xff,0xff };
4544     BYTE rgb24[6] = { 0x11,0x22,0x33, 0xff,0xff,0xff };
4545     BYTE *bits;
4546     GpBitmap *bitmap;
4547     BitmapData data;
4548     GpStatus status;
4549     int match;
4550 
4551     status = GdipCreateBitmapFromScan0(2, 1, 8, PixelFormat32bppARGB, argb, &bitmap);
4552     expect(Ok, status);
4553 
4554     status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppPARGB, &data);
4555     expect(Ok, status);
4556     ok(data.Width == 2, "expected 2, got %d\n", data.Width);
4557     ok(data.Height == 1, "expected 1, got %d\n", data.Height);
4558     ok(data.Stride == 8, "expected 8, got %d\n", data.Stride);
4559     ok(data.PixelFormat == PixelFormat32bppPARGB, "expected PixelFormat32bppPARGB, got %d\n", data.PixelFormat);
4560     match = !memcmp(data.Scan0, pargb, sizeof(pargb));
4561     ok(match, "bits don't match\n");
4562     if (!match)
4563     {
4564         bits = data.Scan0;
4565         trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppPARGB,
4566                bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
4567     }
4568     status = GdipBitmapUnlockBits(bitmap, &data);
4569     expect(Ok, status);
4570 
4571     status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppRGB, &data);
4572     expect(Ok, status);
4573     ok(data.Width == 2, "expected 2, got %d\n", data.Width);
4574     ok(data.Height == 1, "expected 1, got %d\n", data.Height);
4575     ok(data.Stride == 8, "expected 8, got %d\n", data.Stride);
4576     ok(data.PixelFormat == PixelFormat32bppRGB, "expected PixelFormat32bppRGB, got %d\n", data.PixelFormat);
4577     match = !memcmp(data.Scan0, argb, sizeof(argb)) ||
4578             !memcmp(data.Scan0, rgb32_xp, sizeof(rgb32_xp));
4579     ok(match, "bits don't match\n");
4580     if (!match)
4581     {
4582         bits = data.Scan0;
4583         trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppRGB,
4584                bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
4585     }
4586     status = GdipBitmapUnlockBits(bitmap, &data);
4587     expect(Ok, status);
4588 
4589     status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB, &data);
4590     expect(Ok, status);
4591     ok(data.Width == 2, "expected 2, got %d\n", data.Width);
4592     ok(data.Height == 1, "expected 1, got %d\n", data.Height);
4593     ok(data.Stride == 8, "expected 8, got %d\n", data.Stride);
4594     ok(data.PixelFormat == PixelFormat24bppRGB, "expected PixelFormat24bppRGB, got %d\n", data.PixelFormat);
4595     match = !memcmp(data.Scan0, rgb24, sizeof(rgb24));
4596     ok(match, "bits don't match\n");
4597     if (!match)
4598     {
4599         bits = data.Scan0;
4600         trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat24bppRGB,
4601                bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
4602     }
4603     status = GdipBitmapUnlockBits(bitmap, &data);
4604     expect(Ok, status);
4605 
4606     GdipDisposeImage((GpImage *)bitmap);
4607 }
4608 
4609 
4610 static void test_CloneBitmapArea(void)
4611 {
4612     GpStatus status;
4613     GpBitmap *bitmap, *copy;
4614     BitmapData data, data2;
4615 
4616     status = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat24bppRGB, NULL, &bitmap);
4617     expect(Ok, status);
4618 
4619     status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &data);
4620     expect(Ok, status);
4621 
4622     status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB, &data2);
4623     expect(WrongState, status);
4624 
4625     status = GdipCloneBitmapAreaI(0, 0, 1, 1, PixelFormat24bppRGB, bitmap, &copy);
4626     expect(Ok, status);
4627 
4628     status = GdipBitmapUnlockBits(bitmap, &data);
4629     expect(Ok, status);
4630 
4631     GdipDisposeImage((GpImage *)copy);
4632     GdipDisposeImage((GpImage *)bitmap);
4633 }
4634 
4635 static BOOL get_encoder_clsid(LPCWSTR mime, GUID *format, CLSID *clsid)
4636 {
4637     GpStatus status;
4638     UINT n_codecs, info_size, i;
4639     ImageCodecInfo *info;
4640     BOOL ret = FALSE;
4641 
4642     status = GdipGetImageEncodersSize(&n_codecs, &info_size);
4643     expect(Ok, status);
4644 
4645     info = GdipAlloc(info_size);
4646 
4647     status = GdipGetImageEncoders(n_codecs, info_size, info);
4648     expect(Ok, status);
4649 
4650     for (i = 0; i < n_codecs; i++)
4651     {
4652         if (!lstrcmpW(info[i].MimeType, mime))
4653         {
4654             *format = info[i].FormatID;
4655             *clsid = info[i].Clsid;
4656             ret = TRUE;
4657             break;
4658         }
4659     }
4660 
4661     GdipFree(info);
4662     return ret;
4663 }
4664 
4665 static void test_supported_encoders(void)
4666 {
4667     static const WCHAR bmp_mimetype[] = { 'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p',0 };
4668     static const WCHAR jpeg_mimetype[] = { 'i','m','a','g','e','/','j','p','e','g',0 };
4669     static const WCHAR gif_mimetype[] = { 'i','m','a','g','e','/','g','i','f',0 };
4670     static const WCHAR tiff_mimetype[] = { 'i','m','a','g','e','/','t','i','f','f',0 };
4671     static const WCHAR png_mimetype[] = { 'i','m','a','g','e','/','p','n','g',0 };
4672     static const struct test_data
4673     {
4674         LPCWSTR mime;
4675         const GUID *format;
4676     } td[] =
4677     {
4678         { bmp_mimetype, &ImageFormatBMP },
4679         { jpeg_mimetype, &ImageFormatJPEG },
4680         { gif_mimetype, &ImageFormatGIF },
4681         { tiff_mimetype, &ImageFormatTIFF },
4682         { png_mimetype, &ImageFormatPNG }
4683     };
4684     GUID format, clsid;
4685     BOOL ret;
4686     HRESULT hr;
4687     GpStatus status;
4688     GpBitmap *bm;
4689     IStream *stream;
4690     HGLOBAL hmem;
4691     int i;
4692 
4693     status = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat24bppRGB, NULL, &bm);
4694     ok(status == Ok, "GdipCreateBitmapFromScan0 error %d\n", status);
4695 
4696     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
4697     {
4698         ret = get_encoder_clsid(td[i].mime, &format, &clsid);
4699         ok(ret, "%s encoder is not in the list\n", wine_dbgstr_w(td[i].mime));
4700         expect_guid(td[i].format, &format, __LINE__, FALSE);
4701 
4702         hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 16);
4703 
4704         hr = CreateStreamOnHGlobal(hmem, TRUE, &stream);
4705         ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
4706 
4707         status = GdipSaveImageToStream((GpImage *)bm, stream, &clsid, NULL);
4708         ok(status == Ok, "GdipSaveImageToStream error %d\n", status);
4709 
4710         IStream_Release(stream);
4711     }
4712 
4713     GdipDisposeImage((GpImage *)bm);
4714 }
4715 
4716 static void test_createeffect(void)
4717 {
4718     static const GUID noneffect = { 0xcd0c3d4b, 0xe15e, 0x4cf2, { 0x9e, 0xa8, 0x6e, 0x1d, 0x65, 0x48, 0xc5, 0xa5 } };
4719     GpStatus (WINAPI *pGdipCreateEffect)( const GUID guid, CGpEffect **effect);
4720     GpStatus (WINAPI *pGdipDeleteEffect)( CGpEffect *effect);
4721     GpStatus stat;
4722     CGpEffect *effect;
4723     HMODULE mod = GetModuleHandleA("gdiplus.dll");
4724     int i;
4725     const GUID * const effectlist[] =
4726                {&BlurEffectGuid, &SharpenEffectGuid, &ColorMatrixEffectGuid, &ColorLUTEffectGuid,
4727                 &BrightnessContrastEffectGuid, &HueSaturationLightnessEffectGuid, &LevelsEffectGuid,
4728                 &TintEffectGuid, &ColorBalanceEffectGuid, &RedEyeCorrectionEffectGuid, &ColorCurveEffectGuid};
4729 
4730     pGdipCreateEffect = (void*)GetProcAddress( mod, "GdipCreateEffect");
4731     pGdipDeleteEffect = (void*)GetProcAddress( mod, "GdipDeleteEffect");
4732     if(!pGdipCreateEffect || !pGdipDeleteEffect)
4733     {
4734         /* GdipCreateEffect/GdipDeleteEffect was introduced in Windows Vista. */
4735         win_skip("GDIPlus version 1.1 not available\n");
4736         return;
4737     }
4738 
4739     stat = pGdipCreateEffect(BlurEffectGuid, NULL);
4740     expect(InvalidParameter, stat);
4741 
4742     stat = pGdipCreateEffect(noneffect, &effect);
4743     todo_wine expect(Win32Error, stat);
4744 
4745     for(i=0; i < sizeof(effectlist) / sizeof(effectlist[0]); i++)
4746     {
4747         stat = pGdipCreateEffect(*effectlist[i], &effect);
4748         todo_wine expect(Ok, stat);
4749         if(stat == Ok)
4750         {
4751             stat = pGdipDeleteEffect(effect);
4752             expect(Ok, stat);
4753         }
4754     }
4755 }
4756 
4757 static void test_getadjustedpalette(void)
4758 {
4759     ColorMap colormap;
4760     GpImageAttributes *imageattributes;
4761     ColorPalette *palette;
4762     GpStatus stat;
4763 
4764     stat = GdipCreateImageAttributes(&imageattributes);
4765     expect(Ok, stat);
4766 
4767     colormap.oldColor.Argb = 0xffffff00;
4768     colormap.newColor.Argb = 0xffff00ff;
4769     stat = GdipSetImageAttributesRemapTable(imageattributes, ColorAdjustTypeBitmap,
4770         TRUE, 1, &colormap);
4771     expect(Ok, stat);
4772 
4773     colormap.oldColor.Argb = 0xffffff80;
4774     colormap.newColor.Argb = 0xffff80ff;
4775     stat = GdipSetImageAttributesRemapTable(imageattributes, ColorAdjustTypeDefault,
4776         TRUE, 1, &colormap);
4777     expect(Ok, stat);
4778 
4779     palette = GdipAlloc(sizeof(*palette) + sizeof(ARGB) * 2);
4780     palette->Count = 0;
4781 
4782     stat = GdipGetImageAttributesAdjustedPalette(imageattributes, palette, ColorAdjustTypeBitmap);
4783     expect(InvalidParameter, stat);
4784 
4785     palette->Count = 3;
4786     palette->Entries[0] = 0xffffff00;
4787     palette->Entries[1] = 0xffffff80;
4788     palette->Entries[2] = 0xffffffff;
4789 
4790     stat = GdipGetImageAttributesAdjustedPalette(imageattributes, palette, ColorAdjustTypeBitmap);
4791     expect(Ok, stat);
4792     expect(0xffff00ff, palette->Entries[0]);
4793     expect(0xffffff80, palette->Entries[1]);
4794     expect(0xffffffff, palette->Entries[2]);
4795 
4796     palette->Entries[0] = 0xffffff00;
4797     palette->Entries[1] = 0xffffff80;
4798     palette->Entries[2] = 0xffffffff;
4799 
4800     stat = GdipGetImageAttributesAdjustedPalette(imageattributes, palette, ColorAdjustTypeBrush);
4801     expect(Ok, stat);
4802     expect(0xffffff00, palette->Entries[0]);
4803     expect(0xffff80ff, palette->Entries[1]);
4804     expect(0xffffffff, palette->Entries[2]);
4805 
4806     stat = GdipGetImageAttributesAdjustedPalette(NULL, palette, ColorAdjustTypeBitmap);
4807     expect(InvalidParameter, stat);
4808 
4809     stat = GdipGetImageAttributesAdjustedPalette(imageattributes, NULL, ColorAdjustTypeBitmap);
4810     expect(InvalidParameter, stat);
4811 
4812     stat = GdipGetImageAttributesAdjustedPalette(imageattributes, palette, -1);
4813     expect(InvalidParameter, stat);
4814 
4815     stat = GdipGetImageAttributesAdjustedPalette(imageattributes, palette, ColorAdjustTypeDefault);
4816     expect(InvalidParameter, stat);
4817 
4818     GdipFree(palette);
4819     GdipDisposeImageAttributes(imageattributes);
4820 }
4821 
4822 static void test_histogram(void)
4823 {
4824     UINT ch0[256], ch1[256], ch2[256], ch3[256];
4825     HistogramFormat test_formats[] =
4826     {
4827         HistogramFormatARGB,
4828         HistogramFormatPARGB,
4829         HistogramFormatRGB,
4830         HistogramFormatGray,
4831         HistogramFormatB,
4832         HistogramFormatG,
4833         HistogramFormatR,
4834         HistogramFormatA,
4835     };
4836     const UINT WIDTH = 8, HEIGHT = 16;
4837     UINT num, i, x;
4838     GpStatus stat;
4839     GpBitmap *bm;
4840 
4841     if (!pGdipBitmapGetHistogramSize)
4842     {
4843         win_skip("GdipBitmapGetHistogramSize is not supported\n");
4844         return;
4845     }
4846 
4847     stat = pGdipBitmapGetHistogramSize(HistogramFormatARGB, NULL);
4848     expect(InvalidParameter, stat);
4849 
4850     stat = pGdipBitmapGetHistogramSize(0xff, NULL);
4851     expect(InvalidParameter, stat);
4852 
4853     num = 123;
4854     stat = pGdipBitmapGetHistogramSize(10, &num);
4855     expect(Ok, stat);
4856     expect(256, num);
4857 
4858     for (i = 0; i < sizeof(test_formats)/sizeof(test_formats[0]); i++)
4859     {
4860         num = 0;
4861         stat = pGdipBitmapGetHistogramSize(test_formats[i], &num);
4862         expect(Ok, stat);
4863         expect(256, num);
4864     }
4865 
4866     bm = NULL;
4867     stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
4868     expect(Ok, stat);
4869 
4870     /* Three solid rgb rows, next three rows are rgb shades. */
4871     for (x = 0; x < WIDTH; x++)
4872     {
4873         GdipBitmapSetPixel(bm, x, 0, 0xffff0000);
4874         GdipBitmapSetPixel(bm, x, 1, 0xff00ff00);
4875         GdipBitmapSetPixel(bm, x, 2, 0xff0000ff);
4876 
4877         GdipBitmapSetPixel(bm, x, 3, 0xff010000);
4878         GdipBitmapSetPixel(bm, x, 4, 0xff003f00);
4879         GdipBitmapSetPixel(bm, x, 5, 0xff000020);
4880     }
4881 
4882     stat = pGdipBitmapGetHistogram(NULL, HistogramFormatRGB, 256, ch0, ch1, ch2, ch3);
4883     expect(InvalidParameter, stat);
4884 
4885     stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, ch2, ch3);
4886     expect(InvalidParameter, stat);
4887 
4888     stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, ch2, NULL);
4889     expect(InvalidParameter, stat);
4890 
4891     stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, NULL, NULL);
4892     expect(InvalidParameter, stat);
4893 
4894     stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, NULL, NULL, NULL);
4895     expect(InvalidParameter, stat);
4896 
4897     /* Requested format matches bitmap format */
4898     stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 256, ch0, ch1, ch2, ch3);
4899     expect(InvalidParameter, stat);
4900 
4901     stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 100, ch0, ch1, ch2, NULL);
4902     expect(InvalidParameter, stat);
4903 
4904     stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 257, ch0, ch1, ch2, NULL);
4905     expect(InvalidParameter, stat);
4906 
4907     /* Channel 3 is not used, must be NULL */
4908     stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 256, ch0, ch1, ch2, NULL);
4909     expect(Ok, stat);
4910 
4911     ok(ch0[0xff] == WIDTH, "Got red (0xff) %u\n", ch0[0xff]);
4912     ok(ch1[0xff] == WIDTH, "Got green (0xff) %u\n", ch1[0xff]);
4913     ok(ch2[0xff] == WIDTH, "Got blue (0xff) %u\n", ch1[0xff]);
4914     ok(ch0[0x01] == WIDTH, "Got red (0x01) %u\n", ch0[0x01]);
4915     ok(ch1[0x3f] == WIDTH, "Got green (0x3f) %u\n", ch1[0x3f]);
4916     ok(ch2[0x20] == WIDTH, "Got blue (0x20) %u\n", ch1[0x20]);
4917 
4918     /* ARGB histogram from RGB data. */
4919     stat = pGdipBitmapGetHistogram(bm, HistogramFormatARGB, 256, ch0, ch1, ch2, NULL);
4920     expect(InvalidParameter, stat);
4921 
4922     stat = pGdipBitmapGetHistogram(bm, HistogramFormatARGB, 256, ch0, ch1, ch2, ch3);
4923     expect(Ok, stat);
4924 
4925     ok(ch1[0xff] == WIDTH, "Got red (0xff) %u\n", ch1[0xff]);
4926     ok(ch2[0xff] == WIDTH, "Got green (0xff) %u\n", ch2[0xff]);
4927     ok(ch3[0xff] == WIDTH, "Got blue (0xff) %u\n", ch3[0xff]);
4928     ok(ch1[0x01] == WIDTH, "Got red (0x01) %u\n", ch1[0x01]);
4929     ok(ch2[0x3f] == WIDTH, "Got green (0x3f) %u\n", ch2[0x3f]);
4930     ok(ch3[0x20] == WIDTH, "Got blue (0x20) %u\n", ch3[0x20]);
4931 
4932     ok(ch0[0xff] == WIDTH * HEIGHT, "Got alpha (0xff) %u\n", ch0[0xff]);
4933 
4934     /* Request grayscale histogram from RGB bitmap. */
4935     stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, ch2, ch3);
4936     expect(InvalidParameter, stat);
4937 
4938     stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, ch2, NULL);
4939     expect(InvalidParameter, stat);
4940 
4941     stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, NULL, NULL);
4942     expect(InvalidParameter, stat);
4943 
4944     stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, NULL, NULL, NULL);
4945     expect(Ok, stat);
4946 
4947     GdipDisposeImage((GpImage*)bm);
4948 }
4949 
4950 static void test_imageabort(void)
4951 {
4952     GpStatus stat;
4953     GpBitmap *bm;
4954 
4955     if (!pGdipImageSetAbort)
4956     {
4957         win_skip("GdipImageSetAbort() is not supported.\n");
4958         return;
4959     }
4960 
4961     bm = NULL;
4962     stat = GdipCreateBitmapFromScan0(8, 8, 0, PixelFormat24bppRGB, NULL, &bm);
4963     expect(Ok, stat);
4964 
4965     stat = pGdipImageSetAbort(NULL, NULL);
4966     expect(InvalidParameter, stat);
4967 
4968     stat = pGdipImageSetAbort((GpImage*)bm, NULL);
4969     expect(Ok, stat);
4970 
4971     GdipDisposeImage((GpImage*)bm);
4972 }
4973 
4974 /* RGB 24 bpp 1x1 pixel PNG image */
4975 static const char png_1x1_data[] = {
4976   0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a,
4977   0x00,0x00,0x00,0x0d,'I','H','D','R',0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,0xde,
4978   0x00,0x00,0x00,0x0c,'I','D','A','T',0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,0xe7,
4979   0x00,0x00,0x00,0x00,'I','E','N','D',0xae,0x42,0x60,0x82
4980 };
4981 
4982 static void test_png_color_formats(void)
4983 {
4984     static const struct
4985     {
4986         char bit_depth, color_type;
4987         PixelFormat format;
4988         UINT flags;
4989     } td[] =
4990     {
4991         /* 2 - PNG_COLOR_TYPE_RGB */
4992         { 8, 2, PixelFormat24bppRGB, ImageFlagsColorSpaceRGB },
4993         /* 0 - PNG_COLOR_TYPE_GRAY */
4994         { 1, 0, PixelFormat1bppIndexed, ImageFlagsColorSpaceRGB },
4995         { 2, 0, PixelFormat32bppARGB, ImageFlagsColorSpaceGRAY },
4996         { 4, 0, PixelFormat32bppARGB, ImageFlagsColorSpaceGRAY },
4997         { 8, 0, PixelFormat32bppARGB, ImageFlagsColorSpaceGRAY },
4998         { 16, 0, PixelFormat32bppARGB, ImageFlagsColorSpaceGRAY },
4999     };
5000     BYTE buf[sizeof(png_1x1_data)];
5001     GpStatus status;
5002     GpImage *image;
5003     ImageType type;
5004     PixelFormat format;
5005     UINT flags;
5006     int i;
5007 
5008     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
5009     {
5010         memcpy(buf, png_1x1_data, sizeof(png_1x1_data));
5011         buf[24] = td[i].bit_depth;
5012         buf[25] = td[i].color_type;
5013 
5014         image = load_image(buf, sizeof(buf));
5015         ok(image != NULL, "%d: failed to load image data\n", i);
5016         if (!image) continue;
5017 
5018         status = GdipGetImageType(image, &type);
5019         ok(status == Ok, "%u: GdipGetImageType error %d\n", i, status);
5020         ok(type == ImageTypeBitmap, "%d: wrong image type %d\n", i, type);
5021 
5022         status = GdipGetImagePixelFormat(image, &format);
5023         expect(Ok, status);
5024         ok(format == td[i].format ||
5025            broken(td[i].bit_depth == 1 && td[i].color_type == 0 && format == PixelFormat32bppARGB), /* XP */
5026            "%d: expected %#x, got %#x\n", i, td[i].format, format);
5027 
5028         status = GdipGetImageFlags(image, &flags);
5029         expect(Ok, status);
5030         ok((flags & td[i].flags) == td[i].flags ||
5031            broken(td[i].bit_depth == 1 && td[i].color_type == 0 && (flags & ImageFlagsColorSpaceGRAY)), /* XP */
5032            "%d: expected %#x, got %#x\n", i, td[i].flags, flags);
5033 
5034         GdipDisposeImage(image);
5035     }
5036 }
5037 
5038 static BYTE *init_bitmap(UINT *width, UINT *height, UINT *stride)
5039 {
5040     BYTE *src;
5041     UINT i, j, scale;
5042 
5043     *width = 256;
5044     *height = 256;
5045     *stride = (*width * 3 + 3) & ~3;
5046     trace("width %d, height %d, stride %d\n", *width, *height, *stride);
5047 
5048     src = HeapAlloc(GetProcessHeap(), 0, *stride * *height);
5049 
5050     scale = 256 / *width;
5051     if (!scale) scale = 1;
5052 
5053     for (i = 0; i < *height; i++)
5054     {
5055         for (j = 0; j < *width; j++)
5056         {
5057             src[i * *stride + j*3 + 0] = scale * i;
5058             src[i * *stride + j*3 + 1] = scale * (255 - (i+j)/2);
5059             src[i * *stride + j*3 + 2] = scale * j;
5060         }
5061     }
5062 
5063     return src;
5064 }
5065 
5066 static void test_GdipInitializePalette(void)
5067 {
5068     GpStatus status;
5069     BYTE *data;
5070     GpBitmap *bitmap;
5071     ColorPalette *palette;
5072     UINT width, height, stride;
5073 
5074     pGdipInitializePalette = (void *)GetProcAddress(GetModuleHandleA("gdiplus.dll"), "GdipInitializePalette");
5075     if (!pGdipInitializePalette)
5076     {
5077         win_skip("GdipInitializePalette is not supported on this platform\n");
5078         return;
5079     }
5080 
5081     data = init_bitmap(&width, &height, &stride);
5082 
5083     status = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat24bppRGB, data, &bitmap);
5084     expect(Ok, status);
5085 
5086     palette = GdipAlloc(sizeof(*palette) + sizeof(ARGB) * 255);
5087 
5088     palette->Flags = 0;
5089     palette->Count = 15;
5090     status = pGdipInitializePalette(palette, PaletteTypeOptimal, 16, FALSE, bitmap);
5091     expect(GenericError, status);
5092 
5093     palette->Flags = 0;
5094     palette->Count = 256;
5095     status = pGdipInitializePalette(palette, PaletteTypeOptimal, 16, FALSE, NULL);
5096     expect(InvalidParameter, status);
5097 
5098     memset(palette->Entries, 0x11, sizeof(ARGB) * 256);
5099     palette->Flags = 0;
5100     palette->Count = 256;
5101     status = pGdipInitializePalette(palette, PaletteTypeCustom, 16, FALSE, NULL);
5102     expect(Ok, status);
5103     expect(0, palette->Flags);
5104     expect(256, palette->Count);
5105     expect(0x11111111, palette->Entries[0]);
5106     expect(0x11111111, palette->Entries[128]);
5107     expect(0x11111111, palette->Entries[255]);
5108 
5109     memset(palette->Entries, 0x11, sizeof(ARGB) * 256);
5110     palette->Flags = 0;
5111     palette->Count = 256;
5112     status = pGdipInitializePalette(palette, PaletteTypeFixedBW, 0, FALSE, bitmap);
5113     expect(Ok, status);
5114 todo_wine
5115     expect(0x200, palette->Flags);
5116     expect(2, palette->Count);
5117     expect(0xff000000, palette->Entries[0]);
5118     expect(0xffffffff, palette->Entries[1]);
5119 
5120     memset(palette->Entries, 0x11, sizeof(ARGB) * 256);
5121     palette->Flags = 0;
5122     palette->Count = 256;
5123     status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone8, 1, FALSE, NULL);
5124     expect(Ok, status);
5125 todo_wine
5126     expect(0x300, palette->Flags);
5127     expect(16, palette->Count);
5128     expect(0xff000000, palette->Entries[0]);
5129     expect(0xffc0c0c0, palette->Entries[8]);
5130     expect(0xff008080, palette->Entries[15]);
5131 
5132     memset(palette->Entries, 0x11, sizeof(ARGB) * 256);
5133     palette->Flags = 0;
5134     palette->Count = 256;
5135     status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone8, 1, FALSE, bitmap);
5136     expect(Ok, status);
5137 todo_wine
5138     expect(0x300, palette->Flags);
5139     expect(16, palette->Count);
5140     expect(0xff000000, palette->Entries[0]);
5141     expect(0xffc0c0c0, palette->Entries[8]);
5142     expect(0xff008080, palette->Entries[15]);
5143 
5144     memset(palette->Entries, 0x11, sizeof(ARGB) * 256);
5145     palette->Flags = 0;
5146     palette->Count = 256;
5147     status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone252, 1, FALSE, bitmap);
5148     expect(Ok, status);
5149 todo_wine
5150     expect(0x800, palette->Flags);
5151     expect(252, palette->Count);
5152     expect(0xff000000, palette->Entries[0]);
5153     expect(0xff990066, palette->Entries[128]);
5154     expect(0xffffffff, palette->Entries[251]);
5155 
5156     palette->Flags = 0;
5157     palette->Count = 256;
5158     status = pGdipInitializePalette(palette, PaletteTypeOptimal, 1, FALSE, bitmap);
5159     expect(InvalidParameter, status);
5160 
5161     palette->Flags = 0;
5162     palette->Count = 256;
5163     status = pGdipInitializePalette(palette, PaletteTypeOptimal, 2, FALSE, bitmap);
5164     expect(Ok, status);
5165     expect(0, palette->Flags);
5166     expect(2, palette->Count);
5167 
5168     palette->Flags = 0;
5169     palette->Count = 256;
5170     status = pGdipInitializePalette(palette, PaletteTypeOptimal, 16, FALSE, bitmap);
5171     expect(Ok, status);
5172     expect(0, palette->Flags);
5173     expect(16, palette->Count);
5174 
5175     /* passing invalid enumeration palette type crashes under most Windows versions */
5176 
5177     GdipFree(palette);
5178     GdipDisposeImage((GpImage *)bitmap);
5179 }
5180 
5181 #include "pshpack2.h"
5182 static const struct tiff_1x1_data
5183 {
5184     USHORT byte_order;
5185     USHORT version;
5186     ULONG  dir_offset;
5187     USHORT number_of_entries;
5188     struct IFD_entry entry[12];
5189     ULONG next_IFD;
5190     struct IFD_rational res;
5191     short palette_data[3][256];
5192     short bps_data[4];
5193     BYTE pixel_data[32];
5194 } tiff_1x1_data =
5195 {
5196 #ifdef WORDS_BIGENDIAN
5197     'M' | 'M' << 8,
5198 #else
5199     'I' | 'I' << 8,
5200 #endif
5201     42,
5202     FIELD_OFFSET(struct tiff_1x1_data, number_of_entries),
5203     12,
5204     {
5205         { 0xff, IFD_SHORT, 1, 0 }, /* SUBFILETYPE */
5206         { 0x100, IFD_LONG, 1, 1 }, /* IMAGEWIDTH */
5207         { 0x101, IFD_LONG, 1, 1 }, /* IMAGELENGTH */
5208         { 0x102, IFD_SHORT, 3, FIELD_OFFSET(struct tiff_1x1_data, bps_data) }, /* BITSPERSAMPLE */
5209         { 0x103, IFD_SHORT, 1, 1 }, /* COMPRESSION: XP doesn't accept IFD_LONG here */
5210         { 0x106, IFD_SHORT, 1, 2 }, /* PHOTOMETRIC */
5211         { 0x111, IFD_LONG, 1, FIELD_OFFSET(struct tiff_1x1_data, pixel_data) }, /* STRIPOFFSETS */
5212         { 0x115, IFD_SHORT, 1, 3 }, /* SAMPLESPERPIXEL */
5213         { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_1x1_data, res) },
5214         { 0x11b, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_1x1_data, res) },
5215         { 0x128, IFD_SHORT, 1, 2 }, /* RESOLUTIONUNIT */
5216         { 0x140, IFD_SHORT, 256*3, FIELD_OFFSET(struct tiff_1x1_data, palette_data) } /* COLORMAP */
5217     },
5218     0,
5219     { 96, 1 },
5220     { { 0 } },
5221     { 8,8,8,0 },
5222     { 1,0,2,3,4,5,6,7,8,9,0,1,2,3,4,5 }
5223 };
5224 #include "poppack.h"
5225 
5226 static void test_tiff_color_formats(void)
5227 {
5228     static const struct
5229     {
5230         int photometric; /* PhotometricInterpretation */
5231         int samples; /* SamplesPerPixel */
5232         int bps; /* BitsPerSample */
5233         PixelFormat format;
5234     } td[] =
5235     {
5236         /* 2 - RGB */
5237         { 2, 3, 1, PixelFormat24bppRGB },
5238         { 2, 3, 4, PixelFormat24bppRGB },
5239         { 2, 3, 8, PixelFormat24bppRGB },
5240         { 2, 3, 16, PixelFormat48bppRGB },
5241         { 2, 3, 24, 0 },
5242 #if 0 /* FIXME */
5243         { 2, 3, 32, 0 },
5244 #endif
5245         { 2, 4, 1, PixelFormat32bppARGB },
5246         { 2, 4, 4, PixelFormat32bppARGB },
5247         { 2, 4, 8, PixelFormat32bppARGB },
5248         { 2, 4, 16, PixelFormat48bppRGB },
5249         { 2, 4, 24, 0 },
5250         { 2, 4, 32, 0 },
5251         /* 1 - BlackIsZero (Bilevel) */
5252         { 1, 1, 1, PixelFormat1bppIndexed },
5253 #if 0 /* FIXME: PNG vs TIFF mismatch */
5254         { 1, 1, 4, PixelFormat8bppIndexed },
5255 #endif
5256         { 1, 1, 8, PixelFormat8bppIndexed },
5257         { 1, 1, 16, PixelFormat32bppARGB },
5258         { 1, 1, 24, 0 },
5259         { 1, 1, 32, PixelFormat32bppARGB },
5260         /* 3 - Palette Color */
5261         { 3, 1, 1, PixelFormat1bppIndexed },
5262         { 3, 1, 4, PixelFormat4bppIndexed },
5263         { 3, 1, 8, PixelFormat8bppIndexed },
5264 #if 0 /* FIXME: for some reason libtiff replaces photometric 3 by 1 for bps > 8 */
5265         { 3, 1, 16, 0 },
5266         { 3, 1, 24, 0 },
5267         { 3, 1, 32, 0 },
5268 #endif
5269         /* 5 - Separated */
5270         { 5, 4, 1, 0 },
5271         { 5, 4, 4, 0 },
5272         { 5, 4, 8, PixelFormat32bppCMYK },
5273         { 5, 4, 16, PixelFormat48bppRGB },
5274         { 5, 4, 24, 0 },
5275         { 5, 4, 32, 0 },
5276     };
5277     BYTE buf[sizeof(tiff_1x1_data)];
5278     GpStatus status;
5279     GpImage *image;
5280     UINT count, i;
5281     struct IFD_entry *tag, *tag_photo = NULL, *tag_bps = NULL, *tag_samples = NULL, *tag_colormap = NULL;
5282     short *bps;
5283     ImageType type;
5284     PixelFormat format;
5285 
5286     memcpy(buf, &tiff_1x1_data, sizeof(tiff_1x1_data));
5287 
5288     count = *(short *)(buf + tiff_1x1_data.dir_offset);
5289     tag = (struct IFD_entry *)(buf + tiff_1x1_data.dir_offset + sizeof(short));
5290 
5291     /* verify the TIFF structure */
5292     for (i = 0; i < count; i++)
5293     {
5294         if (tag[i].id == 0x102) /* BitsPerSample */
5295             tag_bps = &tag[i];
5296         else if (tag[i].id == 0x106) /* PhotometricInterpretation */
5297             tag_photo = &tag[i];
5298         else if (tag[i].id == 0x115) /* SamplesPerPixel */
5299             tag_samples = &tag[i];
5300         else if (tag[i].id == 0x140) /* ColorMap */
5301             tag_colormap = &tag[i];
5302     }
5303 
5304     ok(tag_bps && tag_photo && tag_samples && tag_colormap, "tag 0x102,0x106,0x115 or 0x140 is missing\n");
5305     if (!tag_bps || !tag_photo || !tag_samples || !tag_colormap) return;
5306 
5307     ok(tag_bps->type == IFD_SHORT, "tag 0x102 should have type IFD_SHORT\n");
5308     bps = (short *)(buf + tag_bps->value);
5309     ok(bps[0] == 8 && bps[1] == 8 && bps[2] == 8 && bps[3] == 0,
5310        "expected bps 8,8,8,0 got %d,%d,%d,%d\n", bps[0], bps[1], bps[2], bps[3]);
5311 
5312     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
5313     {
5314         tag_colormap->count = (1 << td[i].bps) * 3;
5315         tag_photo->value = td[i].photometric;
5316         tag_bps->count = td[i].samples;
5317         tag_samples->value = td[i].samples;
5318 
5319         if (td[i].samples == 1)
5320             tag_bps->value = td[i].bps;
5321         else if (td[i].samples == 2)
5322             tag_bps->value = MAKELONG(td[i].bps, td[i].bps);
5323         else if (td[i].samples == 3)
5324         {
5325             tag_bps->value = (BYTE *)bps - buf;
5326             bps[0] = bps[1] = bps[2] = td[i].bps;
5327         }
5328         else if (td[i].samples == 4)
5329         {
5330             tag_bps->value = (BYTE *)bps - buf;
5331             bps[0] = bps[1] = bps[2] = bps[3] = td[i].bps;
5332         }
5333         else
5334         {
5335             ok(0, "%u: unsupported samples count %d\n", i, td[i].samples);
5336             continue;
5337         }
5338 
5339         image = load_image(buf, sizeof(buf));
5340         if (!td[i].format)
5341             ok(!image,
5342                "%u: (%d,%d,%d) TIFF image loading should have failed\n", i, td[i].photometric, td[i].samples, td[i].bps);
5343         else
5344             ok(image != NULL || broken(!image) /* XP */, "%u: failed to load TIFF image data (%d,%d,%d)\n",
5345                i, td[i].photometric, td[i].samples, td[i].bps);
5346         if (!image) continue;
5347 
5348         status = GdipGetImageType(image, &type);
5349         ok(status == Ok, "%u: GdipGetImageType error %d\n", i, status);
5350         ok(type == ImageTypeBitmap, "%u: wrong image type %d\n", i, type);
5351 
5352         status = GdipGetImagePixelFormat(image, &format);
5353         expect(Ok, status);
5354         ok(format == td[i].format,
5355            "%u: expected %#x, got %#x\n", i, td[i].format, format);
5356 
5357         GdipDisposeImage(image);
5358     }
5359 }
5360 
5361 START_TEST(image)
5362 {
5363     HMODULE mod = GetModuleHandleA("gdiplus.dll");
5364     struct GdiplusStartupInput gdiplusStartupInput;
5365     ULONG_PTR gdiplusToken;
5366     HMODULE hmsvcrt;
5367     int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask);
5368 
5369     /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */
5370     hmsvcrt = LoadLibraryA("msvcrt");
5371     _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s");
5372     if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e);
5373 
5374     gdiplusStartupInput.GdiplusVersion              = 1;
5375     gdiplusStartupInput.DebugEventCallback          = NULL;
5376     gdiplusStartupInput.SuppressBackgroundThread    = 0;
5377     gdiplusStartupInput.SuppressExternalCodecs      = 0;
5378 
5379     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
5380 
5381     pGdipBitmapGetHistogramSize = (void*)GetProcAddress(mod, "GdipBitmapGetHistogramSize");
5382     pGdipBitmapGetHistogram = (void*)GetProcAddress(mod, "GdipBitmapGetHistogram");
5383     pGdipImageSetAbort = (void*)GetProcAddress(mod, "GdipImageSetAbort");
5384 
5385     test_tiff_color_formats();
5386     test_GdipInitializePalette();
5387     test_png_color_formats();
5388     test_supported_encoders();
5389     test_CloneBitmapArea();
5390     test_ARGB_conversion();
5391     test_DrawImage_scale();
5392     test_image_format();
5393     test_DrawImage();
5394     test_DrawImage_SourceCopy();
5395     test_GdipDrawImagePointRect();
5396     test_bitmapbits();
5397     test_tiff_palette();
5398     test_GdipGetAllPropertyItems();
5399     test_tiff_properties();
5400     test_gif_properties();
5401     test_image_properties();
5402     test_Scan0();
5403     test_FromGdiDib();
5404     test_GetImageDimension();
5405     test_GdipImageGetFrameDimensionsCount();
5406     test_LoadingImages();
5407     test_SavingImages();
5408     test_encoders();
5409     test_LockBits();
5410     test_LockBits_UserBuf();
5411     test_GdipCreateBitmapFromHBITMAP();
5412     test_GdipGetImageFlags();
5413     test_GdipCloneImage();
5414     test_testcontrol();
5415     test_fromhicon();
5416     test_getrawformat();
5417     test_loadwmf();
5418     test_createfromwmf();
5419     test_createfromwmf_noplaceable();
5420     test_resolution();
5421     test_createhbitmap();
5422     test_getthumbnail();
5423     test_getsetpixel();
5424     test_palette();
5425     test_colormatrix();
5426     test_gamma();
5427     test_multiframegif();
5428     test_rotateflip();
5429     test_remaptable();
5430     test_colorkey();
5431     test_dispose();
5432     test_createeffect();
5433     test_getadjustedpalette();
5434     test_histogram();
5435     test_imageabort();
5436 
5437     GdiplusShutdown(gdiplusToken);
5438 }
5439