jscript: Added Object function invocation implementation.
[wine] / dlls / gdiplus / image.c
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define NONAMELESSUNION
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "wingdi.h"
27
28 #define COBJMACROS
29 #include "objbase.h"
30 #include "olectl.h"
31 #include "ole2.h"
32
33 #include "initguid.h"
34 #include "wincodec.h"
35 #include "gdiplus.h"
36 #include "gdiplus_private.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
40
41 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
42
43 static INT ipicture_pixel_height(IPicture *pic)
44 {
45     HDC hdcref;
46     OLE_YSIZE_HIMETRIC y;
47
48     IPicture_get_Height(pic, &y);
49
50     hdcref = GetDC(0);
51
52     y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
53     ReleaseDC(0, hdcref);
54
55     return y;
56 }
57
58 static INT ipicture_pixel_width(IPicture *pic)
59 {
60     HDC hdcref;
61     OLE_XSIZE_HIMETRIC x;
62
63     IPicture_get_Width(pic, &x);
64
65     hdcref = GetDC(0);
66
67     x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
68
69     ReleaseDC(0, hdcref);
70
71     return x;
72 }
73
74 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
75     RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
76 {
77     FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
78     /*
79      * Note: According to Jose Roca's GDI+ docs, this function is not
80      * implemented in Windows's GDI+.
81      */
82     return NotImplemented;
83 }
84
85 GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
86     INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
87     GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
88 {
89     FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
90     /*
91      * Note: According to Jose Roca's GDI+ docs, this function is not
92      * implemented in Windows's GDI+.
93      */
94     return NotImplemented;
95 }
96
97 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
98     ARGB *color)
99 {
100     static int calls;
101     TRACE("%p %d %d %p\n", bitmap, x, y, color);
102
103     if(!bitmap || !color)
104         return InvalidParameter;
105
106     if(!(calls++))
107         FIXME("not implemented\n");
108
109     *color = 0xdeadbeef;
110
111     return NotImplemented;
112 }
113
114 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
115     ARGB color)
116 {
117     static int calls;
118     TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color);
119
120     if(!bitmap)
121         return InvalidParameter;
122
123     if(!(calls++))
124         FIXME("not implemented\n");
125
126     return NotImplemented;
127 }
128
129 /* This function returns a pointer to an array of pixels that represents the
130  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
131  * flags.  It is correct behavior that a user who calls this function with write
132  * privileges can write to the whole bitmap (not just the area in rect).
133  *
134  * FIXME: only used portion of format is bits per pixel. */
135 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
136     UINT flags, PixelFormat format, BitmapData* lockeddata)
137 {
138     BOOL bm_is_selected;
139     INT stride, bitspp = PIXELFORMATBPP(format);
140     HDC hdc;
141     HBITMAP hbm, old = NULL;
142     BITMAPINFO *pbmi;
143     BYTE *buff = NULL;
144     UINT abs_height;
145     GpRect act_rect; /* actual rect to be used */
146
147     TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
148
149     if(!lockeddata || !bitmap)
150         return InvalidParameter;
151
152     if(rect){
153         if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
154           (rect->Y + rect->Height > bitmap->height) || !flags)
155             return InvalidParameter;
156
157         act_rect = *rect;
158     }
159     else{
160         act_rect.X = act_rect.Y = 0;
161         act_rect.Width  = bitmap->width;
162         act_rect.Height = bitmap->height;
163     }
164
165     if(flags & ImageLockModeUserInputBuf)
166         return NotImplemented;
167
168     if(bitmap->lockmode)
169         return WrongState;
170
171     if (bitmap->bits && bitmap->format == format)
172     {
173         /* no conversion is necessary; just use the bits directly */
174         lockeddata->Width = act_rect.Width;
175         lockeddata->Height = act_rect.Height;
176         lockeddata->PixelFormat = format;
177         lockeddata->Reserved = flags;
178         lockeddata->Stride = bitmap->stride;
179         lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
180                             bitmap->stride * act_rect.Y;
181
182         bitmap->lockmode = flags;
183         bitmap->numlocks++;
184
185         return Ok;
186     }
187
188     hbm = bitmap->hbitmap;
189     hdc = bitmap->hdc;
190     bm_is_selected = (hdc != 0);
191
192     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
193     if (!pbmi)
194         return OutOfMemory;
195     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
196     pbmi->bmiHeader.biBitCount = 0;
197
198     if(!bm_is_selected){
199         hdc = CreateCompatibleDC(0);
200         old = SelectObject(hdc, hbm);
201     }
202
203     /* fill out bmi */
204     GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
205
206     abs_height = abs(pbmi->bmiHeader.biHeight);
207     stride = pbmi->bmiHeader.biWidth * bitspp / 8;
208     stride = (stride + 3) & ~3;
209
210     buff = GdipAlloc(stride * abs_height);
211
212     pbmi->bmiHeader.biBitCount = bitspp;
213
214     if(buff)
215         GetDIBits(hdc, hbm, 0, abs_height, buff, pbmi, DIB_RGB_COLORS);
216
217     if(!bm_is_selected){
218         SelectObject(hdc, old);
219         DeleteDC(hdc);
220     }
221
222     if(!buff){
223         GdipFree(pbmi);
224         return OutOfMemory;
225     }
226
227     lockeddata->Width  = act_rect.Width;
228     lockeddata->Height = act_rect.Height;
229     lockeddata->PixelFormat = format;
230     lockeddata->Reserved = flags;
231
232     if(pbmi->bmiHeader.biHeight > 0){
233         lockeddata->Stride = -stride;
234         lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X +
235                              stride * (abs_height - 1 - act_rect.Y);
236     }
237     else{
238         lockeddata->Stride = stride;
239         lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
240     }
241
242     bitmap->lockmode = flags;
243     bitmap->numlocks++;
244
245     bitmap->bitmapbits = buff;
246
247     GdipFree(pbmi);
248     return Ok;
249 }
250
251 GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi)
252 {
253     FIXME("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
254
255     return NotImplemented;
256 }
257
258 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
259     BitmapData* lockeddata)
260 {
261     HDC hdc;
262     HBITMAP hbm, old = NULL;
263     BOOL bm_is_selected;
264     BITMAPINFO *pbmi;
265
266     if(!bitmap || !lockeddata)
267         return InvalidParameter;
268
269     if(!bitmap->lockmode)
270         return WrongState;
271
272     if(lockeddata->Reserved & ImageLockModeUserInputBuf)
273         return NotImplemented;
274
275     if(lockeddata->Reserved & ImageLockModeRead){
276         if(!(--bitmap->numlocks))
277             bitmap->lockmode = 0;
278
279         GdipFree(bitmap->bitmapbits);
280         bitmap->bitmapbits = NULL;
281         return Ok;
282     }
283
284     if (!bitmap->bitmapbits)
285     {
286         /* we passed a direct reference; no need to do anything */
287         bitmap->lockmode = 0;
288         return Ok;
289     }
290
291     hbm = bitmap->hbitmap;
292     hdc = bitmap->hdc;
293     bm_is_selected = (hdc != 0);
294
295     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
296     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
297     pbmi->bmiHeader.biBitCount = 0;
298
299     if(!bm_is_selected){
300         hdc = CreateCompatibleDC(0);
301         old = SelectObject(hdc, hbm);
302     }
303
304     GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
305     pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
306     SetDIBits(hdc, hbm, 0, abs(pbmi->bmiHeader.biHeight),
307               bitmap->bitmapbits, pbmi, DIB_RGB_COLORS);
308
309     if(!bm_is_selected){
310         SelectObject(hdc, old);
311         DeleteDC(hdc);
312     }
313
314     GdipFree(pbmi);
315     GdipFree(bitmap->bitmapbits);
316     bitmap->bitmapbits = NULL;
317     bitmap->lockmode = 0;
318
319     return Ok;
320 }
321
322 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
323     PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
324 {
325     FIXME("(%f,%f,%f,%f,%i,%p,%p): stub\n", x, y, width, height, format, srcBitmap, dstBitmap);
326
327     return NotImplemented;
328 }
329
330 GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
331     PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
332 {
333     FIXME("(%i,%i,%i,%i,%i,%p,%p): stub\n", x, y, width, height, format, srcBitmap, dstBitmap);
334
335     return NotImplemented;
336 }
337
338 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
339 {
340     GpStatus stat = GenericError;
341
342     TRACE("%p, %p\n", image, cloneImage);
343
344     if (!image || !cloneImage)
345         return InvalidParameter;
346
347     if (image->picture)
348     {
349         IStream* stream;
350         HRESULT hr;
351         INT size;
352         LARGE_INTEGER move;
353
354         hr = CreateStreamOnHGlobal(0, TRUE, &stream);
355         if (FAILED(hr))
356             return GenericError;
357
358         hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
359         if(FAILED(hr))
360         {
361             WARN("Failed to save image on stream\n");
362             goto out;
363         }
364
365         /* Set seek pointer back to the beginning of the picture */
366         move.QuadPart = 0;
367         hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
368         if (FAILED(hr))
369             goto out;
370
371         stat = GdipLoadImageFromStream(stream, cloneImage);
372         if (stat != Ok) WARN("Failed to load image from stream\n");
373
374     out:
375         IStream_Release(stream);
376         return stat;
377     }
378     else if (image->type == ImageTypeBitmap)
379     {
380         GpBitmap *bitmap = (GpBitmap*)image;
381         BitmapData lockeddata_src, lockeddata_dst;
382         int i;
383         UINT row_size;
384
385         stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
386             &lockeddata_src);
387         if (stat != Ok) return stat;
388
389         stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
390             0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
391         if (stat == Ok)
392         {
393             stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
394                 lockeddata_src.PixelFormat, &lockeddata_dst);
395
396             if (stat == Ok)
397             {
398                 /* copy the image data */
399                 row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
400                 for (i=0; i<lockeddata_src.Height; i++)
401                     memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
402                            (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
403                            row_size);
404
405                 GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
406             }
407
408             GdipBitmapUnlockBits(bitmap, &lockeddata_src);
409         }
410
411         if (stat != Ok)
412         {
413             GdipDisposeImage(*cloneImage);
414             *cloneImage = NULL;
415         }
416
417         memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
418
419         return stat;
420     }
421     else
422     {
423         ERR("GpImage with no IPicture or bitmap?!\n");
424         return NotImplemented;
425     }
426 }
427
428 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
429     GpBitmap **bitmap)
430 {
431     GpStatus stat;
432     IStream *stream;
433
434     TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
435
436     if(!filename || !bitmap)
437         return InvalidParameter;
438
439     stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
440
441     if(stat != Ok)
442         return stat;
443
444     stat = GdipCreateBitmapFromStream(stream, bitmap);
445
446     IStream_Release(stream);
447
448     return stat;
449 }
450
451 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info,
452                                                VOID *bits, GpBitmap **bitmap)
453 {
454     DWORD height, stride;
455     PixelFormat format;
456
457     FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
458
459     height = abs(info->bmiHeader.biHeight);
460     stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
461
462     if(info->bmiHeader.biHeight > 0) /* bottom-up */
463     {
464         bits = (BYTE*)bits + (height - 1) * stride;
465         stride = -stride;
466     }
467
468     switch(info->bmiHeader.biBitCount) {
469     case 1:
470         format = PixelFormat1bppIndexed;
471         break;
472     case 4:
473         format = PixelFormat4bppIndexed;
474         break;
475     case 8:
476         format = PixelFormat8bppIndexed;
477         break;
478     case 24:
479         format = PixelFormat24bppRGB;
480         break;
481     default:
482         FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
483         *bitmap = NULL;
484         return InvalidParameter;
485     }
486
487     return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
488                                      bits, bitmap);
489
490 }
491
492 /* FIXME: no icm */
493 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename,
494     GpBitmap **bitmap)
495 {
496     TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
497
498     return GdipCreateBitmapFromFile(filename, bitmap);
499 }
500
501 GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
502     GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
503 {
504     HBITMAP hbm;
505     GpStatus stat = InvalidParameter;
506
507     TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
508
509     if(!lpBitmapName || !bitmap)
510         return InvalidParameter;
511
512     /* load DIB */
513     hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
514                      LR_CREATEDIBSECTION);
515
516     if(hbm){
517         stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
518         DeleteObject(hbm);
519     }
520
521     return stat;
522 }
523
524 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
525     HBITMAP* hbmReturn, ARGB background)
526 {
527     GpStatus stat;
528     HBITMAP result, oldbitmap;
529     UINT width, height;
530     HDC hdc;
531     GpGraphics *graphics;
532     BITMAPINFOHEADER bih;
533     void *bits;
534     TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
535
536     if (!bitmap || !hbmReturn) return InvalidParameter;
537
538     GdipGetImageWidth((GpImage*)bitmap, &width);
539     GdipGetImageHeight((GpImage*)bitmap, &height);
540
541     bih.biSize = sizeof(bih);
542     bih.biWidth = width;
543     bih.biHeight = height;
544     bih.biPlanes = 1;
545     bih.biBitCount = 32;
546     bih.biCompression = BI_RGB;
547     bih.biSizeImage = 0;
548     bih.biXPelsPerMeter = 0;
549     bih.biYPelsPerMeter = 0;
550     bih.biClrUsed = 0;
551     bih.biClrImportant = 0;
552
553     hdc = CreateCompatibleDC(NULL);
554     if (!hdc) return GenericError;
555
556     result = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, &bits,
557         NULL, 0);
558
559     if (result)
560     {
561         oldbitmap = SelectObject(hdc, result);
562
563         stat = GdipCreateFromHDC(hdc, &graphics);
564         if (stat == Ok)
565         {
566             stat = GdipGraphicsClear(graphics, background);
567
568             if (stat == Ok)
569                 stat = GdipDrawImage(graphics, (GpImage*)bitmap, 0, 0);
570
571             GdipDeleteGraphics(graphics);
572         }
573
574         SelectObject(hdc, oldbitmap);
575     }
576     else
577         stat = GenericError;
578
579     DeleteDC(hdc);
580
581     if (stat != Ok && result)
582     {
583         DeleteObject(result);
584         result = NULL;
585     }
586
587     *hbmReturn = result;
588
589     return stat;
590 }
591
592 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
593     GpMetafile* metafile, BOOL* succ, EmfType emfType,
594     const WCHAR* description, GpMetafile** out_metafile)
595 {
596     static int calls;
597
598     if(!ref || !metafile || !out_metafile)
599         return InvalidParameter;
600
601     *succ = FALSE;
602     *out_metafile = NULL;
603
604     if(!(calls++))
605         FIXME("not implemented\n");
606
607     return NotImplemented;
608 }
609
610 /* FIXME: this should create a bitmap in the given size with the attributes
611  * (resolution etc.) of the graphics object */
612 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
613     GpGraphics* target, GpBitmap** bitmap)
614 {
615     static int calls;
616     GpStatus ret;
617
618     if(!target || !bitmap)
619         return InvalidParameter;
620
621     if(!(calls++))
622         FIXME("hacked stub\n");
623
624     ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat24bppRGB,
625                                     NULL, bitmap);
626
627     return ret;
628 }
629
630 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
631 {
632     GpStatus stat;
633     ICONINFO iinfo;
634     BITMAP bm;
635     int ret;
636     UINT width, height;
637     GpRect rect;
638     BitmapData lockeddata;
639     HDC screendc;
640     BOOL has_alpha;
641     int x, y;
642     BYTE *bits;
643     BITMAPINFOHEADER bih;
644     DWORD *src;
645     BYTE *dst_row;
646     DWORD *dst;
647
648     TRACE("%p, %p\n", hicon, bitmap);
649
650     if(!bitmap || !GetIconInfo(hicon, &iinfo))
651     {
652         DeleteObject(iinfo.hbmColor);
653         DeleteObject(iinfo.hbmMask);
654         return InvalidParameter;
655     }
656
657     /* get the size of the icon */
658     ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
659     if (ret == 0) {
660         DeleteObject(iinfo.hbmColor);
661         DeleteObject(iinfo.hbmMask);
662         return GenericError;
663     }
664
665     width = bm.bmWidth;
666
667     if (iinfo.hbmColor)
668         height = abs(bm.bmHeight);
669     else /* combined bitmap + mask */
670         height = abs(bm.bmHeight) / 2;
671
672     bits = HeapAlloc(GetProcessHeap(), 0, 4*width*height);
673     if (!bits) {
674         DeleteObject(iinfo.hbmColor);
675         DeleteObject(iinfo.hbmMask);
676         return OutOfMemory;
677     }
678
679     stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB, NULL, bitmap);
680     if (stat != Ok) {
681         DeleteObject(iinfo.hbmColor);
682         DeleteObject(iinfo.hbmMask);
683         HeapFree(GetProcessHeap(), 0, bits);
684         return stat;
685     }
686
687     rect.X = 0;
688     rect.Y = 0;
689     rect.Width = width;
690     rect.Height = height;
691
692     stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
693     if (stat != Ok) {
694         DeleteObject(iinfo.hbmColor);
695         DeleteObject(iinfo.hbmMask);
696         HeapFree(GetProcessHeap(), 0, bits);
697         GdipDisposeImage((GpImage*)*bitmap);
698         return stat;
699     }
700
701     bih.biSize = sizeof(bih);
702     bih.biWidth = width;
703     bih.biHeight = -height;
704     bih.biPlanes = 1;
705     bih.biBitCount = 32;
706     bih.biCompression = BI_RGB;
707     bih.biSizeImage = 0;
708     bih.biXPelsPerMeter = 0;
709     bih.biYPelsPerMeter = 0;
710     bih.biClrUsed = 0;
711     bih.biClrImportant = 0;
712
713     screendc = GetDC(0);
714     if (iinfo.hbmColor)
715     {
716         GetDIBits(screendc, iinfo.hbmColor, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
717
718         if (bm.bmBitsPixel == 32)
719         {
720             has_alpha = FALSE;
721
722             /* If any pixel has a non-zero alpha, ignore hbmMask */
723             src = (DWORD*)bits;
724             for (x=0; x<width && !has_alpha; x++)
725                 for (y=0; y<height && !has_alpha; y++)
726                     if ((*src++ & 0xff000000) != 0)
727                         has_alpha = TRUE;
728         }
729         else has_alpha = FALSE;
730     }
731     else
732     {
733         GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
734         has_alpha = FALSE;
735     }
736
737     /* copy the image data to the Bitmap */
738     src = (DWORD*)bits;
739     dst_row = lockeddata.Scan0;
740     for (y=0; y<height; y++)
741     {
742         memcpy(dst_row, src, width*4);
743         src += width;
744         dst_row += lockeddata.Stride;
745     }
746
747     if (!has_alpha)
748     {
749         if (iinfo.hbmMask)
750         {
751             /* read alpha data from the mask */
752             if (iinfo.hbmColor)
753                 GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
754             else
755                 GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
756
757             src = (DWORD*)bits;
758             dst_row = lockeddata.Scan0;
759             for (y=0; y<height; y++)
760             {
761                 dst = (DWORD*)dst_row;
762                 for (x=0; x<height; x++)
763                 {
764                     DWORD src_value = *src++;
765                     if (src_value)
766                         *dst++ = 0;
767                     else
768                         *dst++ |= 0xff000000;
769                 }
770                 dst_row += lockeddata.Stride;
771             }
772         }
773         else
774         {
775             /* set constant alpha of 255 */
776             dst_row = bits;
777             for (y=0; y<height; y++)
778             {
779                 dst = (DWORD*)dst_row;
780                 for (x=0; x<height; x++)
781                     *dst++ |= 0xff000000;
782                 dst_row += lockeddata.Stride;
783             }
784         }
785     }
786
787     ReleaseDC(0, screendc);
788
789     DeleteObject(iinfo.hbmColor);
790     DeleteObject(iinfo.hbmMask);
791
792     GdipBitmapUnlockBits(*bitmap, &lockeddata);
793
794     HeapFree(GetProcessHeap(), 0, bits);
795
796     return Ok;
797 }
798
799 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
800     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
801 {
802     BITMAPINFOHEADER bmih;
803     HBITMAP hbitmap;
804     INT row_size, dib_stride;
805     HDC hdc;
806     BYTE *bits;
807     int i;
808
809     TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
810
811     if (!bitmap) return InvalidParameter;
812
813     if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
814         *bitmap = NULL;
815         return InvalidParameter;
816     }
817
818     if(scan0 && !stride)
819         return InvalidParameter;
820
821     row_size = (width * PIXELFORMATBPP(format)+7) / 8;
822     dib_stride = (row_size + 3) & ~3;
823
824     if(stride == 0)
825         stride = dib_stride;
826
827     bmih.biSize = sizeof(BITMAPINFOHEADER);
828     bmih.biWidth = width;
829     bmih.biHeight = -height;
830     bmih.biPlanes = 1;
831     /* FIXME: use the rest of the data from format */
832     bmih.biBitCount = PIXELFORMATBPP(format);
833     bmih.biCompression = BI_RGB;
834     bmih.biSizeImage = 0;
835     bmih.biXPelsPerMeter = 0;
836     bmih.biYPelsPerMeter = 0;
837     bmih.biClrUsed = 0;
838     bmih.biClrImportant = 0;
839
840     hdc = CreateCompatibleDC(NULL);
841     if (!hdc) return GenericError;
842
843     hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits,
844         NULL, 0);
845
846     DeleteDC(hdc);
847
848     if (!hbitmap) return GenericError;
849
850     /* copy bits to the dib if necessary */
851     /* FIXME: should reference the bits instead of copying them */
852     if (scan0)
853         for (i=0; i<height; i++)
854             memcpy(bits+i*dib_stride, scan0+i*stride, row_size);
855
856     *bitmap = GdipAlloc(sizeof(GpBitmap));
857     if(!*bitmap)
858     {
859         DeleteObject(hbitmap);
860         return OutOfMemory;
861     }
862
863     (*bitmap)->image.type = ImageTypeBitmap;
864     memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
865     (*bitmap)->image.flags = ImageFlagsNone;
866     (*bitmap)->width = width;
867     (*bitmap)->height = height;
868     (*bitmap)->format = format;
869     (*bitmap)->image.picture = NULL;
870     (*bitmap)->hbitmap = hbitmap;
871     (*bitmap)->hdc = NULL;
872     (*bitmap)->bits = bits;
873     (*bitmap)->stride = dib_stride;
874
875     return Ok;
876 }
877
878 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
879     GpBitmap **bitmap)
880 {
881     GpStatus stat;
882
883     TRACE("%p %p\n", stream, bitmap);
884
885     stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
886
887     if(stat != Ok)
888         return stat;
889
890     if((*bitmap)->image.type != ImageTypeBitmap){
891         GdipDisposeImage(&(*bitmap)->image);
892         *bitmap = NULL;
893         return GenericError; /* FIXME: what error to return? */
894     }
895
896     return Ok;
897 }
898
899 /* FIXME: no icm */
900 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
901     GpBitmap **bitmap)
902 {
903     TRACE("%p %p\n", stream, bitmap);
904
905     return GdipCreateBitmapFromStream(stream, bitmap);
906 }
907
908 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
909     GpCachedBitmap **cachedbmp)
910 {
911     GpStatus stat;
912
913     TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
914
915     if(!bitmap || !graphics || !cachedbmp)
916         return InvalidParameter;
917
918     *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
919     if(!*cachedbmp)
920         return OutOfMemory;
921
922     stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
923     if(stat != Ok){
924         GdipFree(*cachedbmp);
925         return stat;
926     }
927
928     return Ok;
929 }
930
931 GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon)
932 {
933     FIXME("(%p, %p)\n", bitmap, hicon);
934
935     return NotImplemented;
936 }
937
938 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
939 {
940     TRACE("%p\n", cachedbmp);
941
942     if(!cachedbmp)
943         return InvalidParameter;
944
945     GdipDisposeImage(cachedbmp->image);
946     GdipFree(cachedbmp);
947
948     return Ok;
949 }
950
951 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
952     GpCachedBitmap *cachedbmp, INT x, INT y)
953 {
954     TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
955
956     if(!graphics || !cachedbmp)
957         return InvalidParameter;
958
959     return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
960 }
961
962 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
963     LPBYTE pData16, INT iMapMode, INT eFlags)
964 {
965     FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
966     return NotImplemented;
967 }
968
969 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
970 {
971     TRACE("%p\n", image);
972
973     if(!image)
974         return InvalidParameter;
975
976     if (image->picture)
977         IPicture_Release(image->picture);
978     if (image->type == ImageTypeBitmap)
979     {
980         GdipFree(((GpBitmap*)image)->bitmapbits);
981         DeleteDC(((GpBitmap*)image)->hdc);
982     }
983     GdipFree(image);
984
985     return Ok;
986 }
987
988 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
989 {
990     if(!image || !item)
991         return InvalidParameter;
992
993     return NotImplemented;
994 }
995
996 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
997     GpUnit *srcUnit)
998 {
999     TRACE("%p %p %p\n", image, srcRect, srcUnit);
1000
1001     if(!image || !srcRect || !srcUnit)
1002         return InvalidParameter;
1003     if(image->type == ImageTypeMetafile){
1004         *srcRect = ((GpMetafile*)image)->bounds;
1005         *srcUnit = ((GpMetafile*)image)->unit;
1006     }
1007     else if(image->type == ImageTypeBitmap){
1008         srcRect->X = srcRect->Y = 0.0;
1009         srcRect->Width = (REAL) ((GpBitmap*)image)->width;
1010         srcRect->Height = (REAL) ((GpBitmap*)image)->height;
1011         *srcUnit = UnitPixel;
1012     }
1013     else{
1014         srcRect->X = srcRect->Y = 0.0;
1015         srcRect->Width = ipicture_pixel_width(image->picture);
1016         srcRect->Height = ipicture_pixel_height(image->picture);
1017         *srcUnit = UnitPixel;
1018     }
1019
1020     TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
1021           srcRect->Width, srcRect->Height, *srcUnit);
1022
1023     return Ok;
1024 }
1025
1026 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
1027     REAL *height)
1028 {
1029     TRACE("%p %p %p\n", image, width, height);
1030
1031     if(!image || !height || !width)
1032         return InvalidParameter;
1033
1034     if(image->type == ImageTypeMetafile){
1035         HDC hdc = GetDC(0);
1036
1037         *height = convert_unit(hdc, ((GpMetafile*)image)->unit) *
1038                         ((GpMetafile*)image)->bounds.Height;
1039
1040         *width = convert_unit(hdc, ((GpMetafile*)image)->unit) *
1041                         ((GpMetafile*)image)->bounds.Width;
1042
1043         ReleaseDC(0, hdc);
1044     }
1045
1046     else if(image->type == ImageTypeBitmap){
1047         *height = ((GpBitmap*)image)->height;
1048         *width = ((GpBitmap*)image)->width;
1049     }
1050     else{
1051         *height = ipicture_pixel_height(image->picture);
1052         *width = ipicture_pixel_width(image->picture);
1053     }
1054
1055     TRACE("returning (%f, %f)\n", *height, *width);
1056     return Ok;
1057 }
1058
1059 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
1060     GpGraphics **graphics)
1061 {
1062     HDC hdc;
1063
1064     TRACE("%p %p\n", image, graphics);
1065
1066     if(!image || !graphics)
1067         return InvalidParameter;
1068
1069     if(image->type != ImageTypeBitmap){
1070         FIXME("not implemented for image type %d\n", image->type);
1071         return NotImplemented;
1072     }
1073
1074     hdc = ((GpBitmap*)image)->hdc;
1075
1076     if(!hdc){
1077         hdc = CreateCompatibleDC(0);
1078         SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
1079         ((GpBitmap*)image)->hdc = hdc;
1080     }
1081
1082     return GdipCreateFromHDC(hdc, graphics);
1083 }
1084
1085 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
1086 {
1087     TRACE("%p %p\n", image, height);
1088
1089     if(!image || !height)
1090         return InvalidParameter;
1091
1092     if(image->type == ImageTypeMetafile){
1093         HDC hdc = GetDC(0);
1094
1095         *height = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
1096                         ((GpMetafile*)image)->bounds.Height);
1097
1098         ReleaseDC(0, hdc);
1099     }
1100     else if(image->type == ImageTypeBitmap)
1101         *height = ((GpBitmap*)image)->height;
1102     else
1103         *height = ipicture_pixel_height(image->picture);
1104
1105     TRACE("returning %d\n", *height);
1106
1107     return Ok;
1108 }
1109
1110 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
1111 {
1112     static int calls;
1113
1114     if(!image || !res)
1115         return InvalidParameter;
1116
1117     if(!(calls++))
1118         FIXME("not implemented\n");
1119
1120     return NotImplemented;
1121 }
1122
1123 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
1124 {
1125     FIXME("%p %p\n", image, size);
1126
1127     if(!image || !size)
1128         return InvalidParameter;
1129
1130     return NotImplemented;
1131 }
1132
1133 /* FIXME: test this function for non-bitmap types */
1134 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
1135 {
1136     TRACE("%p %p\n", image, format);
1137
1138     if(!image || !format)
1139         return InvalidParameter;
1140
1141     if(image->type != ImageTypeBitmap)
1142         *format = PixelFormat24bppRGB;
1143     else
1144         *format = ((GpBitmap*) image)->format;
1145
1146     return Ok;
1147 }
1148
1149 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
1150 {
1151     if(!image || !format)
1152         return InvalidParameter;
1153
1154     memcpy(format, &image->format, sizeof(GUID));
1155
1156     return Ok;
1157 }
1158
1159 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
1160 {
1161     TRACE("%p %p\n", image, type);
1162
1163     if(!image || !type)
1164         return InvalidParameter;
1165
1166     *type = image->type;
1167
1168     return Ok;
1169 }
1170
1171 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
1172 {
1173     static int calls;
1174
1175     if(!image || !res)
1176         return InvalidParameter;
1177
1178     if(!(calls++))
1179         FIXME("not implemented\n");
1180
1181     return NotImplemented;
1182 }
1183
1184 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
1185 {
1186     TRACE("%p %p\n", image, width);
1187
1188     if(!image || !width)
1189         return InvalidParameter;
1190
1191     if(image->type == ImageTypeMetafile){
1192         HDC hdc = GetDC(0);
1193
1194         *width = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
1195                         ((GpMetafile*)image)->bounds.Width);
1196
1197         ReleaseDC(0, hdc);
1198     }
1199     else if(image->type == ImageTypeBitmap)
1200         *width = ((GpBitmap*)image)->width;
1201     else
1202         *width = ipicture_pixel_width(image->picture);
1203
1204     TRACE("returning %d\n", *width);
1205
1206     return Ok;
1207 }
1208
1209 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
1210     MetafileHeader * header)
1211 {
1212     static int calls;
1213
1214     if(!metafile || !header)
1215         return InvalidParameter;
1216
1217     if(!(calls++))
1218         FIXME("not implemented\n");
1219
1220     return Ok;
1221 }
1222
1223 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
1224     UINT num, PropertyItem* items)
1225 {
1226     static int calls;
1227
1228     if(!(calls++))
1229         FIXME("not implemented\n");
1230
1231     return InvalidParameter;
1232 }
1233
1234 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT* num)
1235 {
1236     static int calls;
1237
1238     if(!(calls++))
1239         FIXME("not implemented\n");
1240
1241     return InvalidParameter;
1242 }
1243
1244 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID* list)
1245 {
1246     static int calls;
1247
1248     if(!(calls++))
1249         FIXME("not implemented\n");
1250
1251     return InvalidParameter;
1252 }
1253
1254 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID id, UINT size,
1255     PropertyItem* buffer)
1256 {
1257     static int calls;
1258
1259     if(!(calls++))
1260         FIXME("not implemented\n");
1261
1262     return InvalidParameter;
1263 }
1264
1265 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
1266     UINT* size)
1267 {
1268     static int calls;
1269
1270     TRACE("%p %x %p\n", image, pid, size);
1271
1272     if(!size || !image)
1273         return InvalidParameter;
1274
1275     if(!(calls++))
1276         FIXME("not implemented\n");
1277
1278     return NotImplemented;
1279 }
1280
1281 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT* size, UINT* num)
1282 {
1283     static int calls;
1284
1285     if(!(calls++))
1286         FIXME("not implemented\n");
1287
1288     return InvalidParameter;
1289 }
1290
1291 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
1292     GDIPCONST GUID* dimensionID, UINT* count)
1293 {
1294     static int calls;
1295
1296     if(!image || !dimensionID || !count)
1297         return InvalidParameter;
1298
1299     if(!(calls++))
1300         FIXME("not implemented\n");
1301
1302     return NotImplemented;
1303 }
1304
1305 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
1306     UINT* count)
1307 {
1308     if(!image || !count)
1309         return InvalidParameter;
1310
1311     *count = 1;
1312
1313     FIXME("stub\n");
1314
1315     return Ok;
1316 }
1317
1318 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
1319     GUID* dimensionIDs, UINT count)
1320 {
1321     static int calls;
1322
1323     if(!image || !dimensionIDs)
1324         return InvalidParameter;
1325
1326     if(!(calls++))
1327         FIXME("not implemented\n");
1328
1329     return Ok;
1330 }
1331
1332 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image,
1333     GDIPCONST GUID* dimensionID, UINT frameidx)
1334 {
1335     static int calls;
1336
1337     if(!image || !dimensionID)
1338         return InvalidParameter;
1339
1340     if(!(calls++))
1341         FIXME("not implemented\n");
1342
1343     return Ok;
1344 }
1345
1346 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
1347                                           GpImage **image)
1348 {
1349     GpStatus stat;
1350     IStream *stream;
1351
1352     TRACE("(%s) %p\n", debugstr_w(filename), image);
1353
1354     if (!filename || !image)
1355         return InvalidParameter;
1356
1357     stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
1358
1359     if (stat != Ok)
1360         return stat;
1361
1362     stat = GdipLoadImageFromStream(stream, image);
1363
1364     IStream_Release(stream);
1365
1366     return stat;
1367 }
1368
1369 /* FIXME: no icm handling */
1370 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
1371 {
1372     TRACE("(%s) %p\n", debugstr_w(filename), image);
1373
1374     return GdipLoadImageFromFile(filename, image);
1375 }
1376
1377 static const WICPixelFormatGUID *wic_pixel_formats[] = {
1378     &GUID_WICPixelFormat16bppBGR555,
1379     &GUID_WICPixelFormat24bppBGR,
1380     &GUID_WICPixelFormat32bppBGR,
1381     &GUID_WICPixelFormat32bppBGRA,
1382     &GUID_WICPixelFormat32bppPBGRA,
1383     NULL
1384 };
1385
1386 static const PixelFormat wic_gdip_formats[] = {
1387     PixelFormat16bppRGB555,
1388     PixelFormat24bppRGB,
1389     PixelFormat32bppRGB,
1390     PixelFormat32bppARGB,
1391     PixelFormat32bppPARGB,
1392 };
1393
1394 static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **image)
1395 {
1396     GpStatus status=Ok;
1397     GpBitmap *bitmap;
1398     HRESULT hr;
1399     IWICBitmapDecoder *decoder;
1400     IWICBitmapFrameDecode *frame;
1401     IWICBitmapSource *source=NULL;
1402     WICPixelFormatGUID wic_format;
1403     PixelFormat gdip_format=0;
1404     int i;
1405     UINT width, height;
1406     BitmapData lockeddata;
1407     WICRect wrc;
1408     HRESULT initresult;
1409
1410     initresult = CoInitialize(NULL);
1411
1412     hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
1413         &IID_IWICBitmapDecoder, (void**)&decoder);
1414     if (FAILED(hr)) goto end;
1415
1416     hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1417     if (SUCCEEDED(hr))
1418         hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1419
1420     if (SUCCEEDED(hr)) /* got frame */
1421     {
1422         hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
1423
1424         if (SUCCEEDED(hr))
1425         {
1426             for (i=0; wic_pixel_formats[i]; i++)
1427             {
1428                 if (IsEqualGUID(&wic_format, wic_pixel_formats[i]))
1429                 {
1430                     source = (IWICBitmapSource*)frame;
1431                     IWICBitmapSource_AddRef(source);
1432                     gdip_format = wic_gdip_formats[i];
1433                     break;
1434                 }
1435             }
1436             if (!source)
1437             {
1438                 /* unknown format; fall back on 32bppARGB */
1439                 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
1440                 gdip_format = PixelFormat32bppARGB;
1441             }
1442         }
1443
1444         if (SUCCEEDED(hr)) /* got source */
1445         {
1446             hr = IWICBitmapSource_GetSize(source, &width, &height);
1447
1448             if (SUCCEEDED(hr))
1449                 status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
1450                     NULL, &bitmap);
1451
1452             if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
1453             {
1454                 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
1455                     gdip_format, &lockeddata);
1456                 if (status == Ok) /* locked bitmap */
1457                 {
1458                     wrc.X = 0;
1459                     wrc.Width = width;
1460                     wrc.Height = 1;
1461                     for (i=0; i<height; i++)
1462                     {
1463                         wrc.Y = i;
1464                         hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
1465                             abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
1466                         if (FAILED(hr)) break;
1467                     }
1468
1469                     GdipBitmapUnlockBits(bitmap, &lockeddata);
1470                 }
1471
1472                 if (SUCCEEDED(hr) && status == Ok)
1473                     *image = (GpImage*)bitmap;
1474                 else
1475                 {
1476                     *image = NULL;
1477                     GdipDisposeImage((GpImage*)bitmap);
1478                 }
1479             }
1480
1481             IWICBitmapSource_Release(source);
1482         }
1483
1484         IWICBitmapFrameDecode_Release(frame);
1485     }
1486
1487     IWICBitmapDecoder_Release(decoder);
1488
1489 end:
1490     if (SUCCEEDED(initresult)) CoUninitialize();
1491
1492     if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
1493
1494     return status;
1495 }
1496
1497 static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **image)
1498 {
1499     return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
1500 }
1501
1502 static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image)
1503 {
1504     GpStatus status;
1505     GpBitmap* bitmap;
1506
1507     status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image);
1508
1509     bitmap = (GpBitmap*)*image;
1510
1511     if (status == Ok && bitmap->format == PixelFormat32bppARGB)
1512     {
1513         /* WIC supports bmp files with alpha, but gdiplus does not */
1514         bitmap->format = PixelFormat32bppRGB;
1515     }
1516
1517     return status;
1518 }
1519
1520 static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
1521 {
1522     return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
1523 }
1524
1525 static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image)
1526 {
1527     return decode_image_wic(stream, &CLSID_WICPngDecoder, image);
1528 }
1529
1530 static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
1531 {
1532     return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
1533 }
1534
1535 static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
1536 {
1537     IPicture *pic;
1538
1539     TRACE("%p %p\n", stream, image);
1540
1541     if(!stream || !image)
1542         return InvalidParameter;
1543
1544     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
1545         (LPVOID*) &pic) != S_OK){
1546         TRACE("Could not load picture\n");
1547         return GenericError;
1548     }
1549
1550     /* FIXME: missing initialization code */
1551     *image = GdipAlloc(sizeof(GpMetafile));
1552     if(!*image) return OutOfMemory;
1553     (*image)->type = ImageTypeMetafile;
1554     (*image)->picture = pic;
1555     (*image)->flags   = ImageFlagsNone;
1556
1557     return Ok;
1558 }
1559
1560 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
1561     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
1562
1563 typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, GpImage** image);
1564
1565 typedef struct image_codec {
1566     ImageCodecInfo info;
1567     encode_image_func encode_func;
1568     decode_image_func decode_func;
1569 } image_codec;
1570
1571 typedef enum {
1572     BMP,
1573     JPEG,
1574     GIF,
1575     EMF,
1576     WMF,
1577     PNG,
1578     ICO,
1579     NUM_CODECS
1580 } ImageFormat;
1581
1582 static const struct image_codec codecs[NUM_CODECS];
1583
1584 static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
1585 {
1586     BYTE signature[8];
1587     LARGE_INTEGER seek;
1588     HRESULT hr;
1589     UINT bytesread;
1590     int i, j;
1591
1592     /* seek to the start of the stream */
1593     seek.QuadPart = 0;
1594     hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
1595     if (FAILED(hr)) return hresult_to_status(hr);
1596
1597     /* read the first 8 bytes */
1598     /* FIXME: This assumes all codecs have one signature <= 8 bytes in length */
1599     hr = IStream_Read(stream, signature, 8, &bytesread);
1600     if (FAILED(hr)) return hresult_to_status(hr);
1601     if (hr == S_FALSE || bytesread == 0) return GenericError;
1602
1603     for (i = 0; i < NUM_CODECS; i++) {
1604         if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
1605             bytesread >= codecs[i].info.SigSize)
1606         {
1607             for (j=0; j<codecs[i].info.SigSize; j++)
1608                 if ((signature[j] & codecs[i].info.SigMask[j]) != codecs[i].info.SigPattern[j])
1609                     break;
1610             if (j == codecs[i].info.SigSize)
1611             {
1612                 *result = &codecs[i];
1613                 return Ok;
1614             }
1615         }
1616     }
1617
1618     TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
1619         signature[0],signature[1],signature[2],signature[3],
1620         signature[4],signature[5],signature[6],signature[7]);
1621
1622     return GenericError;
1623 }
1624
1625 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
1626 {
1627     GpStatus stat;
1628     LARGE_INTEGER seek;
1629     HRESULT hr;
1630     const struct image_codec *codec=NULL;
1631
1632     /* choose an appropriate image decoder */
1633     stat = get_decoder_info(stream, &codec);
1634     if (stat != Ok) return stat;
1635
1636     /* seek to the start of the stream */
1637     seek.QuadPart = 0;
1638     hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
1639     if (FAILED(hr)) return hresult_to_status(hr);
1640
1641     /* call on the image decoder to do the real work */
1642     stat = codec->decode_func(stream, &codec->info.Clsid, image);
1643
1644     /* take note of the original data format */
1645     if (stat == Ok)
1646     {
1647         memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
1648     }
1649
1650     return stat;
1651 }
1652
1653 /* FIXME: no ICM */
1654 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
1655 {
1656     TRACE("%p %p\n", stream, image);
1657
1658     return GdipLoadImageFromStream(stream, image);
1659 }
1660
1661 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
1662 {
1663     static int calls;
1664
1665     if(!image)
1666         return InvalidParameter;
1667
1668     if(!(calls++))
1669         FIXME("not implemented\n");
1670
1671     return NotImplemented;
1672 }
1673
1674 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
1675 {
1676     static int calls;
1677
1678     if(!(calls++))
1679         FIXME("not implemented\n");
1680
1681     return NotImplemented;
1682 }
1683
1684 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
1685                                         GDIPCONST CLSID *clsidEncoder,
1686                                         GDIPCONST EncoderParameters *encoderParams)
1687 {
1688     GpStatus stat;
1689     IStream *stream;
1690
1691     TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
1692
1693     if (!image || !filename|| !clsidEncoder)
1694         return InvalidParameter;
1695
1696     stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
1697     if (stat != Ok)
1698         return GenericError;
1699
1700     stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
1701
1702     IStream_Release(stream);
1703     return stat;
1704 }
1705
1706 /*************************************************************************
1707  * Encoding functions -
1708  *   These functions encode an image in different image file formats.
1709  */
1710 #define BITMAP_FORMAT_BMP   0x4d42 /* "BM" */
1711 #define BITMAP_FORMAT_JPEG  0xd8ff
1712 #define BITMAP_FORMAT_GIF   0x4947
1713 #define BITMAP_FORMAT_PNG   0x5089
1714 #define BITMAP_FORMAT_APM   0xcdd7
1715
1716 static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
1717     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
1718 {
1719     GpStatus stat;
1720     GpBitmap *bitmap;
1721     IWICBitmapEncoder *encoder;
1722     IWICBitmapFrameEncode *frameencode;
1723     IPropertyBag2 *encoderoptions;
1724     HRESULT hr;
1725     UINT width, height;
1726     PixelFormat gdipformat=0;
1727     WICPixelFormatGUID wicformat;
1728     GpRect rc;
1729     BitmapData lockeddata;
1730     HRESULT initresult;
1731     UINT i;
1732
1733     if (image->type != ImageTypeBitmap)
1734         return GenericError;
1735
1736     bitmap = (GpBitmap*)image;
1737
1738     GdipGetImageWidth(image, &width);
1739     GdipGetImageHeight(image, &height);
1740
1741     rc.X = 0;
1742     rc.Y = 0;
1743     rc.Width = width;
1744     rc.Height = height;
1745
1746     initresult = CoInitialize(NULL);
1747
1748     hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
1749         &IID_IWICBitmapEncoder, (void**)&encoder);
1750     if (FAILED(hr))
1751     {
1752         if (SUCCEEDED(initresult)) CoUninitialize();
1753         return hresult_to_status(hr);
1754     }
1755
1756     hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
1757
1758     if (SUCCEEDED(hr))
1759     {
1760         hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
1761     }
1762
1763     if (SUCCEEDED(hr)) /* created frame */
1764     {
1765         hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
1766
1767         if (SUCCEEDED(hr))
1768             hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
1769
1770         if (SUCCEEDED(hr))
1771             /* FIXME: use the resolution from the image */
1772             hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0);
1773
1774         if (SUCCEEDED(hr))
1775         {
1776             for (i=0; wic_pixel_formats[i]; i++)
1777             {
1778                 if (wic_gdip_formats[i] == bitmap->format)
1779                     break;
1780             }
1781             if (wic_pixel_formats[i])
1782                 memcpy(&wicformat, wic_pixel_formats[i], sizeof(GUID));
1783             else
1784                 memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
1785
1786             hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
1787
1788             for (i=0; wic_pixel_formats[i]; i++)
1789             {
1790                 if (IsEqualGUID(&wicformat, wic_pixel_formats[i]))
1791                     break;
1792             }
1793             if (wic_pixel_formats[i])
1794                 gdipformat = wic_gdip_formats[i];
1795             else
1796             {
1797                 ERR("cannot provide pixel format %s\n", debugstr_guid(&wicformat));
1798                 hr = E_FAIL;
1799             }
1800         }
1801
1802         if (SUCCEEDED(hr))
1803         {
1804             stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
1805                 &lockeddata);
1806
1807             if (stat == Ok)
1808             {
1809                 UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
1810                 BYTE *row;
1811
1812                 /* write one row at a time in case stride is negative */
1813                 row = lockeddata.Scan0;
1814                 for (i=0; i<lockeddata.Height; i++)
1815                 {
1816                     hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
1817                     if (FAILED(hr)) break;
1818                     row += lockeddata.Stride;
1819                 }
1820
1821                 GdipBitmapUnlockBits(bitmap, &lockeddata);
1822             }
1823             else
1824                 hr = E_FAIL;
1825         }
1826
1827         if (SUCCEEDED(hr))
1828             hr = IWICBitmapFrameEncode_Commit(frameencode);
1829
1830         IWICBitmapFrameEncode_Release(frameencode);
1831         IPropertyBag2_Release(encoderoptions);
1832     }
1833
1834     if (SUCCEEDED(hr))
1835         hr = IWICBitmapEncoder_Commit(encoder);
1836
1837     IWICBitmapEncoder_Release(encoder);
1838
1839     if (SUCCEEDED(initresult)) CoUninitialize();
1840
1841     return hresult_to_status(hr);
1842 }
1843
1844 static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
1845     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
1846 {
1847     return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
1848 }
1849
1850 /*****************************************************************************
1851  * GdipSaveImageToStream [GDIPLUS.@]
1852  */
1853 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
1854     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
1855 {
1856     GpStatus stat;
1857     encode_image_func encode_image;
1858     int i;
1859
1860     TRACE("%p %p %p %p\n", image, stream, clsid, params);
1861
1862     if(!image || !stream)
1863         return InvalidParameter;
1864
1865     /* select correct encoder */
1866     encode_image = NULL;
1867     for (i = 0; i < NUM_CODECS; i++) {
1868         if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
1869             IsEqualCLSID(clsid, &codecs[i].info.Clsid))
1870             encode_image = codecs[i].encode_func;
1871     }
1872     if (encode_image == NULL)
1873         return UnknownImageFormat;
1874
1875     stat = encode_image(image, stream, clsid, params);
1876
1877     return stat;
1878 }
1879
1880 /*****************************************************************************
1881  * GdipGetImagePalette [GDIPLUS.@]
1882  */
1883 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
1884 {
1885     static int calls = 0;
1886
1887     if(!image)
1888         return InvalidParameter;
1889
1890     if(!(calls++))
1891         FIXME("not implemented\n");
1892
1893     return NotImplemented;
1894 }
1895
1896 /*****************************************************************************
1897  * GdipSetImagePalette [GDIPLUS.@]
1898  */
1899 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
1900     GDIPCONST ColorPalette *palette)
1901 {
1902     static int calls;
1903
1904     if(!image || !palette)
1905         return InvalidParameter;
1906
1907     if(!(calls++))
1908         FIXME("not implemented\n");
1909
1910     return NotImplemented;
1911 }
1912
1913 /*************************************************************************
1914  * Encoders -
1915  *   Structures that represent which formats we support for encoding.
1916  */
1917
1918 /* ImageCodecInfo creation routines taken from libgdiplus */
1919 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */
1920 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
1921 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
1922 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
1923 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
1924 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
1925
1926 static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
1927 static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
1928 static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
1929 static const WCHAR jpeg_format[] = {'J','P','E','G',0};
1930 static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
1931 static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
1932
1933 static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
1934 static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
1935 static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
1936 static const WCHAR gif_format[] = {'G','I','F',0};
1937 static const BYTE gif_sig_pattern[4] = "GIF8";
1938 static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
1939
1940 static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
1941 static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
1942 static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
1943 static const WCHAR emf_format[] = {'E','M','F',0};
1944 static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
1945 static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
1946
1947 static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
1948 static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
1949 static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
1950 static const WCHAR wmf_format[] = {'W','M','F',0};
1951 static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
1952 static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
1953
1954 static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
1955 static const WCHAR png_extension[] = {'*','.','P','N','G',0};
1956 static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
1957 static const WCHAR png_format[] = {'P','N','G',0};
1958 static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
1959 static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
1960
1961 static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
1962 static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
1963 static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
1964 static const WCHAR ico_format[] = {'I','C','O',0};
1965 static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
1966 static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
1967
1968 static const struct image_codec codecs[NUM_CODECS] = {
1969     {
1970         { /* BMP */
1971             /* Clsid */              { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
1972             /* FormatID */           { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
1973             /* CodecName */          bmp_codecname,
1974             /* DllName */            NULL,
1975             /* FormatDescription */  bmp_format,
1976             /* FilenameExtension */  bmp_extension,
1977             /* MimeType */           bmp_mimetype,
1978             /* Flags */              ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
1979             /* Version */            1,
1980             /* SigCount */           1,
1981             /* SigSize */            2,
1982             /* SigPattern */         bmp_sig_pattern,
1983             /* SigMask */            bmp_sig_mask,
1984         },
1985         encode_image_BMP,
1986         decode_image_bmp
1987     },
1988     {
1989         { /* JPEG */
1990             /* Clsid */              { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
1991             /* FormatID */           { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
1992             /* CodecName */          jpeg_codecname,
1993             /* DllName */            NULL,
1994             /* FormatDescription */  jpeg_format,
1995             /* FilenameExtension */  jpeg_extension,
1996             /* MimeType */           jpeg_mimetype,
1997             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
1998             /* Version */            1,
1999             /* SigCount */           1,
2000             /* SigSize */            2,
2001             /* SigPattern */         jpeg_sig_pattern,
2002             /* SigMask */            jpeg_sig_mask,
2003         },
2004         NULL,
2005         decode_image_jpeg
2006     },
2007     {
2008         { /* GIF */
2009             /* Clsid */              { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2010             /* FormatID */           { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2011             /* CodecName */          gif_codecname,
2012             /* DllName */            NULL,
2013             /* FormatDescription */  gif_format,
2014             /* FilenameExtension */  gif_extension,
2015             /* MimeType */           gif_mimetype,
2016             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
2017             /* Version */            1,
2018             /* SigCount */           1,
2019             /* SigSize */            4,
2020             /* SigPattern */         gif_sig_pattern,
2021             /* SigMask */            gif_sig_mask,
2022         },
2023         NULL,
2024         decode_image_gif
2025     },
2026     {
2027         { /* EMF */
2028             /* Clsid */              { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2029             /* FormatID */           { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2030             /* CodecName */          emf_codecname,
2031             /* DllName */            NULL,
2032             /* FormatDescription */  emf_format,
2033             /* FilenameExtension */  emf_extension,
2034             /* MimeType */           emf_mimetype,
2035             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
2036             /* Version */            1,
2037             /* SigCount */           1,
2038             /* SigSize */            4,
2039             /* SigPattern */         emf_sig_pattern,
2040             /* SigMask */            emf_sig_mask,
2041         },
2042         NULL,
2043         decode_image_olepicture_metafile
2044     },
2045     {
2046         { /* WMF */
2047             /* Clsid */              { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2048             /* FormatID */           { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2049             /* CodecName */          wmf_codecname,
2050             /* DllName */            NULL,
2051             /* FormatDescription */  wmf_format,
2052             /* FilenameExtension */  wmf_extension,
2053             /* MimeType */           wmf_mimetype,
2054             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
2055             /* Version */            1,
2056             /* SigCount */           1,
2057             /* SigSize */            2,
2058             /* SigPattern */         wmf_sig_pattern,
2059             /* SigMask */            wmf_sig_mask,
2060         },
2061         NULL,
2062         decode_image_olepicture_metafile
2063     },
2064     {
2065         { /* PNG */
2066             /* Clsid */              { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2067             /* FormatID */           { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2068             /* CodecName */          png_codecname,
2069             /* DllName */            NULL,
2070             /* FormatDescription */  png_format,
2071             /* FilenameExtension */  png_extension,
2072             /* MimeType */           png_mimetype,
2073             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
2074             /* Version */            1,
2075             /* SigCount */           1,
2076             /* SigSize */            8,
2077             /* SigPattern */         png_sig_pattern,
2078             /* SigMask */            png_sig_mask,
2079         },
2080         NULL,
2081         decode_image_png
2082     },
2083     {
2084         { /* ICO */
2085             /* Clsid */              { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2086             /* FormatID */           { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2087             /* CodecName */          ico_codecname,
2088             /* DllName */            NULL,
2089             /* FormatDescription */  ico_format,
2090             /* FilenameExtension */  ico_extension,
2091             /* MimeType */           ico_mimetype,
2092             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
2093             /* Version */            1,
2094             /* SigCount */           1,
2095             /* SigSize */            4,
2096             /* SigPattern */         ico_sig_pattern,
2097             /* SigMask */            ico_sig_mask,
2098         },
2099         NULL,
2100         decode_image_icon
2101     },
2102 };
2103
2104 /*****************************************************************************
2105  * GdipGetImageDecodersSize [GDIPLUS.@]
2106  */
2107 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
2108 {
2109     int decoder_count=0;
2110     int i;
2111     TRACE("%p %p\n", numDecoders, size);
2112
2113     if (!numDecoders || !size)
2114         return InvalidParameter;
2115
2116     for (i=0; i<NUM_CODECS; i++)
2117     {
2118         if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
2119             decoder_count++;
2120     }
2121
2122     *numDecoders = decoder_count;
2123     *size = decoder_count * sizeof(ImageCodecInfo);
2124
2125     return Ok;
2126 }
2127
2128 /*****************************************************************************
2129  * GdipGetImageDecoders [GDIPLUS.@]
2130  */
2131 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
2132 {
2133     int i, decoder_count=0;
2134     TRACE("%u %u %p\n", numDecoders, size, decoders);
2135
2136     if (!decoders ||
2137         size != numDecoders * sizeof(ImageCodecInfo))
2138         return GenericError;
2139
2140     for (i=0; i<NUM_CODECS; i++)
2141     {
2142         if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
2143         {
2144             if (decoder_count == numDecoders) return GenericError;
2145             memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
2146             decoder_count++;
2147         }
2148     }
2149
2150     if (decoder_count < numDecoders) return GenericError;
2151
2152     return Ok;
2153 }
2154
2155 /*****************************************************************************
2156  * GdipGetImageEncodersSize [GDIPLUS.@]
2157  */
2158 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
2159 {
2160     int encoder_count=0;
2161     int i;
2162     TRACE("%p %p\n", numEncoders, size);
2163
2164     if (!numEncoders || !size)
2165         return InvalidParameter;
2166
2167     for (i=0; i<NUM_CODECS; i++)
2168     {
2169         if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
2170             encoder_count++;
2171     }
2172
2173     *numEncoders = encoder_count;
2174     *size = encoder_count * sizeof(ImageCodecInfo);
2175
2176     return Ok;
2177 }
2178
2179 /*****************************************************************************
2180  * GdipGetImageEncoders [GDIPLUS.@]
2181  */
2182 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
2183 {
2184     int i, encoder_count=0;
2185     TRACE("%u %u %p\n", numEncoders, size, encoders);
2186
2187     if (!encoders ||
2188         size != numEncoders * sizeof(ImageCodecInfo))
2189         return GenericError;
2190
2191     for (i=0; i<NUM_CODECS; i++)
2192     {
2193         if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
2194         {
2195             if (encoder_count == numEncoders) return GenericError;
2196             memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
2197             encoder_count++;
2198         }
2199     }
2200
2201     if (encoder_count < numEncoders) return GenericError;
2202
2203     return Ok;
2204 }
2205
2206 /*****************************************************************************
2207  * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
2208  */
2209 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
2210 {
2211     BITMAP bm;
2212     GpStatus retval;
2213     PixelFormat format;
2214     BYTE* bits;
2215
2216     TRACE("%p %p %p\n", hbm, hpal, bitmap);
2217
2218     if(!hbm || !bitmap)
2219         return InvalidParameter;
2220
2221     /* TODO: Support for device-dependent bitmaps */
2222     if(hpal){
2223         FIXME("no support for device-dependent bitmaps\n");
2224         return NotImplemented;
2225     }
2226
2227     if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm))
2228             return InvalidParameter;
2229
2230     /* TODO: Figure out the correct format for 16, 32, 64 bpp */
2231     switch(bm.bmBitsPixel) {
2232         case 1:
2233             format = PixelFormat1bppIndexed;
2234             break;
2235         case 4:
2236             format = PixelFormat4bppIndexed;
2237             break;
2238         case 8:
2239             format = PixelFormat8bppIndexed;
2240             break;
2241         case 24:
2242             format = PixelFormat24bppRGB;
2243             break;
2244         case 32:
2245             format = PixelFormat32bppRGB;
2246             break;
2247         case 48:
2248             format = PixelFormat48bppRGB;
2249             break;
2250         default:
2251             FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel);
2252             return InvalidParameter;
2253     }
2254
2255     if (bm.bmBits)
2256         bits = (BYTE*)bm.bmBits + (bm.bmHeight - 1) * bm.bmWidthBytes;
2257     else
2258     {
2259         FIXME("can only get image data from DIB sections\n");
2260         bits = NULL;
2261     }
2262
2263     retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, -bm.bmWidthBytes,
2264         format, bits, bitmap);
2265
2266     return retval;
2267 }
2268
2269 GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect)
2270 {
2271     FIXME("(%p): stub\n", effect);
2272     /* note: According to Jose Roca's GDI+ Docs, this is not implemented
2273      * in Windows's gdiplus */
2274     return NotImplemented;
2275 }
2276
2277 /*****************************************************************************
2278  * GdipSetEffectParameters [GDIPLUS.@]
2279  */
2280 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
2281     const VOID *params, const UINT size)
2282 {
2283     static int calls;
2284
2285     if(!(calls++))
2286         FIXME("not implemented\n");
2287
2288     return NotImplemented;
2289 }
2290
2291 /*****************************************************************************
2292  * GdipGetImageFlags [GDIPLUS.@]
2293  */
2294 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
2295 {
2296     TRACE("%p %p\n", image, flags);
2297
2298     if(!image || !flags)
2299         return InvalidParameter;
2300
2301     *flags = image->flags;
2302
2303     return Ok;
2304 }
2305
2306 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
2307 {
2308     TRACE("(%d, %p)\n", control, param);
2309
2310     switch(control){
2311         case TestControlForceBilinear:
2312             if(param)
2313                 FIXME("TestControlForceBilinear not handled\n");
2314             break;
2315         case TestControlNoICM:
2316             if(param)
2317                 FIXME("TestControlNoICM not handled\n");
2318             break;
2319         case TestControlGetBuildNumber:
2320             *((DWORD*)param) = 3102;
2321             break;
2322     }
2323
2324     return Ok;
2325 }
2326
2327 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
2328                             HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
2329                             MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
2330                             GpMetafile **metafile)
2331 {
2332     FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2333                                  frameUnit, debugstr_w(desc), metafile);
2334
2335     return NotImplemented;
2336 }
2337
2338 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
2339                             GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
2340                             GDIPCONST WCHAR *desc, GpMetafile **metafile)
2341 {
2342     FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2343                                  frameUnit, debugstr_w(desc), metafile);
2344
2345     return NotImplemented;
2346 }
2347
2348 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
2349 {
2350     FIXME("%p\n", image);
2351
2352     return Ok;
2353 }
2354
2355 /*****************************************************************************
2356  * GdipGetImageThumbnail [GDIPLUS.@]
2357  */
2358 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
2359                             GpImage **ret_image, GetThumbnailImageAbort cb,
2360                             VOID * cb_data)
2361 {
2362     FIXME("(%p %u %u %p %p %p) stub\n",
2363         image, width, height, ret_image, cb, cb_data);
2364     return NotImplemented;
2365 }
2366
2367 /*****************************************************************************
2368  * GdipImageRotateFlip [GDIPLUS.@]
2369  */
2370 GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
2371 {
2372     FIXME("(%p %u) stub\n", image, type);
2373     return NotImplemented;
2374 }