winhttp, wininet: Load i2d_X509 from libcrypto.so.
[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 "gdiplus.h"
35 #include "gdiplus_private.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
39
40 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
41
42 static INT ipicture_pixel_height(IPicture *pic)
43 {
44     HDC hdcref;
45     OLE_YSIZE_HIMETRIC y;
46
47     IPicture_get_Height(pic, &y);
48
49     hdcref = GetDC(0);
50
51     y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
52     ReleaseDC(0, hdcref);
53
54     return y;
55 }
56
57 static INT ipicture_pixel_width(IPicture *pic)
58 {
59     HDC hdcref;
60     OLE_XSIZE_HIMETRIC x;
61
62     IPicture_get_Width(pic, &x);
63
64     hdcref = GetDC(0);
65
66     x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
67
68     ReleaseDC(0, hdcref);
69
70     return x;
71 }
72
73 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
74     ARGB *color)
75 {
76     static int calls;
77     TRACE("%p %d %d %p\n", bitmap, x, y, color);
78
79     if(!bitmap || !color)
80         return InvalidParameter;
81
82     if(!(calls++))
83         FIXME("not implemented\n");
84
85     *color = 0xdeadbeef;
86
87     return NotImplemented;
88 }
89
90 /* This function returns a pointer to an array of pixels that represents the
91  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
92  * flags.  It is correct behavior that a user who calls this function with write
93  * privileges can write to the whole bitmap (not just the area in rect).
94  *
95  * FIXME: only used portion of format is bits per pixel. */
96 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
97     UINT flags, PixelFormat format, BitmapData* lockeddata)
98 {
99     BOOL bm_is_selected;
100     INT stride, bitspp = PIXELFORMATBPP(format);
101     HDC hdc;
102     HBITMAP hbm, old = NULL;
103     BITMAPINFO *pbmi;
104     BYTE *buff = NULL;
105     UINT abs_height;
106     GpRect act_rect; /* actual rect to be used */
107
108     TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
109
110     if(!lockeddata || !bitmap)
111         return InvalidParameter;
112
113     if(rect){
114         if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
115           (rect->Y + rect->Height > bitmap->height) || !flags)
116             return InvalidParameter;
117
118         act_rect = *rect;
119     }
120     else{
121         act_rect.X = act_rect.Y = 0;
122         act_rect.Width  = bitmap->width;
123         act_rect.Height = bitmap->height;
124     }
125
126     if(flags & ImageLockModeUserInputBuf)
127         return NotImplemented;
128
129     if(bitmap->lockmode)
130         return WrongState;
131
132     IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
133     IPicture_get_CurDC(bitmap->image.picture, &hdc);
134     bm_is_selected = (hdc != 0);
135
136     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
137     if (!pbmi)
138         return OutOfMemory;
139     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
140     pbmi->bmiHeader.biBitCount = 0;
141
142     if(!bm_is_selected){
143         hdc = CreateCompatibleDC(0);
144         old = SelectObject(hdc, hbm);
145     }
146
147     /* fill out bmi */
148     GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
149
150     abs_height = abs(pbmi->bmiHeader.biHeight);
151     stride = pbmi->bmiHeader.biWidth * bitspp / 8;
152     stride = (stride + 3) & ~3;
153
154     buff = GdipAlloc(stride * abs_height);
155
156     pbmi->bmiHeader.biBitCount = bitspp;
157
158     if(buff)
159         GetDIBits(hdc, hbm, 0, abs_height, buff, pbmi, DIB_RGB_COLORS);
160
161     if(!bm_is_selected){
162         SelectObject(hdc, old);
163         DeleteDC(hdc);
164     }
165
166     if(!buff){
167         GdipFree(pbmi);
168         return OutOfMemory;
169     }
170
171     lockeddata->Width  = act_rect.Width;
172     lockeddata->Height = act_rect.Height;
173     lockeddata->PixelFormat = format;
174     lockeddata->Reserved = flags;
175
176     if(pbmi->bmiHeader.biHeight > 0){
177         lockeddata->Stride = -stride;
178         lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X +
179                              stride * (abs_height - 1 - act_rect.Y);
180     }
181     else{
182         lockeddata->Stride = stride;
183         lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
184     }
185
186     bitmap->lockmode = flags;
187     bitmap->numlocks++;
188
189     bitmap->bitmapbits = buff;
190
191     GdipFree(pbmi);
192     return Ok;
193 }
194
195 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
196     BitmapData* lockeddata)
197 {
198     HDC hdc;
199     HBITMAP hbm, old = NULL;
200     BOOL bm_is_selected;
201     BITMAPINFO *pbmi;
202
203     if(!bitmap || !lockeddata)
204         return InvalidParameter;
205
206     if(!bitmap->lockmode)
207         return WrongState;
208
209     if(lockeddata->Reserved & ImageLockModeUserInputBuf)
210         return NotImplemented;
211
212     if(lockeddata->Reserved & ImageLockModeRead){
213         if(!(--bitmap->numlocks))
214             bitmap->lockmode = 0;
215
216         GdipFree(bitmap->bitmapbits);
217         bitmap->bitmapbits = NULL;
218         return Ok;
219     }
220
221     IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
222     IPicture_get_CurDC(bitmap->image.picture, &hdc);
223     bm_is_selected = (hdc != 0);
224
225     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
226     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
227     pbmi->bmiHeader.biBitCount = 0;
228
229     if(!bm_is_selected){
230         hdc = CreateCompatibleDC(0);
231         old = SelectObject(hdc, hbm);
232     }
233
234     GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
235     pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
236     SetDIBits(hdc, hbm, 0, abs(pbmi->bmiHeader.biHeight),
237               bitmap->bitmapbits, pbmi, DIB_RGB_COLORS);
238
239     if(!bm_is_selected){
240         SelectObject(hdc, old);
241         DeleteDC(hdc);
242     }
243
244     GdipFree(pbmi);
245     GdipFree(bitmap->bitmapbits);
246     bitmap->bitmapbits = NULL;
247     bitmap->lockmode = 0;
248
249     return Ok;
250 }
251
252 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
253 {
254     IStream* stream;
255     HRESULT hr;
256     INT size;
257     LARGE_INTEGER move;
258     GpStatus stat = GenericError;
259
260     TRACE("%p, %p\n", image, cloneImage);
261
262     if (!image || !cloneImage)
263         return InvalidParameter;
264
265     hr = CreateStreamOnHGlobal(0, TRUE, &stream);
266     if (FAILED(hr))
267         return GenericError;
268
269     hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
270     if(FAILED(hr))
271     {
272         WARN("Failed to save image on stream\n");
273         goto out;
274     }
275
276     /* Set seek pointer back to the beginning of the picture */
277     move.QuadPart = 0;
278     hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
279     if (FAILED(hr))
280         goto out;
281
282     stat = GdipLoadImageFromStream(stream, cloneImage);
283     if (stat != Ok) WARN("Failed to load image from stream\n");
284
285 out:
286     IStream_Release(stream);
287     return stat;
288 }
289
290 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
291     GpBitmap **bitmap)
292 {
293     GpStatus stat;
294     IStream *stream;
295
296     TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
297
298     if(!filename || !bitmap)
299         return InvalidParameter;
300
301     stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
302
303     if(stat != Ok)
304         return stat;
305
306     stat = GdipCreateBitmapFromStream(stream, bitmap);
307
308     IStream_Release(stream);
309
310     return stat;
311 }
312
313 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info,
314                                                VOID *bits, GpBitmap **bitmap)
315 {
316     DWORD height, stride;
317     PixelFormat format;
318
319     FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
320
321     height = abs(info->bmiHeader.biHeight);
322     stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
323
324     if(info->bmiHeader.biHeight > 0) /* bottom-up */
325     {
326         bits = (BYTE*)bits + (height - 1) * stride;
327         stride = -stride;
328     }
329
330     switch(info->bmiHeader.biBitCount) {
331     case 1:
332         format = PixelFormat1bppIndexed;
333         break;
334     case 4:
335         format = PixelFormat4bppIndexed;
336         break;
337     case 8:
338         format = PixelFormat8bppIndexed;
339         break;
340     case 24:
341         format = PixelFormat24bppRGB;
342         break;
343     default:
344         FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
345         *bitmap = NULL;
346         return InvalidParameter;
347     }
348
349     return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
350                                      bits, bitmap);
351
352 }
353
354 /* FIXME: no icm */
355 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename,
356     GpBitmap **bitmap)
357 {
358     TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
359
360     return GdipCreateBitmapFromFile(filename, bitmap);
361 }
362
363 GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
364     GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
365 {
366     HBITMAP hbm;
367     GpStatus stat = InvalidParameter;
368
369     TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
370
371     if(!lpBitmapName || !bitmap)
372         return InvalidParameter;
373
374     /* load DIB */
375     hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
376                      LR_CREATEDIBSECTION);
377
378     if(hbm){
379         stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
380         DeleteObject(hbm);
381     }
382
383     return stat;
384 }
385
386 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
387     HBITMAP* hbmReturn, ARGB background)
388 {
389     FIXME("stub\n");
390
391     hbmReturn = NULL;
392
393     return NotImplemented;
394 }
395
396 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
397     GpMetafile* metafile, BOOL* succ, EmfType emfType,
398     const WCHAR* description, GpMetafile** out_metafile)
399 {
400     static int calls;
401
402     if(!ref || !metafile || !out_metafile)
403         return InvalidParameter;
404
405     *succ = FALSE;
406     *out_metafile = NULL;
407
408     if(!(calls++))
409         FIXME("not implemented\n");
410
411     return NotImplemented;
412 }
413
414 /* FIXME: this should create a bitmap in the given size with the attributes
415  * (resolution etc.) of the graphics object */
416 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
417     GpGraphics* target, GpBitmap** bitmap)
418 {
419     static int calls;
420     GpStatus ret;
421
422     if(!target || !bitmap)
423         return InvalidParameter;
424
425     if(!(calls++))
426         FIXME("hacked stub\n");
427
428     ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat24bppRGB,
429                                     NULL, bitmap);
430
431     return ret;
432 }
433
434 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
435 {
436     HICON icon_copy;
437     ICONINFO iinfo;
438     PICTDESC desc;
439
440     TRACE("%p, %p\n", hicon, bitmap);
441
442     if(!bitmap || !GetIconInfo(hicon, &iinfo))
443         return InvalidParameter;
444
445     *bitmap = GdipAlloc(sizeof(GpBitmap));
446     if(!*bitmap)    return OutOfMemory;
447
448     icon_copy = CreateIconIndirect(&iinfo);
449
450     if(!icon_copy){
451         GdipFree(*bitmap);
452         return InvalidParameter;
453     }
454
455     desc.cbSizeofstruct = sizeof(PICTDESC);
456     desc.picType = PICTYPE_ICON;
457     desc.u.icon.hicon = icon_copy;
458
459     if(OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE,
460                                 (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
461         DestroyIcon(icon_copy);
462         GdipFree(*bitmap);
463         return GenericError;
464     }
465
466     (*bitmap)->format = PixelFormat32bppARGB;
467     (*bitmap)->image.type  = ImageTypeBitmap;
468     (*bitmap)->image.flags = ImageFlagsNone;
469     (*bitmap)->width  = ipicture_pixel_width((*bitmap)->image.picture);
470     (*bitmap)->height = ipicture_pixel_height((*bitmap)->image.picture);
471
472     DeleteObject(iinfo.hbmColor);
473     DeleteObject(iinfo.hbmMask);
474
475     return Ok;
476 }
477
478 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
479     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
480 {
481     BITMAPFILEHEADER *bmfh;
482     BITMAPINFOHEADER *bmih;
483     BYTE *buff;
484     INT datalen, size;
485     IStream *stream;
486
487     TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
488
489     if (!bitmap) return InvalidParameter;
490
491     if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
492         *bitmap = NULL;
493         return InvalidParameter;
494     }
495
496     if(scan0 && !stride)
497         return InvalidParameter;
498
499     *bitmap = GdipAlloc(sizeof(GpBitmap));
500     if(!*bitmap)    return OutOfMemory;
501
502     if(stride == 0){
503         stride = width * (PIXELFORMATBPP(format) / 8);
504         stride = (stride + 3) & ~3;
505     }
506
507     datalen = abs(stride * height);
508     size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + datalen;
509     buff = GdipAlloc(size);
510     if(!buff){
511         GdipFree(*bitmap);
512         return OutOfMemory;
513     }
514
515     bmfh = (BITMAPFILEHEADER*) buff;
516     bmih = (BITMAPINFOHEADER*) (bmfh + 1);
517
518     bmfh->bfType    = (((WORD)'M') << 8) + (WORD)'B';
519     bmfh->bfSize    = size;
520     bmfh->bfOffBits = size - datalen;
521
522     bmih->biSize            = sizeof(BITMAPINFOHEADER);
523     bmih->biWidth           = width;
524     /* FIXME: use the rest of the data from format */
525     bmih->biBitCount        = PIXELFORMATBPP(format);
526     bmih->biCompression     = BI_RGB;
527     bmih->biSizeImage       = datalen;
528
529     if (scan0)
530     {
531         if (stride > 0)
532         {
533             bmih->biHeight = -height;
534             memcpy(bmih + 1, scan0, datalen);
535         }
536         else
537         {
538             bmih->biHeight = height;
539             memcpy(bmih + 1, scan0 + stride * (height - 1), datalen);
540         }
541     }
542     else
543     {
544         bmih->biHeight = height;
545         memset(bmih + 1, 0, datalen);
546     }
547
548     if(CreateStreamOnHGlobal(buff, TRUE, &stream) != S_OK){
549         ERR("could not make stream\n");
550         GdipFree(*bitmap);
551         GdipFree(buff);
552         return GenericError;
553     }
554
555     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
556         (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
557         TRACE("Could not load picture\n");
558         IStream_Release(stream);
559         GdipFree(*bitmap);
560         GdipFree(buff);
561         return GenericError;
562     }
563
564     (*bitmap)->image.type = ImageTypeBitmap;
565     (*bitmap)->image.flags = ImageFlagsNone;
566     (*bitmap)->width = width;
567     (*bitmap)->height = height;
568     (*bitmap)->format = format;
569
570     return Ok;
571 }
572
573 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
574     GpBitmap **bitmap)
575 {
576     GpStatus stat;
577
578     TRACE("%p %p\n", stream, bitmap);
579
580     stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
581
582     if(stat != Ok)
583         return stat;
584
585     if((*bitmap)->image.type != ImageTypeBitmap){
586         IPicture_Release((*bitmap)->image.picture);
587         GdipFree(bitmap);
588         return GenericError; /* FIXME: what error to return? */
589     }
590
591     return Ok;
592 }
593
594 /* FIXME: no icm */
595 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
596     GpBitmap **bitmap)
597 {
598     TRACE("%p %p\n", stream, bitmap);
599
600     return GdipCreateBitmapFromStream(stream, bitmap);
601 }
602
603 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
604     GpCachedBitmap **cachedbmp)
605 {
606     GpStatus stat;
607
608     TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
609
610     if(!bitmap || !graphics || !cachedbmp)
611         return InvalidParameter;
612
613     *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
614     if(!*cachedbmp)
615         return OutOfMemory;
616
617     stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
618     if(stat != Ok){
619         GdipFree(*cachedbmp);
620         return stat;
621     }
622
623     return Ok;
624 }
625
626 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
627 {
628     TRACE("%p\n", cachedbmp);
629
630     if(!cachedbmp)
631         return InvalidParameter;
632
633     GdipDisposeImage(cachedbmp->image);
634     GdipFree(cachedbmp);
635
636     return Ok;
637 }
638
639 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
640     GpCachedBitmap *cachedbmp, INT x, INT y)
641 {
642     TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
643
644     if(!graphics || !cachedbmp)
645         return InvalidParameter;
646
647     return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
648 }
649
650 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
651 {
652     HDC hdc;
653
654     TRACE("%p\n", image);
655
656     if(!image)
657         return InvalidParameter;
658
659     IPicture_get_CurDC(image->picture, &hdc);
660     DeleteDC(hdc);
661     IPicture_Release(image->picture);
662     if (image->type == ImageTypeBitmap)
663         GdipFree(((GpBitmap*)image)->bitmapbits);
664     GdipFree(image);
665
666     return Ok;
667 }
668
669 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
670 {
671     if(!image || !item)
672         return InvalidParameter;
673
674     return NotImplemented;
675 }
676
677 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
678     GpUnit *srcUnit)
679 {
680     TRACE("%p %p %p\n", image, srcRect, srcUnit);
681
682     if(!image || !srcRect || !srcUnit)
683         return InvalidParameter;
684     if(image->type == ImageTypeMetafile){
685         *srcRect = ((GpMetafile*)image)->bounds;
686         *srcUnit = ((GpMetafile*)image)->unit;
687     }
688     else if(image->type == ImageTypeBitmap){
689         srcRect->X = srcRect->Y = 0.0;
690         srcRect->Width = (REAL) ((GpBitmap*)image)->width;
691         srcRect->Height = (REAL) ((GpBitmap*)image)->height;
692         *srcUnit = UnitPixel;
693     }
694     else{
695         srcRect->X = srcRect->Y = 0.0;
696         srcRect->Width = ipicture_pixel_width(image->picture);
697         srcRect->Height = ipicture_pixel_height(image->picture);
698         *srcUnit = UnitPixel;
699     }
700
701     TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
702           srcRect->Width, srcRect->Height, *srcUnit);
703
704     return Ok;
705 }
706
707 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
708     REAL *height)
709 {
710     TRACE("%p %p %p\n", image, width, height);
711
712     if(!image || !height || !width)
713         return InvalidParameter;
714
715     if(image->type == ImageTypeMetafile){
716         HDC hdc = GetDC(0);
717
718         *height = convert_unit(hdc, ((GpMetafile*)image)->unit) *
719                         ((GpMetafile*)image)->bounds.Height;
720
721         *width = convert_unit(hdc, ((GpMetafile*)image)->unit) *
722                         ((GpMetafile*)image)->bounds.Width;
723
724         ReleaseDC(0, hdc);
725     }
726
727     else if(image->type == ImageTypeBitmap){
728         *height = ((GpBitmap*)image)->height;
729         *width = ((GpBitmap*)image)->width;
730     }
731     else{
732         *height = ipicture_pixel_height(image->picture);
733         *width = ipicture_pixel_width(image->picture);
734     }
735
736     TRACE("returning (%f, %f)\n", *height, *width);
737     return Ok;
738 }
739
740 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
741     GpGraphics **graphics)
742 {
743     HDC hdc;
744
745     TRACE("%p %p\n", image, graphics);
746
747     if(!image || !graphics)
748         return InvalidParameter;
749
750     if(image->type != ImageTypeBitmap){
751         FIXME("not implemented for image type %d\n", image->type);
752         return NotImplemented;
753     }
754
755     IPicture_get_CurDC(image->picture, &hdc);
756
757     if(!hdc){
758         hdc = CreateCompatibleDC(0);
759         IPicture_SelectPicture(image->picture, hdc, NULL, NULL);
760     }
761
762     return GdipCreateFromHDC(hdc, graphics);
763 }
764
765 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
766 {
767     TRACE("%p %p\n", image, height);
768
769     if(!image || !height)
770         return InvalidParameter;
771
772     if(image->type == ImageTypeMetafile){
773         HDC hdc = GetDC(0);
774
775         *height = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
776                         ((GpMetafile*)image)->bounds.Height);
777
778         ReleaseDC(0, hdc);
779     }
780     else if(image->type == ImageTypeBitmap)
781         *height = ((GpBitmap*)image)->height;
782     else
783         *height = ipicture_pixel_height(image->picture);
784
785     TRACE("returning %d\n", *height);
786
787     return Ok;
788 }
789
790 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
791 {
792     static int calls;
793
794     if(!image || !res)
795         return InvalidParameter;
796
797     if(!(calls++))
798         FIXME("not implemented\n");
799
800     return NotImplemented;
801 }
802
803 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
804 {
805     FIXME("%p %p\n", image, size);
806
807     if(!image || !size)
808         return InvalidParameter;
809
810     return NotImplemented;
811 }
812
813 /* FIXME: test this function for non-bitmap types */
814 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
815 {
816     TRACE("%p %p\n", image, format);
817
818     if(!image || !format)
819         return InvalidParameter;
820
821     if(image->type != ImageTypeBitmap)
822         *format = PixelFormat24bppRGB;
823     else
824         *format = ((GpBitmap*) image)->format;
825
826     return Ok;
827 }
828
829 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
830 {
831     static int calls;
832
833     if(!image || !format)
834         return InvalidParameter;
835
836     if(!(calls++))
837         FIXME("stub\n");
838
839     /* FIXME: should be detected from embedded picture or stored separately */
840     switch (image->type)
841     {
842     case ImageTypeBitmap:   *format = ImageFormatBMP; break;
843     case ImageTypeMetafile: *format = ImageFormatEMF; break;
844     default:
845         WARN("unknown type %u\n", image->type);
846         *format = ImageFormatUndefined;
847     }
848     return Ok;
849 }
850
851 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
852 {
853     TRACE("%p %p\n", image, type);
854
855     if(!image || !type)
856         return InvalidParameter;
857
858     *type = image->type;
859
860     return Ok;
861 }
862
863 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
864 {
865     static int calls;
866
867     if(!image || !res)
868         return InvalidParameter;
869
870     if(!(calls++))
871         FIXME("not implemented\n");
872
873     return NotImplemented;
874 }
875
876 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
877 {
878     TRACE("%p %p\n", image, width);
879
880     if(!image || !width)
881         return InvalidParameter;
882
883     if(image->type == ImageTypeMetafile){
884         HDC hdc = GetDC(0);
885
886         *width = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
887                         ((GpMetafile*)image)->bounds.Width);
888
889         ReleaseDC(0, hdc);
890     }
891     else if(image->type == ImageTypeBitmap)
892         *width = ((GpBitmap*)image)->width;
893     else
894         *width = ipicture_pixel_width(image->picture);
895
896     TRACE("returning %d\n", *width);
897
898     return Ok;
899 }
900
901 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
902     MetafileHeader * header)
903 {
904     static int calls;
905
906     if(!metafile || !header)
907         return InvalidParameter;
908
909     if(!(calls++))
910         FIXME("not implemented\n");
911
912     return Ok;
913 }
914
915 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
916     UINT num, PropertyItem* items)
917 {
918     static int calls;
919
920     if(!(calls++))
921         FIXME("not implemented\n");
922
923     return InvalidParameter;
924 }
925
926 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT* num)
927 {
928     static int calls;
929
930     if(!(calls++))
931         FIXME("not implemented\n");
932
933     return InvalidParameter;
934 }
935
936 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID* list)
937 {
938     static int calls;
939
940     if(!(calls++))
941         FIXME("not implemented\n");
942
943     return InvalidParameter;
944 }
945
946 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID id, UINT size,
947     PropertyItem* buffer)
948 {
949     static int calls;
950
951     if(!(calls++))
952         FIXME("not implemented\n");
953
954     return InvalidParameter;
955 }
956
957 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
958     UINT* size)
959 {
960     static int calls;
961
962     TRACE("%p %x %p\n", image, pid, size);
963
964     if(!size || !image)
965         return InvalidParameter;
966
967     if(!(calls++))
968         FIXME("not implemented\n");
969
970     return NotImplemented;
971 }
972
973 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT* size, UINT* num)
974 {
975     static int calls;
976
977     if(!(calls++))
978         FIXME("not implemented\n");
979
980     return InvalidParameter;
981 }
982
983 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
984     GDIPCONST GUID* dimensionID, UINT* count)
985 {
986     static int calls;
987
988     if(!image || !dimensionID || !count)
989         return InvalidParameter;
990
991     if(!(calls++))
992         FIXME("not implemented\n");
993
994     return NotImplemented;
995 }
996
997 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
998     UINT* count)
999 {
1000     if(!image || !count)
1001         return InvalidParameter;
1002
1003     *count = 1;
1004
1005     FIXME("stub\n");
1006
1007     return Ok;
1008 }
1009
1010 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
1011     GUID* dimensionIDs, UINT count)
1012 {
1013     static int calls;
1014
1015     if(!image || !dimensionIDs)
1016         return InvalidParameter;
1017
1018     if(!(calls++))
1019         FIXME("not implemented\n");
1020
1021     return Ok;
1022 }
1023
1024 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image,
1025     GDIPCONST GUID* dimensionID, UINT frameidx)
1026 {
1027     static int calls;
1028
1029     if(!image || !dimensionID)
1030         return InvalidParameter;
1031
1032     if(!(calls++))
1033         FIXME("not implemented\n");
1034
1035     return Ok;
1036 }
1037
1038 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
1039                                           GpImage **image)
1040 {
1041     GpStatus stat;
1042     IStream *stream;
1043
1044     TRACE("(%s) %p\n", debugstr_w(filename), image);
1045
1046     if (!filename || !image)
1047         return InvalidParameter;
1048
1049     stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
1050
1051     if (stat != Ok)
1052         return stat;
1053
1054     stat = GdipLoadImageFromStream(stream, image);
1055
1056     IStream_Release(stream);
1057
1058     return stat;
1059 }
1060
1061 /* FIXME: no icm handling */
1062 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
1063 {
1064     TRACE("(%s) %p\n", debugstr_w(filename), image);
1065
1066     return GdipLoadImageFromFile(filename, image);
1067 }
1068
1069 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
1070 {
1071     IPicture *pic;
1072     short type;
1073
1074     TRACE("%p %p\n", stream, image);
1075
1076     if(!stream || !image)
1077         return InvalidParameter;
1078
1079     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
1080         (LPVOID*) &pic) != S_OK){
1081         TRACE("Could not load picture\n");
1082         return GenericError;
1083     }
1084
1085     IPicture_get_Type(pic, &type);
1086
1087     if(type == PICTYPE_BITMAP){
1088         BITMAPINFO *pbmi;
1089         BITMAPCOREHEADER* bmch;
1090         HBITMAP hbm;
1091         HDC hdc;
1092
1093         pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1094         if (!pbmi)
1095             return OutOfMemory;
1096         *image = GdipAlloc(sizeof(GpBitmap));
1097         if(!*image){
1098             GdipFree(pbmi);
1099             return OutOfMemory;
1100         }
1101         (*image)->type = ImageTypeBitmap;
1102
1103         (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
1104         (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
1105
1106         /* get the pixel format */
1107         IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm);
1108         IPicture_get_CurDC(pic, &hdc);
1109
1110         bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader);
1111         bmch->bcSize = sizeof(BITMAPCOREHEADER);
1112
1113         if(!hdc){
1114             HBITMAP old;
1115             hdc = CreateCompatibleDC(0);
1116             old = SelectObject(hdc, hbm);
1117             GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
1118             SelectObject(hdc, old);
1119             DeleteDC(hdc);
1120         }
1121         else
1122             GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
1123
1124         switch(bmch->bcBitCount)
1125         {
1126             case 1:
1127                 (*((GpBitmap**) image))->format = PixelFormat1bppIndexed;
1128                 break;
1129             case 4:
1130                 (*((GpBitmap**) image))->format = PixelFormat4bppIndexed;
1131                 break;
1132             case 8:
1133                 (*((GpBitmap**) image))->format = PixelFormat8bppIndexed;
1134                 break;
1135             case 16:
1136                 (*((GpBitmap**) image))->format = PixelFormat16bppRGB565;
1137                 break;
1138             case 24:
1139                 (*((GpBitmap**) image))->format = PixelFormat24bppRGB;
1140                 break;
1141             case 32:
1142                 (*((GpBitmap**) image))->format = PixelFormat32bppRGB;
1143                 break;
1144             case 48:
1145                 (*((GpBitmap**) image))->format = PixelFormat48bppRGB;
1146                 break;
1147             default:
1148                 FIXME("Bit depth %d is not fully supported yet\n", bmch->bcBitCount);
1149                 (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
1150                 break;
1151         }
1152
1153         GdipFree(pbmi);
1154     }
1155     else if(type == PICTYPE_METAFILE || type == PICTYPE_ENHMETAFILE){
1156         /* FIXME: missing initialization code */
1157         *image = GdipAlloc(sizeof(GpMetafile));
1158         if(!*image) return OutOfMemory;
1159         (*image)->type = ImageTypeMetafile;
1160     }
1161     else{
1162         *image = GdipAlloc(sizeof(GpImage));
1163         if(!*image) return OutOfMemory;
1164         (*image)->type = ImageTypeUnknown;
1165     }
1166
1167     (*image)->picture = pic;
1168     (*image)->flags   = ImageFlagsNone;
1169
1170     return Ok;
1171 }
1172
1173 /* FIXME: no ICM */
1174 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
1175 {
1176     TRACE("%p %p\n", stream, image);
1177
1178     return GdipLoadImageFromStream(stream, image);
1179 }
1180
1181 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
1182 {
1183     static int calls;
1184
1185     if(!image)
1186         return InvalidParameter;
1187
1188     if(!(calls++))
1189         FIXME("not implemented\n");
1190
1191     return NotImplemented;
1192 }
1193
1194 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
1195 {
1196     static int calls;
1197
1198     if(!(calls++))
1199         FIXME("not implemented\n");
1200
1201     return NotImplemented;
1202 }
1203
1204 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
1205                                         GDIPCONST CLSID *clsidEncoder,
1206                                         GDIPCONST EncoderParameters *encoderParams)
1207 {
1208     GpStatus stat;
1209     IStream *stream;
1210
1211     TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
1212
1213     if (!image || !filename|| !clsidEncoder)
1214         return InvalidParameter;
1215
1216     if (!(image->picture))
1217         return InvalidParameter;
1218
1219     stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
1220     if (stat != Ok)
1221         return GenericError;
1222
1223     stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
1224
1225     IStream_Release(stream);
1226     return stat;
1227 }
1228
1229 /*************************************************************************
1230  * Encoding functions -
1231  *   These functions encode an image in different image file formats.
1232  */
1233 #define BITMAP_FORMAT_BMP   0x4d42 /* "BM" */
1234 #define BITMAP_FORMAT_JPEG  0xd8ff
1235 #define BITMAP_FORMAT_GIF   0x4947
1236 #define BITMAP_FORMAT_PNG   0x5089
1237 #define BITMAP_FORMAT_APM   0xcdd7
1238
1239 static GpStatus encode_image_BMP(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info,
1240                                  void **output, unsigned int *output_size)
1241 {
1242     int num_palette_entries;
1243     BITMAPFILEHEADER *bmp_file_hdr;
1244     BITMAPINFO *bmp_info_hdr;
1245
1246     if (bitmap_info->bmiHeader.biClrUsed) {
1247         num_palette_entries = bitmap_info->bmiHeader.biClrUsed;
1248         if (num_palette_entries > 256) num_palette_entries = 256;
1249     } else {
1250         if (bitmap_info->bmiHeader.biBitCount <= 8)
1251             num_palette_entries = 1 << bitmap_info->bmiHeader.biBitCount;
1252         else
1253             num_palette_entries = 0;
1254     }
1255
1256     *output_size =
1257         sizeof(BITMAPFILEHEADER) +
1258         sizeof(BITMAPINFOHEADER) +
1259         num_palette_entries * sizeof(RGBQUAD) +
1260         bitmap_info->bmiHeader.biSizeImage;
1261
1262     *output = GdipAlloc(*output_size);
1263
1264     bmp_file_hdr = *output;
1265     bmp_file_hdr->bfType = BITMAP_FORMAT_BMP;
1266     bmp_file_hdr->bfSize = *output_size;
1267     bmp_file_hdr->bfOffBits =
1268         sizeof(BITMAPFILEHEADER) +
1269         sizeof(BITMAPINFOHEADER) +
1270         num_palette_entries * sizeof (RGBQUAD);
1271
1272     bmp_info_hdr = (BITMAPINFO*) ((unsigned char*)(*output) + sizeof(BITMAPFILEHEADER));
1273     memcpy(bmp_info_hdr, bitmap_info, sizeof(BITMAPINFOHEADER) + num_palette_entries * sizeof(RGBQUAD));
1274     memcpy((unsigned char *)(*output) +
1275            sizeof(BITMAPFILEHEADER) +
1276            sizeof(BITMAPINFOHEADER) +
1277            num_palette_entries * sizeof(RGBQUAD),
1278            bitmap_bits, bitmap_info->bmiHeader.biSizeImage);
1279
1280     return Ok;
1281 }
1282
1283 typedef GpStatus encode_image_func(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info,
1284                                    void **output, unsigned int *output_size);
1285
1286 typedef enum {
1287     BMP,
1288     NUM_ENCODERS_SUPPORTED
1289 } ImageFormat;
1290
1291 static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED];
1292 static encode_image_func *const encode_image_funcs[NUM_ENCODERS_SUPPORTED] = {
1293     encode_image_BMP,
1294 };
1295
1296 /*****************************************************************************
1297  * GdipSaveImageToStream [GDIPLUS.@]
1298  */
1299 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
1300     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
1301 {
1302     GpStatus stat;
1303     HRESULT hr;
1304     short type;
1305     HBITMAP hbmp;
1306     HBITMAP old_hbmp;
1307     HDC hdc;
1308     int bm_is_selected;
1309     BITMAPINFO bmp_info;
1310     LPVOID bmp_bits;
1311     encode_image_func* encode_image;
1312     LPVOID output;
1313     unsigned int output_size;
1314     unsigned int dummy;
1315     int i;
1316
1317     old_hbmp = 0;
1318     output = NULL;
1319     output_size = 0;
1320
1321     TRACE("%p %p %p %p\n", image, stream, clsid, params);
1322
1323     if(!image || !stream)
1324         return InvalidParameter;
1325
1326     if (!image->picture)
1327         return GenericError;
1328
1329     hr = IPicture_get_Type(image->picture, &type);
1330     if (FAILED(hr) || type != PICTYPE_BITMAP)
1331         return GenericError;
1332
1333     /* select correct encoder */
1334     encode_image = NULL;
1335     for (i = 0; i < NUM_ENCODERS_SUPPORTED; i++) {
1336         if (IsEqualCLSID(clsid, &codecs[i].Clsid))
1337             encode_image = encode_image_funcs[i];
1338     }
1339     if (encode_image == NULL)
1340         return UnknownImageFormat;
1341
1342     /* extract underlying hbitmap representation from the IPicture */
1343     hr = IPicture_get_Handle(image->picture, (OLE_HANDLE*)&hbmp);
1344     if (FAILED(hr) || !hbmp)
1345         return GenericError;
1346     hr = IPicture_get_CurDC(image->picture, &hdc);
1347     if (FAILED(hr))
1348         return GenericError;
1349     bm_is_selected = (hdc != 0);
1350     if (!bm_is_selected) {
1351         hdc = CreateCompatibleDC(0);
1352         old_hbmp = SelectObject(hdc, hbmp);
1353     }
1354
1355     /* get bits from HBITMAP */
1356     bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
1357     bmp_info.bmiHeader.biBitCount = 0;
1358     GetDIBits(hdc, hbmp, 0, 0, NULL, &bmp_info, DIB_RGB_COLORS);
1359
1360     bmp_bits = GdipAlloc(bmp_info.bmiHeader.biSizeImage);
1361
1362     if (bmp_bits)
1363         GetDIBits(hdc, hbmp, 0, abs(bmp_info.bmiHeader.biHeight), bmp_bits, &bmp_info, DIB_RGB_COLORS);
1364
1365     if (!bm_is_selected) {
1366         SelectObject(hdc, old_hbmp);
1367         DeleteDC(hdc);
1368     }
1369
1370     if (!bmp_bits)
1371         return OutOfMemory;
1372
1373     stat = encode_image(bmp_bits, &bmp_info, &output, &output_size);
1374     if (stat == Ok)
1375         IStream_Write(stream, output, output_size, &dummy);
1376
1377     GdipFree(output);
1378     GdipFree(bmp_bits);
1379
1380     return stat;
1381 }
1382
1383 /*****************************************************************************
1384  * GdipSetImagePalette [GDIPLUS.@]
1385  */
1386 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
1387     GDIPCONST ColorPalette *palette)
1388 {
1389     static int calls;
1390
1391     if(!image || !palette)
1392         return InvalidParameter;
1393
1394     if(!(calls++))
1395         FIXME("not implemented\n");
1396
1397     return NotImplemented;
1398 }
1399
1400 /*************************************************************************
1401  * Encoders -
1402  *   Structures that represent which formats we support for encoding.
1403  */
1404
1405 /* ImageCodecInfo creation routines taken from libgdiplus */
1406 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */
1407 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
1408 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
1409 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
1410 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
1411 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
1412
1413 static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED] =
1414     {
1415         { /* BMP */
1416             /* Clsid */              { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
1417             /* FormatID */           { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
1418             /* CodecName */          bmp_codecname,
1419             /* DllName */            NULL,
1420             /* FormatDescription */  bmp_format,
1421             /* FilenameExtension */  bmp_extension,
1422             /* MimeType */           bmp_mimetype,
1423             /* Flags */              ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
1424             /* Version */            1,
1425             /* SigCount */           1,
1426             /* SigSize */            2,
1427             /* SigPattern */         bmp_sig_pattern,
1428             /* SigMask */            bmp_sig_mask,
1429         },
1430     };
1431
1432 /*****************************************************************************
1433  * GdipGetImageDecodersSize [GDIPLUS.@]
1434  */
1435 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
1436 {
1437     FIXME("%p %p stub!\n", numDecoders, size);
1438
1439     if (!numDecoders || !size)
1440         return InvalidParameter;
1441
1442     *numDecoders = 0;
1443     *size = 0;
1444
1445     return Ok;
1446 }
1447
1448 /*****************************************************************************
1449  * GdipGetImageDecoders [GDIPLUS.@]
1450  */
1451 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
1452 {
1453     FIXME("%u %u %p stub!\n", numDecoders, size, decoders);
1454
1455     if (!decoders)
1456         return GenericError;
1457
1458     return NotImplemented;
1459 }
1460
1461 /*****************************************************************************
1462  * GdipGetImageEncodersSize [GDIPLUS.@]
1463  */
1464 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
1465 {
1466     TRACE("%p %p\n", numEncoders, size);
1467
1468     if (!numEncoders || !size)
1469         return InvalidParameter;
1470
1471     *numEncoders = NUM_ENCODERS_SUPPORTED;
1472     *size = sizeof (codecs);
1473
1474     return Ok;
1475 }
1476
1477 /*****************************************************************************
1478  * GdipGetImageEncoders [GDIPLUS.@]
1479  */
1480 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
1481 {
1482     TRACE("%u %u %p\n", numEncoders, size, encoders);
1483
1484     if (!encoders ||
1485         (numEncoders != NUM_ENCODERS_SUPPORTED) ||
1486         (size != sizeof (codecs)))
1487         return GenericError;
1488
1489     memcpy(encoders, codecs, sizeof (codecs));
1490
1491     return Ok;
1492 }
1493
1494 /*****************************************************************************
1495  * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
1496  */
1497 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
1498 {
1499     BITMAP bm;
1500     GpStatus retval;
1501     PixelFormat format;
1502     BYTE* bits;
1503
1504     TRACE("%p %p %p\n", hbm, hpal, bitmap);
1505
1506     if(!hbm || !bitmap)
1507         return InvalidParameter;
1508
1509     /* TODO: Support for device-dependent bitmaps */
1510     if(hpal){
1511         FIXME("no support for device-dependent bitmaps\n");
1512         return NotImplemented;
1513     }
1514
1515     if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm))
1516             return InvalidParameter;
1517
1518     /* TODO: Figure out the correct format for 16, 32, 64 bpp */
1519     switch(bm.bmBitsPixel) {
1520         case 1:
1521             format = PixelFormat1bppIndexed;
1522             break;
1523         case 4:
1524             format = PixelFormat4bppIndexed;
1525             break;
1526         case 8:
1527             format = PixelFormat8bppIndexed;
1528             break;
1529         case 24:
1530             format = PixelFormat24bppRGB;
1531             break;
1532         case 32:
1533             format = PixelFormat32bppRGB;
1534             break;
1535         case 48:
1536             format = PixelFormat48bppRGB;
1537             break;
1538         default:
1539             FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel);
1540             return InvalidParameter;
1541     }
1542
1543     if (bm.bmBits)
1544         bits = (BYTE*)bm.bmBits + (bm.bmHeight - 1) * bm.bmWidthBytes;
1545     else
1546     {
1547         FIXME("can only get image data from DIB sections\n");
1548         bits = NULL;
1549     }
1550
1551     retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, -bm.bmWidthBytes,
1552         format, bits, bitmap);
1553
1554     return retval;
1555 }
1556
1557 /*****************************************************************************
1558  * GdipSetEffectParameters [GDIPLUS.@]
1559  */
1560 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
1561     const VOID *params, const UINT size)
1562 {
1563     static int calls;
1564
1565     if(!(calls++))
1566         FIXME("not implemented\n");
1567
1568     return NotImplemented;
1569 }
1570
1571 /*****************************************************************************
1572  * GdipGetImageFlags [GDIPLUS.@]
1573  */
1574 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
1575 {
1576     TRACE("%p %p\n", image, flags);
1577
1578     if(!image || !flags)
1579         return InvalidParameter;
1580
1581     *flags = image->flags;
1582
1583     return Ok;
1584 }
1585
1586 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
1587 {
1588     TRACE("(%d, %p)\n", control, param);
1589
1590     switch(control){
1591         case TestControlForceBilinear:
1592             if(param)
1593                 FIXME("TestControlForceBilinear not handled\n");
1594             break;
1595         case TestControlNoICM:
1596             if(param)
1597                 FIXME("TestControlNoICM not handled\n");
1598             break;
1599         case TestControlGetBuildNumber:
1600             *((DWORD*)param) = 3102;
1601             break;
1602     }
1603
1604     return Ok;
1605 }
1606
1607 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
1608                             HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
1609                             MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
1610                             GpMetafile **metafile)
1611 {
1612     FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1613                                  frameUnit, debugstr_w(desc), metafile);
1614
1615     return NotImplemented;
1616 }
1617
1618 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
1619                             GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
1620                             GDIPCONST WCHAR *desc, GpMetafile **metafile)
1621 {
1622     FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1623                                  frameUnit, debugstr_w(desc), metafile);
1624
1625     return NotImplemented;
1626 }
1627
1628 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
1629 {
1630     FIXME("%p\n", image);
1631
1632     return Ok;
1633 }