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