gdiplus: Assign to structs instead of using memcpy.
[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 #include "windef.h"
22 #include "winbase.h"
23 #include "winuser.h"
24 #include "wingdi.h"
25
26 #define COBJMACROS
27 #include "objbase.h"
28 #include "olectl.h"
29 #include "ole2.h"
30
31 #include "gdiplus.h"
32 #include "gdiplus_private.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
36
37 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
38
39 static INT ipicture_pixel_height(IPicture *pic)
40 {
41     HDC hdcref;
42     OLE_YSIZE_HIMETRIC y;
43
44     IPicture_get_Height(pic, &y);
45
46     hdcref = GetDC(0);
47
48     y = (UINT)(((REAL)y) * ((REAL)GetDeviceCaps(hdcref, LOGPIXELSY)) /
49               ((REAL)INCH_HIMETRIC));
50     ReleaseDC(0, hdcref);
51
52     return y;
53 }
54
55 static INT ipicture_pixel_width(IPicture *pic)
56 {
57     HDC hdcref;
58     OLE_XSIZE_HIMETRIC x;
59
60     IPicture_get_Width(pic, &x);
61
62     hdcref = GetDC(0);
63
64     x = (UINT)(((REAL)x) * ((REAL)GetDeviceCaps(hdcref, LOGPIXELSX)) /
65               ((REAL)INCH_HIMETRIC));
66
67     ReleaseDC(0, hdcref);
68
69     return x;
70 }
71
72 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
73     ARGB *color)
74 {
75     static int calls;
76     TRACE("%p %d %d %p\n", bitmap, x, y, color);
77
78     if(!bitmap || !color)
79         return InvalidParameter;
80
81     if(!(calls++))
82         FIXME("not implemented\n");
83
84     *color = 0xdeadbeef;
85
86     return NotImplemented;
87 }
88
89 /* This function returns a pointer to an array of pixels that represents the
90  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
91  * flags.  It is correct behavior that a user who calls this function with write
92  * privileges can write to the whole bitmap (not just the area in rect).
93  *
94  * FIXME: only used portion of format is bits per pixel. */
95 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
96     UINT flags, PixelFormat format, BitmapData* lockeddata)
97 {
98     BOOL bm_is_selected;
99     INT stride, bitspp = PIXELFORMATBPP(format);
100     OLE_HANDLE hbm;
101     HDC hdc;
102     HBITMAP old = NULL;
103     BITMAPINFO bmi;
104     BYTE *buff = NULL;
105     UINT abs_height;
106
107     TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
108
109     if(!lockeddata || !bitmap || !rect)
110         return InvalidParameter;
111
112     if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
113        (rect->Y + rect->Height > bitmap->height) || !flags)
114         return InvalidParameter;
115
116     if(flags & ImageLockModeUserInputBuf)
117         return NotImplemented;
118
119     if((bitmap->lockmode & ImageLockModeWrite) || (bitmap->lockmode &&
120         (flags & ImageLockModeWrite)))
121         return WrongState;
122
123     IPicture_get_Handle(bitmap->image.picture, &hbm);
124     IPicture_get_CurDC(bitmap->image.picture, &hdc);
125     bm_is_selected = (hdc != 0);
126
127     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
128     bmi.bmiHeader.biBitCount = 0;
129
130     if(!bm_is_selected){
131         hdc = CreateCompatibleDC(0);
132         old = SelectObject(hdc, (HBITMAP)hbm);
133     }
134
135     /* fill out bmi */
136     GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
137
138     abs_height = abs(bmi.bmiHeader.biHeight);
139     stride = bmi.bmiHeader.biWidth * bitspp / 8;
140     stride = (stride + 3) & ~3;
141
142     buff = GdipAlloc(stride * abs_height);
143
144     bmi.bmiHeader.biBitCount = bitspp;
145
146     if(buff)
147         GetDIBits(hdc, (HBITMAP)hbm, 0, abs_height, buff, &bmi, DIB_RGB_COLORS);
148
149     if(!bm_is_selected){
150         SelectObject(hdc, old);
151         DeleteDC(hdc);
152     }
153
154     if(!buff)
155         return OutOfMemory;
156
157     lockeddata->Width = rect->Width;
158     lockeddata->Height = rect->Height;
159     lockeddata->PixelFormat = format;
160     lockeddata->Reserved = flags;
161
162     if(bmi.bmiHeader.biHeight > 0){
163         lockeddata->Stride = -stride;
164         lockeddata->Scan0 = buff + (bitspp / 8) * rect->X +
165                             stride * (abs_height - 1 - rect->Y);
166     }
167     else{
168         lockeddata->Stride = stride;
169         lockeddata->Scan0 = buff + (bitspp / 8) * rect->X + stride * rect->Y;
170     }
171
172     bitmap->lockmode = flags;
173     bitmap->numlocks++;
174
175     if(flags & ImageLockModeWrite)
176         bitmap->bitmapbits = buff;
177
178     return Ok;
179 }
180
181 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
182     BitmapData* lockeddata)
183 {
184     OLE_HANDLE hbm;
185     HDC hdc;
186     HBITMAP old = NULL;
187     BOOL bm_is_selected;
188     BITMAPINFO bmi;
189
190     if(!bitmap || !lockeddata)
191         return InvalidParameter;
192
193     if(!bitmap->lockmode)
194         return WrongState;
195
196     if(lockeddata->Reserved & ImageLockModeUserInputBuf)
197         return NotImplemented;
198
199     if(lockeddata->Reserved & ImageLockModeRead){
200         if(!(--bitmap->numlocks))
201             bitmap->lockmode = 0;
202
203         GdipFree(lockeddata->Scan0);
204         return Ok;
205     }
206
207     IPicture_get_Handle(bitmap->image.picture, &hbm);
208     IPicture_get_CurDC(bitmap->image.picture, &hdc);
209     bm_is_selected = (hdc != 0);
210
211     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
212     bmi.bmiHeader.biBitCount = 0;
213
214     if(!bm_is_selected){
215         hdc = CreateCompatibleDC(0);
216         old = SelectObject(hdc, (HBITMAP)hbm);
217     }
218
219     GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
220     bmi.bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
221     SetDIBits(hdc, (HBITMAP)hbm, 0, abs(bmi.bmiHeader.biHeight),
222               bitmap->bitmapbits, &bmi, DIB_RGB_COLORS);
223
224     if(!bm_is_selected){
225         SelectObject(hdc, old);
226         DeleteDC(hdc);
227     }
228
229     GdipFree(bitmap->bitmapbits);
230
231     return Ok;
232 }
233
234 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
235     GpBitmap **bitmap)
236 {
237     GpStatus stat;
238     IStream *stream;
239
240     if(!filename || !bitmap)
241         return InvalidParameter;
242
243     stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
244
245     if(stat != Ok)
246         return stat;
247
248     stat = GdipCreateBitmapFromStream(stream, bitmap);
249
250     if(!stat)
251         IStream_Release(stream);
252
253     return stat;
254 }
255
256 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
257     HBITMAP* hbmReturn, ARGB background)
258 {
259     FIXME("stub\n");
260
261     hbmReturn = NULL;
262
263     return NotImplemented;
264 }
265
266 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
267     GpMetafile* metafile, BOOL* succ, EmfType emfType,
268     const WCHAR* description, GpMetafile** out_metafile)
269 {
270     static int calls;
271
272     if(!ref || !metafile || !out_metafile)
273         return InvalidParameter;
274
275     *succ = FALSE;
276     *out_metafile = NULL;
277
278     if(!(calls++))
279         FIXME("not implemented\n");
280
281     return NotImplemented;
282 }
283
284 /* FIXME: this should create a bitmap in the given size with the attributes
285  * (resolution etc.) of the graphics object */
286 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
287     GpGraphics* target, GpBitmap** bitmap)
288 {
289     static int calls;
290     GpStatus ret;
291
292     if(!target || !bitmap)
293         return InvalidParameter;
294
295     if(!(calls++))
296         FIXME("hacked stub\n");
297
298     ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat24bppRGB,
299                                     NULL, bitmap);
300
301     return ret;
302 }
303
304 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
305     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
306 {
307     BITMAPFILEHEADER *bmfh;
308     BITMAPINFOHEADER *bmih;
309     BYTE *buff;
310     INT datalen, size;
311     IStream *stream;
312
313     TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
314
315     if(!bitmap || width <= 0 || height <= 0 || (scan0 && (stride % 4))){
316         *bitmap = NULL;
317         return InvalidParameter;
318     }
319
320     if(scan0 && !stride)
321         return InvalidParameter;
322
323     /* FIXME: windows allows negative stride (reads backwards from scan0) */
324     if(stride < 0){
325         FIXME("negative stride\n");
326         return InvalidParameter;
327     }
328
329     *bitmap = GdipAlloc(sizeof(GpBitmap));
330     if(!*bitmap)    return OutOfMemory;
331
332     if(stride == 0){
333         stride = width * (PIXELFORMATBPP(format) / 8);
334         stride = (stride + 3) & ~3;
335     }
336
337     datalen = abs(stride * height);
338     size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + datalen;
339     buff = GdipAlloc(size);
340     if(!buff){
341         GdipFree(*bitmap);
342         return OutOfMemory;
343     }
344
345     bmfh = (BITMAPFILEHEADER*) buff;
346     bmih = (BITMAPINFOHEADER*) (bmfh + 1);
347
348     bmfh->bfType    = (((WORD)'M') << 8) + (WORD)'B';
349     bmfh->bfSize    = size;
350     bmfh->bfOffBits = size - datalen;
351
352     bmih->biSize            = sizeof(BITMAPINFOHEADER);
353     bmih->biWidth           = width;
354     bmih->biHeight          = -height;
355     /* FIXME: use the rest of the data from format */
356     bmih->biBitCount        = PIXELFORMATBPP(format);
357     bmih->biCompression     = BI_RGB;
358     bmih->biSizeImage       = datalen;
359
360     if(scan0)
361         memcpy(bmih + 1, scan0, datalen);
362     else
363         memset(bmih + 1, 0, datalen);
364
365     if(CreateStreamOnHGlobal(buff, TRUE, &stream) != S_OK){
366         ERR("could not make stream\n");
367         GdipFree(*bitmap);
368         GdipFree(buff);
369         return GenericError;
370     }
371
372     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
373         (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
374         TRACE("Could not load picture\n");
375         IStream_Release(stream);
376         GdipFree(*bitmap);
377         GdipFree(buff);
378         return GenericError;
379     }
380
381     (*bitmap)->image.type = ImageTypeBitmap;
382     (*bitmap)->width = width;
383     (*bitmap)->height = height;
384     (*bitmap)->format = format;
385
386     return Ok;
387 }
388
389 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
390     GpBitmap **bitmap)
391 {
392     GpStatus stat;
393
394     stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
395
396     if(stat != Ok)
397         return stat;
398
399     if((*bitmap)->image.type != ImageTypeBitmap){
400         IPicture_Release((*bitmap)->image.picture);
401         GdipFree(bitmap);
402         return GenericError; /* FIXME: what error to return? */
403     }
404
405     return Ok;
406 }
407
408 /* FIXME: no icm */
409 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
410     GpBitmap **bitmap)
411 {
412     return GdipCreateBitmapFromStream(stream, bitmap);
413 }
414
415 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
416 {
417     HDC hdc;
418
419     if(!image)
420         return InvalidParameter;
421
422     IPicture_get_CurDC(image->picture, &hdc);
423     DeleteDC(hdc);
424     IPicture_Release(image->picture);
425     GdipFree(image);
426
427     return Ok;
428 }
429
430 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
431 {
432     if(!image || !item)
433         return InvalidParameter;
434
435     return NotImplemented;
436 }
437
438 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
439     GpUnit *srcUnit)
440 {
441     if(!image || !srcRect || !srcUnit)
442         return InvalidParameter;
443     if(image->type == ImageTypeMetafile){
444         *srcRect = ((GpMetafile*)image)->bounds;
445         *srcUnit = ((GpMetafile*)image)->unit;
446     }
447     else if(image->type == ImageTypeBitmap){
448         srcRect->X = srcRect->Y = 0.0;
449         srcRect->Width = (REAL) ((GpBitmap*)image)->width;
450         srcRect->Height = (REAL) ((GpBitmap*)image)->height;
451         *srcUnit = UnitPixel;
452     }
453     else{
454         srcRect->X = srcRect->Y = 0.0;
455         srcRect->Width = ipicture_pixel_width(image->picture);
456         srcRect->Height = ipicture_pixel_height(image->picture);
457         *srcUnit = UnitPixel;
458     }
459
460     TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
461           srcRect->Width, srcRect->Height, *srcUnit);
462
463     return Ok;
464 }
465
466 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
467     REAL *height)
468 {
469     if(!image || !height || !width)
470         return InvalidParameter;
471
472     if(image->type == ImageTypeMetafile){
473         HDC hdc = GetDC(0);
474
475         *height = convert_unit(hdc, ((GpMetafile*)image)->unit) *
476                         ((GpMetafile*)image)->bounds.Height;
477
478         *width = convert_unit(hdc, ((GpMetafile*)image)->unit) *
479                         ((GpMetafile*)image)->bounds.Width;
480
481         ReleaseDC(0, hdc);
482     }
483
484     else if(image->type == ImageTypeBitmap){
485         *height = ((GpBitmap*)image)->height;
486         *width = ((GpBitmap*)image)->width;
487     }
488     else{
489         *height = ipicture_pixel_height(image->picture);
490         *width = ipicture_pixel_width(image->picture);
491     }
492
493     TRACE("returning (%f, %f)\n", *height, *width);
494     return Ok;
495 }
496
497 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
498     GpGraphics **graphics)
499 {
500     HDC hdc;
501
502     if(!image || !graphics)
503         return InvalidParameter;
504
505     if(image->type != ImageTypeBitmap){
506         FIXME("not implemented for image type %d\n", image->type);
507         return NotImplemented;
508     }
509
510     IPicture_get_CurDC(image->picture, &hdc);
511
512     if(!hdc){
513         hdc = CreateCompatibleDC(0);
514         IPicture_SelectPicture(image->picture, hdc, NULL, NULL);
515     }
516
517     return GdipCreateFromHDC(hdc, graphics);
518 }
519
520 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
521 {
522     if(!image || !height)
523         return InvalidParameter;
524
525     if(image->type == ImageTypeMetafile){
526         HDC hdc = GetDC(0);
527
528         *height = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
529                         ((GpMetafile*)image)->bounds.Height);
530
531         ReleaseDC(0, hdc);
532     }
533     else if(image->type == ImageTypeBitmap)
534         *height = ((GpBitmap*)image)->height;
535     else
536         *height = ipicture_pixel_height(image->picture);
537
538     TRACE("returning %d\n", *height);
539
540     return Ok;
541 }
542
543 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
544 {
545     static int calls;
546
547     if(!image || !res)
548         return InvalidParameter;
549
550     if(!(calls++))
551         FIXME("not implemented\n");
552
553     return NotImplemented;
554 }
555
556 /* FIXME: test this function for non-bitmap types */
557 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
558 {
559     if(!image || !format)
560         return InvalidParameter;
561
562     if(image->type != ImageTypeBitmap)
563         *format = PixelFormat24bppRGB;
564     else
565         *format = ((GpBitmap*) image)->format;
566
567     return Ok;
568 }
569
570 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
571 {
572     static int calls;
573
574     if(!image || !format)
575         return InvalidParameter;
576
577     if(!(calls++))
578         FIXME("not implemented\n");
579
580     return NotImplemented;
581 }
582
583 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
584 {
585     if(!image || !type)
586         return InvalidParameter;
587
588     *type = image->type;
589
590     return Ok;
591 }
592
593 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
594 {
595     static int calls;
596
597     if(!image || !res)
598         return InvalidParameter;
599
600     if(!(calls++))
601         FIXME("not implemented\n");
602
603     return NotImplemented;
604 }
605
606 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
607 {
608     if(!image || !width)
609         return InvalidParameter;
610
611     if(image->type == ImageTypeMetafile){
612         HDC hdc = GetDC(0);
613
614         *width = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
615                         ((GpMetafile*)image)->bounds.Width);
616
617         ReleaseDC(0, hdc);
618     }
619     else if(image->type == ImageTypeBitmap)
620         *width = ((GpBitmap*)image)->width;
621     else
622         *width = ipicture_pixel_width(image->picture);
623
624     TRACE("returning %d\n", *width);
625
626     return Ok;
627 }
628
629 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
630     MetafileHeader * header)
631 {
632     static int calls;
633
634     if(!metafile || !header)
635         return InvalidParameter;
636
637     if(!(calls++))
638         FIXME("not implemented\n");
639
640     return Ok;
641 }
642
643 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
644     UINT* size)
645 {
646     static int calls;
647
648     TRACE("%p %x %p\n", image, pid, size);
649
650     if(!size || !image)
651         return InvalidParameter;
652
653     if(!(calls++))
654         FIXME("not implemented\n");
655
656     return NotImplemented;
657 }
658
659 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
660     GDIPCONST GUID* dimensionID, UINT* count)
661 {
662     static int calls;
663
664     if(!image || !dimensionID || !count)
665         return InvalidParameter;
666
667     if(!(calls++))
668         FIXME("not implemented\n");
669
670     return NotImplemented;
671 }
672
673 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
674     GUID* dimensionIDs, UINT count)
675 {
676     static int calls;
677
678     if(!image || !dimensionIDs)
679         return InvalidParameter;
680
681     if(!(calls++))
682         FIXME("not implemented\n");
683
684     return Ok;
685 }
686
687 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image,
688     GDIPCONST GUID* dimensionID, UINT frameidx)
689 {
690     static int calls;
691
692     if(!image || !dimensionID)
693         return InvalidParameter;
694
695     if(!(calls++))
696         FIXME("not implemented\n");
697
698     return Ok;
699 }
700
701 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
702 {
703     IPicture *pic;
704     short type;
705
706     if(!stream || !image)
707         return InvalidParameter;
708
709     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
710         (LPVOID*) &pic) != S_OK){
711         TRACE("Could not load picture\n");
712         return GenericError;
713     }
714
715     IStream_AddRef(stream);
716
717     IPicture_get_Type(pic, &type);
718
719     if(type == PICTYPE_BITMAP){
720         BITMAPINFO bmi;
721         BITMAPCOREHEADER* bmch;
722         OLE_HANDLE hbm;
723         HDC hdc;
724
725         *image = GdipAlloc(sizeof(GpBitmap));
726         if(!*image) return OutOfMemory;
727         (*image)->type = ImageTypeBitmap;
728
729         (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
730         (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
731
732         /* get the pixel format */
733         IPicture_get_Handle(pic, &hbm);
734         IPicture_get_CurDC(pic, &hdc);
735
736         bmch = (BITMAPCOREHEADER*) (&bmi.bmiHeader);
737         bmch->bcSize = sizeof(BITMAPCOREHEADER);
738
739         if(!hdc){
740             HBITMAP old;
741             hdc = CreateCompatibleDC(0);
742             old = SelectObject(hdc, (HBITMAP)hbm);
743             GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
744             SelectObject(hdc, old);
745             DeleteDC(hdc);
746         }
747         else
748             GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
749
750         (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
751     }
752     else if(type == PICTYPE_METAFILE || type == PICTYPE_ENHMETAFILE){
753         /* FIXME: missing initialization code */
754         *image = GdipAlloc(sizeof(GpMetafile));
755         if(!*image) return OutOfMemory;
756         (*image)->type = ImageTypeMetafile;
757     }
758     else{
759         *image = GdipAlloc(sizeof(GpImage));
760         if(!*image) return OutOfMemory;
761         (*image)->type = ImageTypeUnknown;
762     }
763
764     (*image)->picture = pic;
765
766     return Ok;
767 }
768
769 /* FIXME: no ICM */
770 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
771 {
772     return GdipLoadImageFromStream(stream, image);
773 }
774
775 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
776 {
777     static int calls;
778
779     if(!image)
780         return InvalidParameter;
781
782     if(!(calls++))
783         FIXME("not implemented\n");
784
785     return NotImplemented;
786 }
787
788 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
789     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
790 {
791     if(!image || !stream)
792         return InvalidParameter;
793
794     /* FIXME: CLSID, EncoderParameters not used */
795
796     IPicture_SaveAsFile(image->picture, stream, FALSE, NULL);
797
798     return Ok;
799 }
800
801 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
802     GDIPCONST ColorPalette *palette)
803 {
804     static int calls;
805
806     if(!image || !palette)
807         return InvalidParameter;
808
809     if(!(calls++))
810         FIXME("not implemented\n");
811
812     return NotImplemented;
813 }