gdiplus: Mark the Graphics object as busy before freeing it.
[wine/multimedia.git] / dlls / gdiplus / image.c
blob0ad2308ca8dfdcab5d2186f5b6d318019bee3ed6
1 /*
2 * Copyright (C) 2007 Google (Evan Stade)
3 * Copyright (C) 2012 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #include <assert.h>
23 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "wingdi.h"
30 #define COBJMACROS
31 #include "objbase.h"
32 #include "olectl.h"
33 #include "ole2.h"
35 #include "initguid.h"
36 #include "wincodec.h"
37 #include "gdiplus.h"
38 #include "gdiplus_private.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
43 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
45 static const struct
47 const WICPixelFormatGUID *wic_format;
48 PixelFormat gdip_format;
49 /* predefined palette type to use for pixel format conversions */
50 WICBitmapPaletteType palette_type;
51 } pixel_formats[] =
53 { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
54 { &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
55 { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 },
56 { &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedHalftone256 },
57 { &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555, WICBitmapPaletteTypeFixedHalftone256 },
58 { &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
59 { &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
60 { &GUID_WICPixelFormat32bppBGRA, PixelFormat32bppARGB, WICBitmapPaletteTypeFixedHalftone256 },
61 { &GUID_WICPixelFormat32bppPBGRA, PixelFormat32bppPARGB, WICBitmapPaletteTypeFixedHalftone256 },
62 { NULL }
65 static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteType palette_type)
67 HRESULT hr;
68 IWICImagingFactory *factory;
69 IWICPalette *wic_palette;
70 ColorPalette *palette = NULL;
72 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
73 &IID_IWICImagingFactory, (void **)&factory);
74 if (hr != S_OK) return NULL;
76 hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
77 if (hr == S_OK)
79 hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
80 if (frame)
81 hr = IWICBitmapFrameDecode_CopyPalette(frame, wic_palette);
82 if (hr != S_OK)
84 TRACE("using predefined palette %#x\n", palette_type);
85 hr = IWICPalette_InitializePredefined(wic_palette, palette_type, FALSE);
87 if (hr == S_OK)
89 UINT count;
90 BOOL mono, gray;
92 IWICPalette_IsBlackWhite(wic_palette, &mono);
93 IWICPalette_IsGrayscale(wic_palette, &gray);
95 IWICPalette_GetColorCount(wic_palette, &count);
96 palette = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(UINT) + count * sizeof(ARGB));
97 IWICPalette_GetColors(wic_palette, count, palette->Entries, &palette->Count);
99 if (mono)
100 palette->Flags = 0;
101 else if (gray)
102 palette->Flags = PaletteFlagsGrayScale;
103 else
104 palette->Flags = PaletteFlagsHalftone;
106 IWICPalette_Release(wic_palette);
108 IWICImagingFactory_Release(factory);
109 return palette;
112 static INT ipicture_pixel_height(IPicture *pic)
114 HDC hdcref;
115 OLE_YSIZE_HIMETRIC y;
117 IPicture_get_Height(pic, &y);
119 hdcref = CreateCompatibleDC(0);
120 y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
121 DeleteDC(hdcref);
123 return y;
126 static INT ipicture_pixel_width(IPicture *pic)
128 HDC hdcref;
129 OLE_XSIZE_HIMETRIC x;
131 IPicture_get_Width(pic, &x);
133 hdcref = CreateCompatibleDC(0);
134 x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
135 DeleteDC(hdcref);
137 return x;
140 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
141 RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
143 FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
145 * Note: According to Jose Roca's GDI+ docs, this function is not
146 * implemented in Windows's GDI+.
148 return NotImplemented;
151 GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
152 INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
153 GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
155 FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
157 * Note: According to Jose Roca's GDI+ docs, this function is not
158 * implemented in Windows's GDI+.
160 return NotImplemented;
163 static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
165 *index = (row[x/8]>>(7-x%8)) & 1;
168 static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x)
170 if (x & 1)
171 *index = row[x/2]&0xf;
172 else
173 *index = row[x/2]>>4;
176 static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
178 *index = row[x];
181 static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
182 const BYTE *row, UINT x)
184 *r = *g = *b = row[x*2+1];
185 *a = 255;
188 static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
189 const BYTE *row, UINT x)
191 WORD pixel = *((const WORD*)(row)+x);
192 *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
193 *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
194 *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
195 *a = 255;
198 static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
199 const BYTE *row, UINT x)
201 WORD pixel = *((const WORD*)(row)+x);
202 *r = (pixel>>8&0xf8)|(pixel>>13&0x7);
203 *g = (pixel>>3&0xfc)|(pixel>>9&0x3);
204 *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
205 *a = 255;
208 static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
209 const BYTE *row, UINT x)
211 WORD pixel = *((const WORD*)(row)+x);
212 *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
213 *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
214 *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
215 if ((pixel&0x8000) == 0x8000)
216 *a = 255;
217 else
218 *a = 0;
221 static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
222 const BYTE *row, UINT x)
224 *r = row[x*3+2];
225 *g = row[x*3+1];
226 *b = row[x*3];
227 *a = 255;
230 static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
231 const BYTE *row, UINT x)
233 *r = row[x*4+2];
234 *g = row[x*4+1];
235 *b = row[x*4];
236 *a = 255;
239 static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
240 const BYTE *row, UINT x)
242 *r = row[x*4+2];
243 *g = row[x*4+1];
244 *b = row[x*4];
245 *a = row[x*4+3];
248 static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
249 const BYTE *row, UINT x)
251 *a = row[x*4+3];
252 if (*a == 0)
253 *r = *g = *b = 0;
254 else
256 *r = row[x*4+2] * 255 / *a;
257 *g = row[x*4+1] * 255 / *a;
258 *b = row[x*4] * 255 / *a;
262 static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
263 const BYTE *row, UINT x)
265 *r = row[x*6+5];
266 *g = row[x*6+3];
267 *b = row[x*6+1];
268 *a = 255;
271 static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
272 const BYTE *row, UINT x)
274 *r = row[x*8+5];
275 *g = row[x*8+3];
276 *b = row[x*8+1];
277 *a = row[x*8+7];
280 static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
281 const BYTE *row, UINT x)
283 *a = row[x*8+7];
284 if (*a == 0)
285 *r = *g = *b = 0;
286 else
288 *r = row[x*8+5] * 255 / *a;
289 *g = row[x*8+3] * 255 / *a;
290 *b = row[x*8+1] * 255 / *a;
294 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
295 ARGB *color)
297 BYTE r, g, b, a;
298 BYTE index;
299 BYTE *row;
301 if(!bitmap || !color ||
302 x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
303 return InvalidParameter;
305 row = bitmap->bits+bitmap->stride*y;
307 switch (bitmap->format)
309 case PixelFormat1bppIndexed:
310 getpixel_1bppIndexed(&index,row,x);
311 break;
312 case PixelFormat4bppIndexed:
313 getpixel_4bppIndexed(&index,row,x);
314 break;
315 case PixelFormat8bppIndexed:
316 getpixel_8bppIndexed(&index,row,x);
317 break;
318 case PixelFormat16bppGrayScale:
319 getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
320 break;
321 case PixelFormat16bppRGB555:
322 getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
323 break;
324 case PixelFormat16bppRGB565:
325 getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
326 break;
327 case PixelFormat16bppARGB1555:
328 getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
329 break;
330 case PixelFormat24bppRGB:
331 getpixel_24bppRGB(&r,&g,&b,&a,row,x);
332 break;
333 case PixelFormat32bppRGB:
334 getpixel_32bppRGB(&r,&g,&b,&a,row,x);
335 break;
336 case PixelFormat32bppARGB:
337 getpixel_32bppARGB(&r,&g,&b,&a,row,x);
338 break;
339 case PixelFormat32bppPARGB:
340 getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
341 break;
342 case PixelFormat48bppRGB:
343 getpixel_48bppRGB(&r,&g,&b,&a,row,x);
344 break;
345 case PixelFormat64bppARGB:
346 getpixel_64bppARGB(&r,&g,&b,&a,row,x);
347 break;
348 case PixelFormat64bppPARGB:
349 getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
350 break;
351 default:
352 FIXME("not implemented for format 0x%x\n", bitmap->format);
353 return NotImplemented;
356 if (bitmap->format & PixelFormatIndexed)
357 *color = bitmap->image.palette->Entries[index];
358 else
359 *color = a<<24|r<<16|g<<8|b;
361 return Ok;
364 static inline UINT get_palette_index(BYTE r, BYTE g, BYTE b, BYTE a, ColorPalette *palette)
366 BYTE index = 0;
367 int best_distance = 0x7fff;
368 int distance;
369 UINT i;
371 if (!palette) return 0;
372 /* This algorithm scans entire palette,
373 computes difference from desired color (all color components have equal weight)
374 and returns the index of color with least difference.
376 Note: Maybe it could be replaced with a better algorithm for better image quality
377 and performance, though better algorithm would probably need some pre-built lookup
378 tables and thus may actually be slower if this method is called only few times per
379 every image.
381 for(i=0;i<palette->Count;i++) {
382 ARGB color=palette->Entries[i];
383 distance=abs(b-(color & 0xff)) + abs(g-(color>>8 & 0xff)) + abs(r-(color>>16 & 0xff)) + abs(a-(color>>24 & 0xff));
384 if (distance<best_distance) {
385 best_distance=distance;
386 index=i;
389 return index;
392 static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
393 BYTE *row, UINT x, ColorPalette *palette)
395 BYTE index = get_palette_index(r,g,b,a,palette);
396 row[x]=index;
399 static inline void setpixel_1bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
400 BYTE *row, UINT x, ColorPalette *palette)
402 row[x/8] = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,palette)<<(7-x%8));
405 static inline void setpixel_4bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
406 BYTE *row, UINT x, ColorPalette *palette)
408 if (x & 1)
409 row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,palette);
410 else
411 row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,palette)<<4;
414 static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
415 BYTE *row, UINT x)
417 *((WORD*)(row)+x) = (r+g+b)*85;
420 static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
421 BYTE *row, UINT x)
423 *((WORD*)(row)+x) = (r<<7&0x7c00)|
424 (g<<2&0x03e0)|
425 (b>>3&0x001f);
428 static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
429 BYTE *row, UINT x)
431 *((WORD*)(row)+x) = (r<<8&0xf800)|
432 (g<<3&0x07e0)|
433 (b>>3&0x001f);
436 static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
437 BYTE *row, UINT x)
439 *((WORD*)(row)+x) = (a<<8&0x8000)|
440 (r<<7&0x7c00)|
441 (g<<2&0x03e0)|
442 (b>>3&0x001f);
445 static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
446 BYTE *row, UINT x)
448 row[x*3+2] = r;
449 row[x*3+1] = g;
450 row[x*3] = b;
453 static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
454 BYTE *row, UINT x)
456 *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
459 static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
460 BYTE *row, UINT x)
462 *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
465 static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
466 BYTE *row, UINT x)
468 r = r * a / 255;
469 g = g * a / 255;
470 b = b * a / 255;
471 *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
474 static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
475 BYTE *row, UINT x)
477 row[x*6+5] = row[x*6+4] = r;
478 row[x*6+3] = row[x*6+2] = g;
479 row[x*6+1] = row[x*6] = b;
482 static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
483 BYTE *row, UINT x)
485 UINT64 a64=a, r64=r, g64=g, b64=b;
486 *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
489 static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
490 BYTE *row, UINT x)
492 UINT64 a64, r64, g64, b64;
493 a64 = a * 257;
494 r64 = r * a / 255;
495 g64 = g * a / 255;
496 b64 = b * a / 255;
497 *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
500 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
501 ARGB color)
503 BYTE a, r, g, b;
504 BYTE *row;
506 if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
507 return InvalidParameter;
509 a = color>>24;
510 r = color>>16;
511 g = color>>8;
512 b = color;
514 row = bitmap->bits + bitmap->stride * y;
516 switch (bitmap->format)
518 case PixelFormat16bppGrayScale:
519 setpixel_16bppGrayScale(r,g,b,a,row,x);
520 break;
521 case PixelFormat16bppRGB555:
522 setpixel_16bppRGB555(r,g,b,a,row,x);
523 break;
524 case PixelFormat16bppRGB565:
525 setpixel_16bppRGB565(r,g,b,a,row,x);
526 break;
527 case PixelFormat16bppARGB1555:
528 setpixel_16bppARGB1555(r,g,b,a,row,x);
529 break;
530 case PixelFormat24bppRGB:
531 setpixel_24bppRGB(r,g,b,a,row,x);
532 break;
533 case PixelFormat32bppRGB:
534 setpixel_32bppRGB(r,g,b,a,row,x);
535 break;
536 case PixelFormat32bppARGB:
537 setpixel_32bppARGB(r,g,b,a,row,x);
538 break;
539 case PixelFormat32bppPARGB:
540 setpixel_32bppPARGB(r,g,b,a,row,x);
541 break;
542 case PixelFormat48bppRGB:
543 setpixel_48bppRGB(r,g,b,a,row,x);
544 break;
545 case PixelFormat64bppARGB:
546 setpixel_64bppARGB(r,g,b,a,row,x);
547 break;
548 case PixelFormat64bppPARGB:
549 setpixel_64bppPARGB(r,g,b,a,row,x);
550 break;
551 case PixelFormat8bppIndexed:
552 setpixel_8bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
553 break;
554 case PixelFormat4bppIndexed:
555 setpixel_4bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
556 break;
557 case PixelFormat1bppIndexed:
558 setpixel_1bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
559 break;
560 default:
561 FIXME("not implemented for format 0x%x\n", bitmap->format);
562 return NotImplemented;
565 return Ok;
568 GpStatus convert_pixels(INT width, INT height,
569 INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
570 INT src_stride, const BYTE *src_bits, PixelFormat src_format,
571 ColorPalette *palette)
573 INT x, y;
575 if (src_format == dst_format ||
576 (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32))
578 UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8;
579 for (y=0; y<height; y++)
580 memcpy(dst_bits+dst_stride*y, src_bits+src_stride*y, widthbytes);
581 return Ok;
584 #define convert_indexed_to_rgb(getpixel_function, setpixel_function) do { \
585 for (x=0; x<width; x++) \
586 for (y=0; y<height; y++) { \
587 BYTE index; \
588 ARGB argb; \
589 BYTE *color = (BYTE *)&argb; \
590 getpixel_function(&index, src_bits+src_stride*y, x); \
591 argb = (palette && index < palette->Count) ? palette->Entries[index] : 0; \
592 setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
594 return Ok; \
595 } while (0);
597 #define convert_rgb_to_rgb(getpixel_function, setpixel_function) do { \
598 for (x=0; x<width; x++) \
599 for (y=0; y<height; y++) { \
600 BYTE r, g, b, a; \
601 getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
602 setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x); \
604 return Ok; \
605 } while (0);
607 #define convert_rgb_to_indexed(getpixel_function, setpixel_function) do { \
608 for (x=0; x<width; x++) \
609 for (y=0; y<height; y++) { \
610 BYTE r, g, b, a; \
611 getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
612 setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x, palette); \
614 return Ok; \
615 } while (0);
617 switch (src_format)
619 case PixelFormat1bppIndexed:
620 switch (dst_format)
622 case PixelFormat16bppGrayScale:
623 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppGrayScale);
624 case PixelFormat16bppRGB555:
625 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB555);
626 case PixelFormat16bppRGB565:
627 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB565);
628 case PixelFormat16bppARGB1555:
629 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppARGB1555);
630 case PixelFormat24bppRGB:
631 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_24bppRGB);
632 case PixelFormat32bppRGB:
633 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppRGB);
634 case PixelFormat32bppARGB:
635 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppARGB);
636 case PixelFormat32bppPARGB:
637 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppPARGB);
638 case PixelFormat48bppRGB:
639 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_48bppRGB);
640 case PixelFormat64bppARGB:
641 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_64bppARGB);
642 default:
643 break;
645 break;
646 case PixelFormat4bppIndexed:
647 switch (dst_format)
649 case PixelFormat16bppGrayScale:
650 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppGrayScale);
651 case PixelFormat16bppRGB555:
652 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB555);
653 case PixelFormat16bppRGB565:
654 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB565);
655 case PixelFormat16bppARGB1555:
656 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppARGB1555);
657 case PixelFormat24bppRGB:
658 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_24bppRGB);
659 case PixelFormat32bppRGB:
660 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppRGB);
661 case PixelFormat32bppARGB:
662 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppARGB);
663 case PixelFormat32bppPARGB:
664 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppPARGB);
665 case PixelFormat48bppRGB:
666 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_48bppRGB);
667 case PixelFormat64bppARGB:
668 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_64bppARGB);
669 default:
670 break;
672 break;
673 case PixelFormat8bppIndexed:
674 switch (dst_format)
676 case PixelFormat16bppGrayScale:
677 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppGrayScale);
678 case PixelFormat16bppRGB555:
679 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB555);
680 case PixelFormat16bppRGB565:
681 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB565);
682 case PixelFormat16bppARGB1555:
683 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppARGB1555);
684 case PixelFormat24bppRGB:
685 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_24bppRGB);
686 case PixelFormat32bppRGB:
687 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppRGB);
688 case PixelFormat32bppARGB:
689 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppARGB);
690 case PixelFormat32bppPARGB:
691 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppPARGB);
692 case PixelFormat48bppRGB:
693 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_48bppRGB);
694 case PixelFormat64bppARGB:
695 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_64bppARGB);
696 default:
697 break;
699 break;
700 case PixelFormat16bppGrayScale:
701 switch (dst_format)
703 case PixelFormat1bppIndexed:
704 convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_1bppIndexed);
705 case PixelFormat8bppIndexed:
706 convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_8bppIndexed);
707 case PixelFormat16bppRGB555:
708 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB555);
709 case PixelFormat16bppRGB565:
710 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB565);
711 case PixelFormat16bppARGB1555:
712 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppARGB1555);
713 case PixelFormat24bppRGB:
714 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_24bppRGB);
715 case PixelFormat32bppRGB:
716 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppRGB);
717 case PixelFormat32bppARGB:
718 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppARGB);
719 case PixelFormat32bppPARGB:
720 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppPARGB);
721 case PixelFormat48bppRGB:
722 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_48bppRGB);
723 case PixelFormat64bppARGB:
724 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_64bppARGB);
725 default:
726 break;
728 break;
729 case PixelFormat16bppRGB555:
730 switch (dst_format)
732 case PixelFormat1bppIndexed:
733 convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_1bppIndexed);
734 case PixelFormat8bppIndexed:
735 convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_8bppIndexed);
736 case PixelFormat16bppGrayScale:
737 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppGrayScale);
738 case PixelFormat16bppRGB565:
739 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppRGB565);
740 case PixelFormat16bppARGB1555:
741 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppARGB1555);
742 case PixelFormat24bppRGB:
743 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_24bppRGB);
744 case PixelFormat32bppRGB:
745 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppRGB);
746 case PixelFormat32bppARGB:
747 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppARGB);
748 case PixelFormat32bppPARGB:
749 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppPARGB);
750 case PixelFormat48bppRGB:
751 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_48bppRGB);
752 case PixelFormat64bppARGB:
753 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_64bppARGB);
754 default:
755 break;
757 break;
758 case PixelFormat16bppRGB565:
759 switch (dst_format)
761 case PixelFormat1bppIndexed:
762 convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_1bppIndexed);
763 case PixelFormat8bppIndexed:
764 convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_8bppIndexed);
765 case PixelFormat16bppGrayScale:
766 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppGrayScale);
767 case PixelFormat16bppRGB555:
768 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppRGB555);
769 case PixelFormat16bppARGB1555:
770 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppARGB1555);
771 case PixelFormat24bppRGB:
772 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_24bppRGB);
773 case PixelFormat32bppRGB:
774 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppRGB);
775 case PixelFormat32bppARGB:
776 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppARGB);
777 case PixelFormat32bppPARGB:
778 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppPARGB);
779 case PixelFormat48bppRGB:
780 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_48bppRGB);
781 case PixelFormat64bppARGB:
782 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_64bppARGB);
783 default:
784 break;
786 break;
787 case PixelFormat16bppARGB1555:
788 switch (dst_format)
790 case PixelFormat1bppIndexed:
791 convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_1bppIndexed);
792 case PixelFormat8bppIndexed:
793 convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_8bppIndexed);
794 case PixelFormat16bppGrayScale:
795 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppGrayScale);
796 case PixelFormat16bppRGB555:
797 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB555);
798 case PixelFormat16bppRGB565:
799 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB565);
800 case PixelFormat24bppRGB:
801 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_24bppRGB);
802 case PixelFormat32bppRGB:
803 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppRGB);
804 case PixelFormat32bppARGB:
805 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppARGB);
806 case PixelFormat32bppPARGB:
807 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppPARGB);
808 case PixelFormat48bppRGB:
809 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_48bppRGB);
810 case PixelFormat64bppARGB:
811 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_64bppARGB);
812 default:
813 break;
815 break;
816 case PixelFormat24bppRGB:
817 switch (dst_format)
819 case PixelFormat1bppIndexed:
820 convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_1bppIndexed);
821 case PixelFormat8bppIndexed:
822 convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_8bppIndexed);
823 case PixelFormat16bppGrayScale:
824 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppGrayScale);
825 case PixelFormat16bppRGB555:
826 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB555);
827 case PixelFormat16bppRGB565:
828 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB565);
829 case PixelFormat16bppARGB1555:
830 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppARGB1555);
831 case PixelFormat32bppRGB:
832 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppRGB);
833 case PixelFormat32bppARGB:
834 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppARGB);
835 case PixelFormat32bppPARGB:
836 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppPARGB);
837 case PixelFormat48bppRGB:
838 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_48bppRGB);
839 case PixelFormat64bppARGB:
840 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_64bppARGB);
841 default:
842 break;
844 break;
845 case PixelFormat32bppRGB:
846 switch (dst_format)
848 case PixelFormat1bppIndexed:
849 convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_1bppIndexed);
850 case PixelFormat8bppIndexed:
851 convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_8bppIndexed);
852 case PixelFormat16bppGrayScale:
853 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppGrayScale);
854 case PixelFormat16bppRGB555:
855 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB555);
856 case PixelFormat16bppRGB565:
857 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB565);
858 case PixelFormat16bppARGB1555:
859 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppARGB1555);
860 case PixelFormat24bppRGB:
861 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_24bppRGB);
862 case PixelFormat32bppARGB:
863 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppARGB);
864 case PixelFormat32bppPARGB:
865 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppPARGB);
866 case PixelFormat48bppRGB:
867 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_48bppRGB);
868 case PixelFormat64bppARGB:
869 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_64bppARGB);
870 default:
871 break;
873 break;
874 case PixelFormat32bppARGB:
875 switch (dst_format)
877 case PixelFormat1bppIndexed:
878 convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_1bppIndexed);
879 case PixelFormat8bppIndexed:
880 convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_8bppIndexed);
881 case PixelFormat16bppGrayScale:
882 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppGrayScale);
883 case PixelFormat16bppRGB555:
884 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB555);
885 case PixelFormat16bppRGB565:
886 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB565);
887 case PixelFormat16bppARGB1555:
888 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppARGB1555);
889 case PixelFormat24bppRGB:
890 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_24bppRGB);
891 case PixelFormat32bppPARGB:
892 convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
893 return Ok;
894 case PixelFormat48bppRGB:
895 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_48bppRGB);
896 case PixelFormat64bppARGB:
897 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_64bppARGB);
898 default:
899 break;
901 break;
902 case PixelFormat32bppPARGB:
903 switch (dst_format)
905 case PixelFormat1bppIndexed:
906 convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_1bppIndexed);
907 case PixelFormat8bppIndexed:
908 convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_8bppIndexed);
909 case PixelFormat16bppGrayScale:
910 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppGrayScale);
911 case PixelFormat16bppRGB555:
912 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB555);
913 case PixelFormat16bppRGB565:
914 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB565);
915 case PixelFormat16bppARGB1555:
916 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppARGB1555);
917 case PixelFormat24bppRGB:
918 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_24bppRGB);
919 case PixelFormat32bppRGB:
920 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppRGB);
921 case PixelFormat32bppARGB:
922 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppARGB);
923 case PixelFormat48bppRGB:
924 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_48bppRGB);
925 case PixelFormat64bppARGB:
926 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_64bppARGB);
927 default:
928 break;
930 break;
931 case PixelFormat48bppRGB:
932 switch (dst_format)
934 case PixelFormat1bppIndexed:
935 convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_1bppIndexed);
936 case PixelFormat8bppIndexed:
937 convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_8bppIndexed);
938 case PixelFormat16bppGrayScale:
939 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppGrayScale);
940 case PixelFormat16bppRGB555:
941 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB555);
942 case PixelFormat16bppRGB565:
943 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB565);
944 case PixelFormat16bppARGB1555:
945 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppARGB1555);
946 case PixelFormat24bppRGB:
947 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_24bppRGB);
948 case PixelFormat32bppRGB:
949 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppRGB);
950 case PixelFormat32bppARGB:
951 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppARGB);
952 case PixelFormat32bppPARGB:
953 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppPARGB);
954 case PixelFormat64bppARGB:
955 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_64bppARGB);
956 default:
957 break;
959 break;
960 case PixelFormat64bppARGB:
961 switch (dst_format)
963 case PixelFormat1bppIndexed:
964 convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_1bppIndexed);
965 case PixelFormat8bppIndexed:
966 convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_8bppIndexed);
967 case PixelFormat16bppGrayScale:
968 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppGrayScale);
969 case PixelFormat16bppRGB555:
970 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB555);
971 case PixelFormat16bppRGB565:
972 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB565);
973 case PixelFormat16bppARGB1555:
974 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppARGB1555);
975 case PixelFormat24bppRGB:
976 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_24bppRGB);
977 case PixelFormat32bppRGB:
978 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppRGB);
979 case PixelFormat32bppARGB:
980 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppARGB);
981 case PixelFormat32bppPARGB:
982 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppPARGB);
983 case PixelFormat48bppRGB:
984 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_48bppRGB);
985 default:
986 break;
988 break;
989 case PixelFormat64bppPARGB:
990 switch (dst_format)
992 case PixelFormat1bppIndexed:
993 convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_1bppIndexed);
994 case PixelFormat8bppIndexed:
995 convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_8bppIndexed);
996 case PixelFormat16bppGrayScale:
997 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppGrayScale);
998 case PixelFormat16bppRGB555:
999 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB555);
1000 case PixelFormat16bppRGB565:
1001 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB565);
1002 case PixelFormat16bppARGB1555:
1003 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppARGB1555);
1004 case PixelFormat24bppRGB:
1005 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_24bppRGB);
1006 case PixelFormat32bppRGB:
1007 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppRGB);
1008 case PixelFormat32bppARGB:
1009 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppARGB);
1010 case PixelFormat32bppPARGB:
1011 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppPARGB);
1012 case PixelFormat48bppRGB:
1013 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_48bppRGB);
1014 case PixelFormat64bppARGB:
1015 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_64bppARGB);
1016 default:
1017 break;
1019 break;
1020 default:
1021 break;
1024 #undef convert_indexed_to_rgb
1025 #undef convert_rgb_to_rgb
1027 return NotImplemented;
1030 /* This function returns a pointer to an array of pixels that represents the
1031 * bitmap. The *entire* bitmap is locked according to the lock mode specified by
1032 * flags. It is correct behavior that a user who calls this function with write
1033 * privileges can write to the whole bitmap (not just the area in rect).
1035 * FIXME: only used portion of format is bits per pixel. */
1036 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
1037 UINT flags, PixelFormat format, BitmapData* lockeddata)
1039 INT bitspp = PIXELFORMATBPP(format);
1040 GpRect act_rect; /* actual rect to be used */
1041 GpStatus stat;
1043 TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
1045 if(!lockeddata || !bitmap)
1046 return InvalidParameter;
1048 if(rect){
1049 if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
1050 (rect->Y + rect->Height > bitmap->height) || !flags)
1051 return InvalidParameter;
1053 act_rect = *rect;
1055 else{
1056 act_rect.X = act_rect.Y = 0;
1057 act_rect.Width = bitmap->width;
1058 act_rect.Height = bitmap->height;
1061 if(bitmap->lockmode)
1063 WARN("bitmap is already locked and cannot be locked again\n");
1064 return WrongState;
1067 if (bitmap->bits && bitmap->format == format && !(flags & ImageLockModeUserInputBuf))
1069 /* no conversion is necessary; just use the bits directly */
1070 lockeddata->Width = act_rect.Width;
1071 lockeddata->Height = act_rect.Height;
1072 lockeddata->PixelFormat = format;
1073 lockeddata->Reserved = flags;
1074 lockeddata->Stride = bitmap->stride;
1075 lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
1076 bitmap->stride * act_rect.Y;
1078 bitmap->lockmode = flags | ImageLockModeRead;
1079 bitmap->numlocks++;
1081 return Ok;
1084 /* Make sure we can convert to the requested format. */
1085 if (flags & ImageLockModeRead)
1087 stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL);
1088 if (stat == NotImplemented)
1090 FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
1091 return NotImplemented;
1095 /* If we're opening for writing, make sure we'll be able to write back in
1096 * the original format. */
1097 if (flags & ImageLockModeWrite)
1099 stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL);
1100 if (stat == NotImplemented)
1102 FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
1103 return NotImplemented;
1107 lockeddata->Width = act_rect.Width;
1108 lockeddata->Height = act_rect.Height;
1109 lockeddata->PixelFormat = format;
1110 lockeddata->Reserved = flags;
1112 if(!(flags & ImageLockModeUserInputBuf))
1114 lockeddata->Stride = (((act_rect.Width * bitspp + 7) / 8) + 3) & ~3;
1116 bitmap->bitmapbits = GdipAlloc(lockeddata->Stride * act_rect.Height);
1118 if (!bitmap->bitmapbits) return OutOfMemory;
1120 lockeddata->Scan0 = bitmap->bitmapbits;
1123 if (flags & ImageLockModeRead)
1125 static BOOL fixme = FALSE;
1127 if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
1129 FIXME("Cannot copy rows that don't start at a whole byte.\n");
1130 fixme = TRUE;
1133 stat = convert_pixels(act_rect.Width, act_rect.Height,
1134 lockeddata->Stride, lockeddata->Scan0, format,
1135 bitmap->stride,
1136 bitmap->bits + bitmap->stride * act_rect.Y + PIXELFORMATBPP(bitmap->format) * act_rect.X / 8,
1137 bitmap->format, bitmap->image.palette);
1139 if (stat != Ok)
1141 GdipFree(bitmap->bitmapbits);
1142 bitmap->bitmapbits = NULL;
1143 return stat;
1147 bitmap->lockmode = flags | ImageLockModeRead;
1148 bitmap->numlocks++;
1149 bitmap->lockx = act_rect.X;
1150 bitmap->locky = act_rect.Y;
1152 return Ok;
1155 GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi)
1157 TRACE("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
1159 if (!bitmap || xdpi == 0.0 || ydpi == 0.0)
1160 return InvalidParameter;
1162 bitmap->image.xres = xdpi;
1163 bitmap->image.yres = ydpi;
1165 return Ok;
1168 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
1169 BitmapData* lockeddata)
1171 GpStatus stat;
1172 static BOOL fixme = FALSE;
1174 TRACE("(%p,%p)\n", bitmap, lockeddata);
1176 if(!bitmap || !lockeddata)
1177 return InvalidParameter;
1179 if(!bitmap->lockmode)
1180 return WrongState;
1182 if(!(lockeddata->Reserved & ImageLockModeWrite)){
1183 if(!(--bitmap->numlocks))
1184 bitmap->lockmode = 0;
1186 GdipFree(bitmap->bitmapbits);
1187 bitmap->bitmapbits = NULL;
1188 return Ok;
1191 if (!bitmap->bitmapbits && !(lockeddata->Reserved & ImageLockModeUserInputBuf))
1193 /* we passed a direct reference; no need to do anything */
1194 bitmap->lockmode = 0;
1195 bitmap->numlocks = 0;
1196 return Ok;
1199 if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
1201 FIXME("Cannot copy rows that don't start at a whole byte.\n");
1202 fixme = TRUE;
1205 stat = convert_pixels(lockeddata->Width, lockeddata->Height,
1206 bitmap->stride,
1207 bitmap->bits + bitmap->stride * bitmap->locky + PIXELFORMATBPP(bitmap->format) * bitmap->lockx / 8,
1208 bitmap->format,
1209 lockeddata->Stride, lockeddata->Scan0, lockeddata->PixelFormat, NULL);
1211 if (stat != Ok)
1213 ERR("failed to convert pixels; this should never happen\n");
1216 GdipFree(bitmap->bitmapbits);
1217 bitmap->bitmapbits = NULL;
1218 bitmap->lockmode = 0;
1219 bitmap->numlocks = 0;
1221 return stat;
1224 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
1225 PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1227 Rect area;
1228 GpStatus stat;
1230 TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1232 if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap ||
1233 x < 0 || y < 0 ||
1234 x + width > srcBitmap->width || y + height > srcBitmap->height)
1236 TRACE("<-- InvalidParameter\n");
1237 return InvalidParameter;
1240 if (format == PixelFormatDontCare)
1241 format = srcBitmap->format;
1243 area.X = gdip_round(x);
1244 area.Y = gdip_round(y);
1245 area.Width = gdip_round(width);
1246 area.Height = gdip_round(height);
1248 stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap);
1249 if (stat == Ok)
1251 stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format,
1252 srcBitmap->stride,
1253 srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8,
1254 srcBitmap->format, srcBitmap->image.palette);
1255 if (stat != Ok)
1256 GdipDisposeImage((GpImage*)*dstBitmap);
1259 if (stat != Ok)
1260 *dstBitmap = NULL;
1262 return stat;
1265 GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
1266 PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1268 TRACE("(%i,%i,%i,%i,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1270 return GdipCloneBitmapArea(x, y, width, height, format, srcBitmap, dstBitmap);
1273 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
1275 GpStatus stat = GenericError;
1277 TRACE("%p, %p\n", image, cloneImage);
1279 if (!image || !cloneImage)
1280 return InvalidParameter;
1282 if (image->picture)
1284 IStream* stream;
1285 HRESULT hr;
1286 INT size;
1287 LARGE_INTEGER move;
1289 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
1290 if (FAILED(hr))
1291 return GenericError;
1293 hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
1294 if(FAILED(hr))
1296 WARN("Failed to save image on stream\n");
1297 goto out;
1300 /* Set seek pointer back to the beginning of the picture */
1301 move.QuadPart = 0;
1302 hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
1303 if (FAILED(hr))
1304 goto out;
1306 stat = GdipLoadImageFromStream(stream, cloneImage);
1307 if (stat != Ok) WARN("Failed to load image from stream\n");
1309 out:
1310 IStream_Release(stream);
1311 return stat;
1313 else if (image->type == ImageTypeBitmap)
1315 GpBitmap *bitmap = (GpBitmap *)image;
1317 return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height,
1318 bitmap->format, bitmap, (GpBitmap **)cloneImage);
1320 else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
1322 GpMetafile *result, *metafile;
1324 metafile = (GpMetafile*)image;
1326 result = GdipAlloc(sizeof(*result));
1327 if (!result)
1328 return OutOfMemory;
1330 result->image.type = ImageTypeMetafile;
1331 result->image.format = image->format;
1332 result->image.flags = image->flags;
1333 result->image.frame_count = 1;
1334 result->image.xres = image->xres;
1335 result->image.yres = image->yres;
1336 result->bounds = metafile->bounds;
1337 result->unit = metafile->unit;
1338 result->metafile_type = metafile->metafile_type;
1339 result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
1341 if (!result->hemf)
1343 GdipFree(result);
1344 return OutOfMemory;
1347 *cloneImage = &result->image;
1348 return Ok;
1350 else
1352 WARN("GpImage with no image data (metafile in wrong state?)\n");
1353 return InvalidParameter;
1357 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
1358 GpBitmap **bitmap)
1360 GpStatus stat;
1361 IStream *stream;
1363 TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1365 if(!filename || !bitmap)
1366 return InvalidParameter;
1368 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
1370 if(stat != Ok)
1371 return stat;
1373 stat = GdipCreateBitmapFromStream(stream, bitmap);
1375 IStream_Release(stream);
1377 return stat;
1380 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info,
1381 VOID *bits, GpBitmap **bitmap)
1383 DWORD height, stride;
1384 PixelFormat format;
1386 FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
1388 if (!info || !bits || !bitmap)
1389 return InvalidParameter;
1391 height = abs(info->bmiHeader.biHeight);
1392 stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
1394 if(info->bmiHeader.biHeight > 0) /* bottom-up */
1396 bits = (BYTE*)bits + (height - 1) * stride;
1397 stride = -stride;
1400 switch(info->bmiHeader.biBitCount) {
1401 case 1:
1402 format = PixelFormat1bppIndexed;
1403 break;
1404 case 4:
1405 format = PixelFormat4bppIndexed;
1406 break;
1407 case 8:
1408 format = PixelFormat8bppIndexed;
1409 break;
1410 case 16:
1411 format = PixelFormat16bppRGB555;
1412 break;
1413 case 24:
1414 format = PixelFormat24bppRGB;
1415 break;
1416 case 32:
1417 format = PixelFormat32bppRGB;
1418 break;
1419 default:
1420 FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
1421 *bitmap = NULL;
1422 return InvalidParameter;
1425 return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
1426 bits, bitmap);
1430 /* FIXME: no icm */
1431 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename,
1432 GpBitmap **bitmap)
1434 TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1436 return GdipCreateBitmapFromFile(filename, bitmap);
1439 GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
1440 GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
1442 HBITMAP hbm;
1443 GpStatus stat = InvalidParameter;
1445 TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
1447 if(!lpBitmapName || !bitmap)
1448 return InvalidParameter;
1450 /* load DIB */
1451 hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
1452 LR_CREATEDIBSECTION);
1454 if(hbm){
1455 stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
1456 DeleteObject(hbm);
1459 return stat;
1462 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
1463 HBITMAP* hbmReturn, ARGB background)
1465 GpStatus stat;
1466 HBITMAP result;
1467 UINT width, height;
1468 BITMAPINFOHEADER bih;
1469 LPBYTE bits;
1470 BitmapData lockeddata;
1471 TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
1473 if (!bitmap || !hbmReturn) return InvalidParameter;
1475 GdipGetImageWidth((GpImage*)bitmap, &width);
1476 GdipGetImageHeight((GpImage*)bitmap, &height);
1478 bih.biSize = sizeof(bih);
1479 bih.biWidth = width;
1480 bih.biHeight = height;
1481 bih.biPlanes = 1;
1482 bih.biBitCount = 32;
1483 bih.biCompression = BI_RGB;
1484 bih.biSizeImage = 0;
1485 bih.biXPelsPerMeter = 0;
1486 bih.biYPelsPerMeter = 0;
1487 bih.biClrUsed = 0;
1488 bih.biClrImportant = 0;
1490 result = CreateDIBSection(0, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1492 if (result)
1494 lockeddata.Stride = -width * 4;
1495 lockeddata.Scan0 = bits + (width * 4 * (height - 1));
1497 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead|ImageLockModeUserInputBuf,
1498 PixelFormat32bppPARGB, &lockeddata);
1500 if (stat == Ok)
1501 stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
1503 else
1504 stat = GenericError;
1506 if (stat != Ok && result)
1508 DeleteObject(result);
1509 result = NULL;
1512 *hbmReturn = result;
1514 return stat;
1517 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
1518 GpMetafile* metafile, BOOL* succ, EmfType emfType,
1519 const WCHAR* description, GpMetafile** out_metafile)
1521 static int calls;
1523 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
1524 debugstr_w(description), out_metafile);
1526 if(!ref || !metafile || !out_metafile)
1527 return InvalidParameter;
1529 *succ = FALSE;
1530 *out_metafile = NULL;
1532 if(!(calls++))
1533 FIXME("not implemented\n");
1535 return NotImplemented;
1538 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
1539 GpGraphics* target, GpBitmap** bitmap)
1541 GpStatus ret;
1543 TRACE("(%d, %d, %p, %p)\n", width, height, target, bitmap);
1545 if(!target || !bitmap)
1546 return InvalidParameter;
1548 ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
1549 NULL, bitmap);
1551 if (ret == Ok)
1553 GdipGetDpiX(target, &(*bitmap)->image.xres);
1554 GdipGetDpiY(target, &(*bitmap)->image.yres);
1557 return ret;
1560 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
1562 GpStatus stat;
1563 ICONINFO iinfo;
1564 BITMAP bm;
1565 int ret;
1566 UINT width, height, stride;
1567 GpRect rect;
1568 BitmapData lockeddata;
1569 HDC screendc;
1570 BOOL has_alpha;
1571 int x, y;
1572 BITMAPINFOHEADER bih;
1573 DWORD *src;
1574 BYTE *dst_row;
1575 DWORD *dst;
1577 TRACE("%p, %p\n", hicon, bitmap);
1579 if(!bitmap || !GetIconInfo(hicon, &iinfo))
1580 return InvalidParameter;
1582 /* get the size of the icon */
1583 ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
1584 if (ret == 0) {
1585 DeleteObject(iinfo.hbmColor);
1586 DeleteObject(iinfo.hbmMask);
1587 return GenericError;
1590 width = bm.bmWidth;
1591 height = iinfo.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2;
1592 stride = width * 4;
1594 stat = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat32bppARGB, NULL, bitmap);
1595 if (stat != Ok) {
1596 DeleteObject(iinfo.hbmColor);
1597 DeleteObject(iinfo.hbmMask);
1598 return stat;
1601 rect.X = 0;
1602 rect.Y = 0;
1603 rect.Width = width;
1604 rect.Height = height;
1606 stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
1607 if (stat != Ok) {
1608 DeleteObject(iinfo.hbmColor);
1609 DeleteObject(iinfo.hbmMask);
1610 GdipDisposeImage((GpImage*)*bitmap);
1611 return stat;
1614 bih.biSize = sizeof(bih);
1615 bih.biWidth = width;
1616 bih.biHeight = iinfo.hbmColor ? -height: -height * 2;
1617 bih.biPlanes = 1;
1618 bih.biBitCount = 32;
1619 bih.biCompression = BI_RGB;
1620 bih.biSizeImage = 0;
1621 bih.biXPelsPerMeter = 0;
1622 bih.biYPelsPerMeter = 0;
1623 bih.biClrUsed = 0;
1624 bih.biClrImportant = 0;
1626 screendc = CreateCompatibleDC(0);
1627 if (iinfo.hbmColor)
1629 GetDIBits(screendc, iinfo.hbmColor, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1631 if (bm.bmBitsPixel == 32)
1633 has_alpha = FALSE;
1635 /* If any pixel has a non-zero alpha, ignore hbmMask */
1636 src = (DWORD*)lockeddata.Scan0;
1637 for (x=0; x<width && !has_alpha; x++)
1638 for (y=0; y<height && !has_alpha; y++)
1639 if ((*src++ & 0xff000000) != 0)
1640 has_alpha = TRUE;
1642 else has_alpha = FALSE;
1644 else
1646 GetDIBits(screendc, iinfo.hbmMask, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1647 has_alpha = FALSE;
1650 if (!has_alpha)
1652 if (iinfo.hbmMask)
1654 BYTE *bits = HeapAlloc(GetProcessHeap(), 0, height * stride);
1656 /* read alpha data from the mask */
1657 if (iinfo.hbmColor)
1658 GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1659 else
1660 GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1662 src = (DWORD*)bits;
1663 dst_row = lockeddata.Scan0;
1664 for (y=0; y<height; y++)
1666 dst = (DWORD*)dst_row;
1667 for (x=0; x<height; x++)
1669 DWORD src_value = *src++;
1670 if (src_value)
1671 *dst++ = 0;
1672 else
1673 *dst++ |= 0xff000000;
1675 dst_row += lockeddata.Stride;
1678 HeapFree(GetProcessHeap(), 0, bits);
1680 else
1682 /* set constant alpha of 255 */
1683 dst_row = lockeddata.Scan0;
1684 for (y=0; y<height; y++)
1686 dst = (DWORD*)dst_row;
1687 for (x=0; x<height; x++)
1688 *dst++ |= 0xff000000;
1689 dst_row += lockeddata.Stride;
1694 DeleteDC(screendc);
1696 DeleteObject(iinfo.hbmColor);
1697 DeleteObject(iinfo.hbmMask);
1699 GdipBitmapUnlockBits(*bitmap, &lockeddata);
1701 return Ok;
1704 static void generate_halftone_palette(ARGB *entries, UINT count)
1706 static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
1707 UINT i;
1709 for (i=0; i<8 && i<count; i++)
1711 entries[i] = 0xff000000;
1712 if (i&1) entries[i] |= 0x800000;
1713 if (i&2) entries[i] |= 0x8000;
1714 if (i&4) entries[i] |= 0x80;
1717 if (8 < count)
1718 entries[i] = 0xffc0c0c0;
1720 for (i=9; i<16 && i<count; i++)
1722 entries[i] = 0xff000000;
1723 if (i&1) entries[i] |= 0xff0000;
1724 if (i&2) entries[i] |= 0xff00;
1725 if (i&4) entries[i] |= 0xff;
1728 for (i=16; i<40 && i<count; i++)
1730 entries[i] = 0;
1733 for (i=40; i<256 && i<count; i++)
1735 entries[i] = 0xff000000;
1736 entries[i] |= halftone_values[(i-40)%6];
1737 entries[i] |= halftone_values[((i-40)/6)%6] << 8;
1738 entries[i] |= halftone_values[((i-40)/36)%6] << 16;
1742 static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
1744 HDC screendc = CreateCompatibleDC(0);
1746 if (!screendc) return GenericError;
1748 *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
1749 *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
1751 DeleteDC(screendc);
1753 return Ok;
1756 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
1757 PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
1759 HBITMAP hbitmap=NULL;
1760 INT row_size, dib_stride;
1761 BYTE *bits=NULL, *own_bits=NULL;
1762 REAL xres, yres;
1763 GpStatus stat;
1765 TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
1767 if (!bitmap) return InvalidParameter;
1769 if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
1770 *bitmap = NULL;
1771 return InvalidParameter;
1774 if(scan0 && !stride)
1775 return InvalidParameter;
1777 stat = get_screen_resolution(&xres, &yres);
1778 if (stat != Ok) return stat;
1780 row_size = (width * PIXELFORMATBPP(format)+7) / 8;
1781 dib_stride = (row_size + 3) & ~3;
1783 if(stride == 0)
1784 stride = dib_stride;
1786 if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
1788 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1789 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
1791 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1792 pbmi->bmiHeader.biWidth = width;
1793 pbmi->bmiHeader.biHeight = -height;
1794 pbmi->bmiHeader.biPlanes = 1;
1795 /* FIXME: use the rest of the data from format */
1796 pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
1797 pbmi->bmiHeader.biCompression = BI_RGB;
1798 pbmi->bmiHeader.biSizeImage = 0;
1799 pbmi->bmiHeader.biXPelsPerMeter = 0;
1800 pbmi->bmiHeader.biYPelsPerMeter = 0;
1801 pbmi->bmiHeader.biClrUsed = 0;
1802 pbmi->bmiHeader.biClrImportant = 0;
1804 hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1806 if (!hbitmap) return GenericError;
1808 stride = dib_stride;
1810 else
1812 /* Not a GDI format; don't try to make an HBITMAP. */
1813 if (scan0)
1814 bits = scan0;
1815 else
1817 INT size = abs(stride) * height;
1819 own_bits = bits = GdipAlloc(size);
1820 if (!own_bits) return OutOfMemory;
1822 if (stride < 0)
1823 bits += stride * (1 - height);
1827 *bitmap = GdipAlloc(sizeof(GpBitmap));
1828 if(!*bitmap)
1830 DeleteObject(hbitmap);
1831 GdipFree(own_bits);
1832 return OutOfMemory;
1835 (*bitmap)->image.type = ImageTypeBitmap;
1836 memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
1837 (*bitmap)->image.flags = ImageFlagsNone;
1838 (*bitmap)->image.frame_count = 1;
1839 (*bitmap)->image.current_frame = 0;
1840 (*bitmap)->image.palette = NULL;
1841 (*bitmap)->image.xres = xres;
1842 (*bitmap)->image.yres = yres;
1843 (*bitmap)->width = width;
1844 (*bitmap)->height = height;
1845 (*bitmap)->format = format;
1846 (*bitmap)->image.picture = NULL;
1847 (*bitmap)->image.stream = NULL;
1848 (*bitmap)->hbitmap = hbitmap;
1849 (*bitmap)->hdc = NULL;
1850 (*bitmap)->bits = bits;
1851 (*bitmap)->stride = stride;
1852 (*bitmap)->own_bits = own_bits;
1853 (*bitmap)->metadata_reader = NULL;
1854 (*bitmap)->prop_count = 0;
1855 (*bitmap)->prop_item = NULL;
1857 /* set format-related flags */
1858 if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed))
1859 (*bitmap)->image.flags |= ImageFlagsHasAlpha;
1861 if (format == PixelFormat1bppIndexed ||
1862 format == PixelFormat4bppIndexed ||
1863 format == PixelFormat8bppIndexed)
1865 (*bitmap)->image.palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * (1 << PIXELFORMATBPP(format)));
1867 if (!(*bitmap)->image.palette)
1869 GdipDisposeImage(&(*bitmap)->image);
1870 *bitmap = NULL;
1871 return OutOfMemory;
1874 (*bitmap)->image.palette->Count = 1 << PIXELFORMATBPP(format);
1876 if (format == PixelFormat1bppIndexed)
1878 (*bitmap)->image.palette->Flags = PaletteFlagsGrayScale;
1879 (*bitmap)->image.palette->Entries[0] = 0xff000000;
1880 (*bitmap)->image.palette->Entries[1] = 0xffffffff;
1882 else
1884 if (format == PixelFormat8bppIndexed)
1885 (*bitmap)->image.palette->Flags = PaletteFlagsHalftone;
1887 generate_halftone_palette((*bitmap)->image.palette->Entries,
1888 (*bitmap)->image.palette->Count);
1892 TRACE("<-- %p\n", *bitmap);
1894 return Ok;
1897 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
1898 GpBitmap **bitmap)
1900 GpStatus stat;
1902 TRACE("%p %p\n", stream, bitmap);
1904 stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
1906 if(stat != Ok)
1907 return stat;
1909 if((*bitmap)->image.type != ImageTypeBitmap){
1910 GdipDisposeImage(&(*bitmap)->image);
1911 *bitmap = NULL;
1912 return GenericError; /* FIXME: what error to return? */
1915 return Ok;
1918 /* FIXME: no icm */
1919 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
1920 GpBitmap **bitmap)
1922 TRACE("%p %p\n", stream, bitmap);
1924 return GdipCreateBitmapFromStream(stream, bitmap);
1927 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
1928 GpCachedBitmap **cachedbmp)
1930 GpStatus stat;
1932 TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
1934 if(!bitmap || !graphics || !cachedbmp)
1935 return InvalidParameter;
1937 *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
1938 if(!*cachedbmp)
1939 return OutOfMemory;
1941 stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
1942 if(stat != Ok){
1943 GdipFree(*cachedbmp);
1944 return stat;
1947 return Ok;
1950 GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon)
1952 GpStatus stat;
1953 BitmapData lockeddata;
1954 ULONG andstride, xorstride, bitssize;
1955 LPBYTE andbits, xorbits, androw, xorrow, srcrow;
1956 UINT x, y;
1958 TRACE("(%p, %p)\n", bitmap, hicon);
1960 if (!bitmap || !hicon)
1961 return InvalidParameter;
1963 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead,
1964 PixelFormat32bppPARGB, &lockeddata);
1965 if (stat == Ok)
1967 andstride = ((lockeddata.Width+31)/32)*4;
1968 xorstride = lockeddata.Width*4;
1969 bitssize = (andstride + xorstride) * lockeddata.Height;
1971 andbits = GdipAlloc(bitssize);
1973 if (andbits)
1975 xorbits = andbits + andstride * lockeddata.Height;
1977 for (y=0; y<lockeddata.Height; y++)
1979 srcrow = ((LPBYTE)lockeddata.Scan0) + lockeddata.Stride * y;
1981 androw = andbits + andstride * y;
1982 for (x=0; x<lockeddata.Width; x++)
1983 if (srcrow[3+4*x] >= 128)
1984 androw[x/8] |= 1 << (7-x%8);
1986 xorrow = xorbits + xorstride * y;
1987 memcpy(xorrow, srcrow, xorstride);
1990 *hicon = CreateIcon(NULL, lockeddata.Width, lockeddata.Height, 1, 32,
1991 andbits, xorbits);
1993 GdipFree(andbits);
1995 else
1996 stat = OutOfMemory;
1998 GdipBitmapUnlockBits(bitmap, &lockeddata);
2001 return stat;
2004 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
2006 TRACE("%p\n", cachedbmp);
2008 if(!cachedbmp)
2009 return InvalidParameter;
2011 GdipDisposeImage(cachedbmp->image);
2012 GdipFree(cachedbmp);
2014 return Ok;
2017 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
2018 GpCachedBitmap *cachedbmp, INT x, INT y)
2020 TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
2022 if(!graphics || !cachedbmp)
2023 return InvalidParameter;
2025 return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
2028 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
2029 LPBYTE pData16, INT iMapMode, INT eFlags)
2031 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
2032 return NotImplemented;
2035 /* Internal utility function: Replace the image data of dst with that of src,
2036 * and free src. */
2037 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
2039 assert(src->image.type == ImageTypeBitmap);
2040 assert(dst->image.type == ImageTypeBitmap);
2042 GdipFree(dst->bitmapbits);
2043 GdipFree(dst->own_bits);
2044 DeleteDC(dst->hdc);
2045 DeleteObject(dst->hbitmap);
2047 if (clobber_palette)
2049 GdipFree(dst->image.palette);
2050 dst->image.palette = src->image.palette;
2052 else
2053 GdipFree(src->image.palette);
2055 dst->image.xres = src->image.xres;
2056 dst->image.yres = src->image.yres;
2057 dst->width = src->width;
2058 dst->height = src->height;
2059 dst->format = src->format;
2060 dst->hbitmap = src->hbitmap;
2061 dst->hdc = src->hdc;
2062 dst->bits = src->bits;
2063 dst->stride = src->stride;
2064 dst->own_bits = src->own_bits;
2065 if (dst->metadata_reader)
2066 IWICMetadataReader_Release(dst->metadata_reader);
2067 dst->metadata_reader = src->metadata_reader;
2068 GdipFree(dst->prop_item);
2069 dst->prop_item = src->prop_item;
2070 dst->prop_count = src->prop_count;
2071 if (dst->image.stream)
2072 IStream_Release(dst->image.stream);
2073 dst->image.stream = src->image.stream;
2074 dst->image.frame_count = src->image.frame_count;
2075 dst->image.current_frame = src->image.current_frame;
2076 dst->image.format = src->image.format;
2078 src->image.type = ~0;
2079 GdipFree(src);
2082 static GpStatus free_image_data(GpImage *image)
2084 if(!image)
2085 return InvalidParameter;
2087 if (image->type == ImageTypeBitmap)
2089 GdipFree(((GpBitmap*)image)->bitmapbits);
2090 GdipFree(((GpBitmap*)image)->own_bits);
2091 DeleteDC(((GpBitmap*)image)->hdc);
2092 DeleteObject(((GpBitmap*)image)->hbitmap);
2093 if (((GpBitmap*)image)->metadata_reader)
2094 IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader);
2095 GdipFree(((GpBitmap*)image)->prop_item);
2097 else if (image->type == ImageTypeMetafile)
2099 GpMetafile *metafile = (GpMetafile*)image;
2100 GdipFree(metafile->comment_data);
2101 DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
2102 if (!metafile->preserve_hemf)
2103 DeleteEnhMetaFile(metafile->hemf);
2104 if (metafile->record_graphics)
2106 WARN("metafile closed while recording\n");
2107 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
2108 metafile->record_graphics->image = NULL;
2109 metafile->record_graphics->busy = TRUE;
2112 else
2114 WARN("invalid image: %p\n", image);
2115 return ObjectBusy;
2117 if (image->picture)
2118 IPicture_Release(image->picture);
2119 if (image->stream)
2120 IStream_Release(image->stream);
2121 GdipFree(image->palette);
2123 return Ok;
2126 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
2128 GpStatus status;
2130 TRACE("%p\n", image);
2132 status = free_image_data(image);
2133 if (status != Ok) return status;
2134 image->type = ~0;
2135 GdipFree(image);
2137 return Ok;
2140 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
2142 static int calls;
2144 TRACE("(%p,%p)\n", image, item);
2146 if(!image || !item)
2147 return InvalidParameter;
2149 if (!(calls++))
2150 FIXME("not implemented\n");
2152 return NotImplemented;
2155 GpStatus WINGDIPAPI GdipGetImageItemData(GpImage *image, ImageItemData *item)
2157 static int calls;
2159 TRACE("(%p,%p)\n", image, item);
2161 if (!(calls++))
2162 FIXME("not implemented\n");
2164 return NotImplemented;
2167 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
2168 GpUnit *srcUnit)
2170 TRACE("%p %p %p\n", image, srcRect, srcUnit);
2172 if(!image || !srcRect || !srcUnit)
2173 return InvalidParameter;
2174 if(image->type == ImageTypeMetafile){
2175 *srcRect = ((GpMetafile*)image)->bounds;
2176 *srcUnit = ((GpMetafile*)image)->unit;
2178 else if(image->type == ImageTypeBitmap){
2179 srcRect->X = srcRect->Y = 0.0;
2180 srcRect->Width = (REAL) ((GpBitmap*)image)->width;
2181 srcRect->Height = (REAL) ((GpBitmap*)image)->height;
2182 *srcUnit = UnitPixel;
2184 else{
2185 srcRect->X = srcRect->Y = 0.0;
2186 srcRect->Width = ipicture_pixel_width(image->picture);
2187 srcRect->Height = ipicture_pixel_height(image->picture);
2188 *srcUnit = UnitPixel;
2191 TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
2192 srcRect->Width, srcRect->Height, *srcUnit);
2194 return Ok;
2197 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
2198 REAL *height)
2200 TRACE("%p %p %p\n", image, width, height);
2202 if(!image || !height || !width)
2203 return InvalidParameter;
2205 if(image->type == ImageTypeMetafile){
2206 *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2207 *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2209 else if(image->type == ImageTypeBitmap){
2210 *height = ((GpBitmap*)image)->height;
2211 *width = ((GpBitmap*)image)->width;
2213 else{
2214 *height = ipicture_pixel_height(image->picture);
2215 *width = ipicture_pixel_width(image->picture);
2218 TRACE("returning (%f, %f)\n", *height, *width);
2219 return Ok;
2222 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
2223 GpGraphics **graphics)
2225 HDC hdc;
2226 GpStatus stat;
2228 TRACE("%p %p\n", image, graphics);
2230 if(!image || !graphics)
2231 return InvalidParameter;
2233 if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
2235 hdc = ((GpBitmap*)image)->hdc;
2237 if(!hdc){
2238 hdc = CreateCompatibleDC(0);
2239 SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
2240 ((GpBitmap*)image)->hdc = hdc;
2243 stat = GdipCreateFromHDC(hdc, graphics);
2245 if (stat == Ok)
2247 (*graphics)->image = image;
2248 (*graphics)->xres = image->xres;
2249 (*graphics)->yres = image->yres;
2252 else if (image->type == ImageTypeMetafile)
2253 stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics);
2254 else
2255 stat = graphics_from_image(image, graphics);
2257 return stat;
2260 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
2262 TRACE("%p %p\n", image, height);
2264 if(!image || !height)
2265 return InvalidParameter;
2267 if(image->type == ImageTypeMetafile)
2268 *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2269 else if(image->type == ImageTypeBitmap)
2270 *height = ((GpBitmap*)image)->height;
2271 else
2272 *height = ipicture_pixel_height(image->picture);
2274 TRACE("returning %d\n", *height);
2276 return Ok;
2279 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
2281 if(!image || !res)
2282 return InvalidParameter;
2284 *res = image->xres;
2286 TRACE("(%p) <-- %0.2f\n", image, *res);
2288 return Ok;
2291 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
2293 TRACE("%p %p\n", image, size);
2295 if(!image || !size)
2296 return InvalidParameter;
2298 if (!image->palette || image->palette->Count == 0)
2299 *size = sizeof(ColorPalette);
2300 else
2301 *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette->Count;
2303 TRACE("<-- %u\n", *size);
2305 return Ok;
2308 /* FIXME: test this function for non-bitmap types */
2309 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
2311 TRACE("%p %p\n", image, format);
2313 if(!image || !format)
2314 return InvalidParameter;
2316 if(image->type != ImageTypeBitmap)
2317 *format = PixelFormat24bppRGB;
2318 else
2319 *format = ((GpBitmap*) image)->format;
2321 return Ok;
2324 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
2326 TRACE("(%p, %p)\n", image, format);
2328 if(!image || !format)
2329 return InvalidParameter;
2331 memcpy(format, &image->format, sizeof(GUID));
2333 return Ok;
2336 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
2338 TRACE("%p %p\n", image, type);
2340 if(!image || !type)
2341 return InvalidParameter;
2343 *type = image->type;
2345 return Ok;
2348 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
2350 if(!image || !res)
2351 return InvalidParameter;
2353 *res = image->yres;
2355 TRACE("(%p) <-- %0.2f\n", image, *res);
2357 return Ok;
2360 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
2362 TRACE("%p %p\n", image, width);
2364 if(!image || !width)
2365 return InvalidParameter;
2367 if(image->type == ImageTypeMetafile)
2368 *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2369 else if(image->type == ImageTypeBitmap)
2370 *width = ((GpBitmap*)image)->width;
2371 else
2372 *width = ipicture_pixel_width(image->picture);
2374 TRACE("returning %d\n", *width);
2376 return Ok;
2379 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
2380 MetafileHeader * header)
2382 static int calls;
2384 TRACE("(%p, %p)\n", metafile, header);
2386 if(!metafile || !header)
2387 return InvalidParameter;
2389 if(!(calls++))
2390 FIXME("not implemented\n");
2392 memset(header, 0, sizeof(MetafileHeader));
2394 return Ok;
2397 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
2398 MetafileHeader *header)
2400 static int calls;
2402 if(!hEmf || !header)
2403 return InvalidParameter;
2405 if(!(calls++))
2406 FIXME("not implemented\n");
2408 memset(header, 0, sizeof(MetafileHeader));
2410 return Ok;
2413 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
2414 MetafileHeader *header)
2416 static int calls;
2418 TRACE("(%s,%p)\n", debugstr_w(filename), header);
2420 if(!filename || !header)
2421 return InvalidParameter;
2423 if(!(calls++))
2424 FIXME("not implemented\n");
2426 memset(header, 0, sizeof(MetafileHeader));
2428 return Ok;
2431 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
2432 MetafileHeader *header)
2434 static int calls;
2436 TRACE("(%p,%p)\n", stream, header);
2438 if(!stream || !header)
2439 return InvalidParameter;
2441 if(!(calls++))
2442 FIXME("not implemented\n");
2444 memset(header, 0, sizeof(MetafileHeader));
2446 return Ok;
2449 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num)
2451 TRACE("(%p, %p)\n", image, num);
2453 if (!image || !num) return InvalidParameter;
2455 *num = 0;
2457 if (image->type == ImageTypeBitmap)
2459 if (((GpBitmap *)image)->prop_item)
2461 *num = ((GpBitmap *)image)->prop_count;
2462 return Ok;
2465 if (((GpBitmap *)image)->metadata_reader)
2466 IWICMetadataReader_GetCount(((GpBitmap *)image)->metadata_reader, num);
2469 return Ok;
2472 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID *list)
2474 HRESULT hr;
2475 IWICMetadataReader *reader;
2476 IWICEnumMetadataItem *enumerator;
2477 UINT prop_count, i, items_returned;
2479 TRACE("(%p, %u, %p)\n", image, num, list);
2481 if (!image || !list) return InvalidParameter;
2483 if (image->type != ImageTypeBitmap)
2485 FIXME("Not implemented for type %d\n", image->type);
2486 return NotImplemented;
2489 if (((GpBitmap *)image)->prop_item)
2491 if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter;
2493 for (i = 0; i < num; i++)
2495 list[i] = ((GpBitmap *)image)->prop_item[i].id;
2498 return Ok;
2501 reader = ((GpBitmap *)image)->metadata_reader;
2502 if (!reader)
2504 if (num != 0) return InvalidParameter;
2505 return Ok;
2508 hr = IWICMetadataReader_GetCount(reader, &prop_count);
2509 if (FAILED(hr)) return hresult_to_status(hr);
2511 if (num != prop_count) return InvalidParameter;
2513 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2514 if (FAILED(hr)) return hresult_to_status(hr);
2516 IWICEnumMetadataItem_Reset(enumerator);
2518 for (i = 0; i < num; i++)
2520 PROPVARIANT id;
2522 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, NULL, &items_returned);
2523 if (hr != S_OK) break;
2525 if (id.vt != VT_UI2)
2527 FIXME("not supported propvariant type for id: %u\n", id.vt);
2528 list[i] = 0;
2529 continue;
2531 list[i] = id.u.uiVal;
2534 IWICEnumMetadataItem_Release(enumerator);
2536 return hr == S_OK ? Ok : hresult_to_status(hr);
2539 static UINT propvariant_size(PROPVARIANT *value)
2541 switch (value->vt & ~VT_VECTOR)
2543 case VT_EMPTY:
2544 return 0;
2545 case VT_I1:
2546 case VT_UI1:
2547 if (!(value->vt & VT_VECTOR)) return 1;
2548 return value->u.caub.cElems;
2549 case VT_I2:
2550 case VT_UI2:
2551 if (!(value->vt & VT_VECTOR)) return 2;
2552 return value->u.caui.cElems * 2;
2553 case VT_I4:
2554 case VT_UI4:
2555 case VT_R4:
2556 if (!(value->vt & VT_VECTOR)) return 4;
2557 return value->u.caul.cElems * 4;
2558 case VT_I8:
2559 case VT_UI8:
2560 case VT_R8:
2561 if (!(value->vt & VT_VECTOR)) return 8;
2562 return value->u.cauh.cElems * 8;
2563 case VT_LPSTR:
2564 return value->u.pszVal ? strlen(value->u.pszVal) + 1 : 0;
2565 case VT_BLOB:
2566 return value->u.blob.cbSize;
2567 default:
2568 FIXME("not supported variant type %d\n", value->vt);
2569 return 0;
2573 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID propid, UINT *size)
2575 HRESULT hr;
2576 IWICMetadataReader *reader;
2577 PROPVARIANT id, value;
2579 TRACE("(%p,%#x,%p)\n", image, propid, size);
2581 if (!size || !image) return InvalidParameter;
2583 if (image->type != ImageTypeBitmap)
2585 FIXME("Not implemented for type %d\n", image->type);
2586 return NotImplemented;
2589 if (((GpBitmap *)image)->prop_item)
2591 UINT i;
2593 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2595 if (propid == ((GpBitmap *)image)->prop_item[i].id)
2597 *size = sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2598 return Ok;
2602 return PropertyNotFound;
2605 reader = ((GpBitmap *)image)->metadata_reader;
2606 if (!reader) return PropertyNotFound;
2608 id.vt = VT_UI2;
2609 id.u.uiVal = propid;
2610 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2611 if (FAILED(hr)) return PropertyNotFound;
2613 *size = propvariant_size(&value);
2614 if (*size) *size += sizeof(PropertyItem);
2615 PropVariantClear(&value);
2617 return Ok;
2620 #ifndef PropertyTagTypeSByte
2621 #define PropertyTagTypeSByte 6
2622 #define PropertyTagTypeSShort 8
2623 #define PropertyTagTypeFloat 11
2624 #define PropertyTagTypeDouble 12
2625 #endif
2627 static UINT vt_to_itemtype(UINT vt)
2629 static const struct
2631 UINT vt, type;
2632 } vt2type[] =
2634 { VT_I1, PropertyTagTypeSByte },
2635 { VT_UI1, PropertyTagTypeByte },
2636 { VT_I2, PropertyTagTypeSShort },
2637 { VT_UI2, PropertyTagTypeShort },
2638 { VT_I4, PropertyTagTypeSLONG },
2639 { VT_UI4, PropertyTagTypeLong },
2640 { VT_I8, PropertyTagTypeSRational },
2641 { VT_UI8, PropertyTagTypeRational },
2642 { VT_R4, PropertyTagTypeFloat },
2643 { VT_R8, PropertyTagTypeDouble },
2644 { VT_LPSTR, PropertyTagTypeASCII },
2645 { VT_BLOB, PropertyTagTypeUndefined }
2647 UINT i;
2648 for (i = 0; i < sizeof(vt2type)/sizeof(vt2type[0]); i++)
2650 if (vt2type[i].vt == vt) return vt2type[i].type;
2652 FIXME("not supported variant type %u\n", vt);
2653 return 0;
2656 static GpStatus propvariant_to_item(PROPVARIANT *value, PropertyItem *item,
2657 UINT size, PROPID id)
2659 UINT item_size, item_type;
2661 item_size = propvariant_size(value);
2662 if (size != item_size + sizeof(PropertyItem)) return InvalidParameter;
2664 item_type = vt_to_itemtype(value->vt & ~VT_VECTOR);
2665 if (!item_type) return InvalidParameter;
2667 item->value = item + 1;
2669 switch (value->vt & ~VT_VECTOR)
2671 case VT_I1:
2672 case VT_UI1:
2673 if (!(value->vt & VT_VECTOR))
2674 *(BYTE *)item->value = value->u.bVal;
2675 else
2676 memcpy(item->value, value->u.caub.pElems, item_size);
2677 break;
2678 case VT_I2:
2679 case VT_UI2:
2680 if (!(value->vt & VT_VECTOR))
2681 *(USHORT *)item->value = value->u.uiVal;
2682 else
2683 memcpy(item->value, value->u.caui.pElems, item_size);
2684 break;
2685 case VT_I4:
2686 case VT_UI4:
2687 case VT_R4:
2688 if (!(value->vt & VT_VECTOR))
2689 *(ULONG *)item->value = value->u.ulVal;
2690 else
2691 memcpy(item->value, value->u.caul.pElems, item_size);
2692 break;
2693 case VT_I8:
2694 case VT_UI8:
2695 case VT_R8:
2696 if (!(value->vt & VT_VECTOR))
2697 *(ULONGLONG *)item->value = value->u.uhVal.QuadPart;
2698 else
2699 memcpy(item->value, value->u.cauh.pElems, item_size);
2700 break;
2701 case VT_LPSTR:
2702 memcpy(item->value, value->u.pszVal, item_size);
2703 break;
2704 case VT_BLOB:
2705 memcpy(item->value, value->u.blob.pBlobData, item_size);
2706 break;
2707 default:
2708 FIXME("not supported variant type %d\n", value->vt);
2709 return InvalidParameter;
2712 item->length = item_size;
2713 item->type = item_type;
2714 item->id = id;
2716 return Ok;
2719 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID propid, UINT size,
2720 PropertyItem *buffer)
2722 GpStatus stat;
2723 HRESULT hr;
2724 IWICMetadataReader *reader;
2725 PROPVARIANT id, value;
2727 TRACE("(%p,%#x,%u,%p)\n", image, propid, size, buffer);
2729 if (!image || !buffer) return InvalidParameter;
2731 if (image->type != ImageTypeBitmap)
2733 FIXME("Not implemented for type %d\n", image->type);
2734 return NotImplemented;
2737 if (((GpBitmap *)image)->prop_item)
2739 UINT i;
2741 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2743 if (propid == ((GpBitmap *)image)->prop_item[i].id)
2745 if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length)
2746 return InvalidParameter;
2748 *buffer = ((GpBitmap *)image)->prop_item[i];
2749 buffer->value = buffer + 1;
2750 memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length);
2751 return Ok;
2755 return PropertyNotFound;
2758 reader = ((GpBitmap *)image)->metadata_reader;
2759 if (!reader) return PropertyNotFound;
2761 id.vt = VT_UI2;
2762 id.u.uiVal = propid;
2763 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2764 if (FAILED(hr)) return PropertyNotFound;
2766 stat = propvariant_to_item(&value, buffer, size, propid);
2767 PropVariantClear(&value);
2769 return stat;
2772 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT *size, UINT *count)
2774 HRESULT hr;
2775 IWICMetadataReader *reader;
2776 IWICEnumMetadataItem *enumerator;
2777 UINT prop_count, prop_size, i;
2778 PROPVARIANT id, value;
2780 TRACE("(%p,%p,%p)\n", image, size, count);
2782 if (!image || !size || !count) return InvalidParameter;
2784 if (image->type != ImageTypeBitmap)
2786 FIXME("Not implemented for type %d\n", image->type);
2787 return NotImplemented;
2790 if (((GpBitmap *)image)->prop_item)
2792 *count = ((GpBitmap *)image)->prop_count;
2793 *size = 0;
2795 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2797 *size += sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2800 return Ok;
2803 reader = ((GpBitmap *)image)->metadata_reader;
2804 if (!reader) return PropertyNotFound;
2806 hr = IWICMetadataReader_GetCount(reader, &prop_count);
2807 if (FAILED(hr)) return hresult_to_status(hr);
2809 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2810 if (FAILED(hr)) return hresult_to_status(hr);
2812 IWICEnumMetadataItem_Reset(enumerator);
2814 prop_size = 0;
2816 PropVariantInit(&id);
2817 PropVariantInit(&value);
2819 for (i = 0; i < prop_count; i++)
2821 UINT items_returned, item_size;
2823 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2824 if (hr != S_OK) break;
2826 item_size = propvariant_size(&value);
2827 if (item_size) prop_size += sizeof(PropertyItem) + item_size;
2829 PropVariantClear(&id);
2830 PropVariantClear(&value);
2833 IWICEnumMetadataItem_Release(enumerator);
2835 if (hr != S_OK) return PropertyNotFound;
2837 *count = prop_count;
2838 *size = prop_size;
2839 return Ok;
2842 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
2843 UINT count, PropertyItem *buf)
2845 GpStatus status;
2846 HRESULT hr;
2847 IWICMetadataReader *reader;
2848 IWICEnumMetadataItem *enumerator;
2849 UINT prop_count, prop_size, i;
2850 PROPVARIANT id, value;
2851 char *item_value;
2853 TRACE("(%p,%u,%u,%p)\n", image, size, count, buf);
2855 if (!image || !buf) return InvalidParameter;
2857 if (image->type != ImageTypeBitmap)
2859 FIXME("Not implemented for type %d\n", image->type);
2860 return NotImplemented;
2863 status = GdipGetPropertySize(image, &prop_size, &prop_count);
2864 if (status != Ok) return status;
2866 if (prop_count != count || prop_size != size) return InvalidParameter;
2868 if (((GpBitmap *)image)->prop_item)
2870 memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size);
2872 item_value = (char *)(buf + prop_count);
2874 for (i = 0; i < prop_count; i++)
2876 buf[i].value = item_value;
2877 item_value += buf[i].length;
2880 return Ok;
2883 reader = ((GpBitmap *)image)->metadata_reader;
2884 if (!reader) return PropertyNotFound;
2886 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2887 if (FAILED(hr)) return hresult_to_status(hr);
2889 IWICEnumMetadataItem_Reset(enumerator);
2891 item_value = (char *)(buf + prop_count);
2893 PropVariantInit(&id);
2894 PropVariantInit(&value);
2896 for (i = 0; i < prop_count; i++)
2898 PropertyItem *item;
2899 UINT items_returned, item_size;
2901 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2902 if (hr != S_OK) break;
2904 if (id.vt != VT_UI2)
2906 FIXME("not supported propvariant type for id: %u\n", id.vt);
2907 continue;
2910 item_size = propvariant_size(&value);
2911 if (item_size)
2913 item = HeapAlloc(GetProcessHeap(), 0, item_size + sizeof(*item));
2915 propvariant_to_item(&value, item, item_size + sizeof(*item), id.u.uiVal);
2916 buf[i].id = item->id;
2917 buf[i].type = item->type;
2918 buf[i].length = item_size;
2919 buf[i].value = item_value;
2920 memcpy(item_value, item->value, item_size);
2921 item_value += item_size;
2923 HeapFree(GetProcessHeap(), 0, item);
2926 PropVariantClear(&id);
2927 PropVariantClear(&value);
2930 IWICEnumMetadataItem_Release(enumerator);
2932 if (hr != S_OK) return PropertyNotFound;
2934 return Ok;
2937 struct image_format_dimension
2939 const GUID *format;
2940 const GUID *dimension;
2943 static const struct image_format_dimension image_format_dimensions[] =
2945 {&ImageFormatGIF, &FrameDimensionTime},
2946 {&ImageFormatIcon, &FrameDimensionResolution},
2947 {NULL}
2950 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
2951 GDIPCONST GUID* dimensionID, UINT* count)
2953 TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
2955 if(!image || !count)
2956 return InvalidParameter;
2958 if (!dimensionID ||
2959 IsEqualGUID(dimensionID, &image->format) ||
2960 IsEqualGUID(dimensionID, &FrameDimensionPage) ||
2961 IsEqualGUID(dimensionID, &FrameDimensionTime))
2963 *count = image->frame_count;
2964 return Ok;
2967 return InvalidParameter;
2970 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
2971 UINT* count)
2973 TRACE("(%p, %p)\n", image, count);
2975 /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
2977 if(!image || !count)
2978 return InvalidParameter;
2980 *count = 1;
2982 return Ok;
2985 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
2986 GUID* dimensionIDs, UINT count)
2988 int i;
2989 const GUID *result=NULL;
2991 TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
2993 if(!image || !dimensionIDs || count != 1)
2994 return InvalidParameter;
2996 for (i=0; image_format_dimensions[i].format; i++)
2998 if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
3000 result = image_format_dimensions[i].dimension;
3001 break;
3005 if (!result)
3006 result = &FrameDimensionPage;
3008 memcpy(dimensionIDs, result, sizeof(GUID));
3010 return Ok;
3013 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
3014 GpImage **image)
3016 GpStatus stat;
3017 IStream *stream;
3019 TRACE("(%s) %p\n", debugstr_w(filename), image);
3021 if (!filename || !image)
3022 return InvalidParameter;
3024 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
3026 if (stat != Ok)
3027 return stat;
3029 stat = GdipLoadImageFromStream(stream, image);
3031 IStream_Release(stream);
3033 return stat;
3036 /* FIXME: no icm handling */
3037 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
3039 TRACE("(%s) %p\n", debugstr_w(filename), image);
3041 return GdipLoadImageFromFile(filename, image);
3044 static void add_property(GpBitmap *bitmap, PropertyItem *item)
3046 UINT prop_size, prop_count;
3047 PropertyItem *prop_item;
3049 if (bitmap->prop_item == NULL)
3051 prop_size = prop_count = 0;
3052 prop_item = GdipAlloc(item->length + sizeof(PropertyItem));
3053 if (!prop_item) return;
3055 else
3057 UINT i;
3058 char *item_value;
3060 GdipGetPropertySize((GpImage *)bitmap, &prop_size, &prop_count);
3062 prop_item = GdipAlloc(prop_size + item->length + sizeof(PropertyItem));
3063 if (!prop_item) return;
3064 memcpy(prop_item, bitmap->prop_item, sizeof(PropertyItem) * bitmap->prop_count);
3065 prop_size -= sizeof(PropertyItem) * bitmap->prop_count;
3066 memcpy(prop_item + prop_count + 1, bitmap->prop_item + prop_count, prop_size);
3068 item_value = (char *)(prop_item + prop_count + 1);
3070 for (i = 0; i < prop_count; i++)
3072 prop_item[i].value = item_value;
3073 item_value += prop_item[i].length;
3077 prop_item[prop_count].id = item->id;
3078 prop_item[prop_count].type = item->type;
3079 prop_item[prop_count].length = item->length;
3080 prop_item[prop_count].value = (char *)(prop_item + prop_count + 1) + prop_size;
3081 memcpy(prop_item[prop_count].value, item->value, item->length);
3083 GdipFree(bitmap->prop_item);
3084 bitmap->prop_item = prop_item;
3085 bitmap->prop_count++;
3088 static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3090 HRESULT hr;
3091 GUID format;
3092 PROPVARIANT id, value;
3093 BOOL ret = FALSE;
3095 IWICMetadataReader_GetMetadataFormat(reader, &format);
3096 if (!IsEqualGUID(&format, guid)) return FALSE;
3098 PropVariantInit(&id);
3099 PropVariantInit(&value);
3101 id.vt = VT_LPWSTR;
3102 id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3103 if (!id.u.pwszVal) return FALSE;
3104 lstrcpyW(id.u.pwszVal, prop_name);
3105 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3106 if (hr == S_OK && value.vt == VT_BOOL)
3107 ret = value.u.boolVal;
3109 PropVariantClear(&id);
3110 PropVariantClear(&value);
3112 return ret;
3115 static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3117 HRESULT hr;
3118 GUID format;
3119 PROPVARIANT id, value;
3120 PropertyItem *item = NULL;
3122 IWICMetadataReader_GetMetadataFormat(reader, &format);
3123 if (!IsEqualGUID(&format, guid)) return NULL;
3125 PropVariantInit(&id);
3126 PropVariantInit(&value);
3128 id.vt = VT_LPWSTR;
3129 id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3130 if (!id.u.pwszVal) return NULL;
3131 lstrcpyW(id.u.pwszVal, prop_name);
3132 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3133 if (hr == S_OK)
3135 UINT item_size = propvariant_size(&value);
3136 if (item_size)
3138 item_size += sizeof(*item);
3139 item = GdipAlloc(item_size);
3140 if (propvariant_to_item(&value, item, item_size, 0) != Ok)
3142 GdipFree(item);
3143 item = NULL;
3148 PropVariantClear(&id);
3149 PropVariantClear(&value);
3151 return item;
3154 static PropertyItem *get_gif_comment(IWICMetadataReader *reader)
3156 static const WCHAR textentryW[] = { 'T','e','x','t','E','n','t','r','y',0 };
3157 PropertyItem *comment;
3159 comment = get_property(reader, &GUID_MetadataFormatGifComment, textentryW);
3160 if (comment)
3161 comment->id = PropertyTagExifUserComment;
3163 return comment;
3166 static PropertyItem *get_gif_loopcount(IWICMetadataReader *reader)
3168 static const WCHAR applicationW[] = { 'A','p','p','l','i','c','a','t','i','o','n',0 };
3169 static const WCHAR dataW[] = { 'D','a','t','a',0 };
3170 PropertyItem *appext = NULL, *appdata = NULL, *loop = NULL;
3172 appext = get_property(reader, &GUID_MetadataFormatAPE, applicationW);
3173 if (appext)
3175 if (appext->type == PropertyTagTypeByte && appext->length == 11 &&
3176 (!memcmp(appext->value, "NETSCAPE2.0", 11) || !memcmp(appext->value, "ANIMEXTS1.0", 11)))
3178 appdata = get_property(reader, &GUID_MetadataFormatAPE, dataW);
3179 if (appdata)
3181 if (appdata->type == PropertyTagTypeByte && appdata->length == 4)
3183 BYTE *data = appdata->value;
3184 if (data[0] == 3 && data[1] == 1)
3186 loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
3187 if (loop)
3189 loop->type = PropertyTagTypeShort;
3190 loop->id = PropertyTagLoopCount;
3191 loop->length = sizeof(SHORT);
3192 loop->value = loop + 1;
3193 *(SHORT *)loop->value = data[2] | (data[3] << 8);
3201 GdipFree(appext);
3202 GdipFree(appdata);
3204 return loop;
3207 static PropertyItem *get_gif_background(IWICMetadataReader *reader)
3209 static const WCHAR backgroundW[] = { 'B','a','c','k','g','r','o','u','n','d','C','o','l','o','r','I','n','d','e','x',0 };
3210 PropertyItem *background;
3212 background = get_property(reader, &GUID_MetadataFormatLSD, backgroundW);
3213 if (background)
3214 background->id = PropertyTagIndexBackground;
3216 return background;
3219 static PropertyItem *get_gif_palette(IWICBitmapDecoder *decoder, IWICMetadataReader *reader)
3221 static const WCHAR global_flagW[] = { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 };
3222 HRESULT hr;
3223 IWICImagingFactory *factory;
3224 IWICPalette *palette;
3225 UINT count = 0;
3226 WICColor colors[256];
3228 if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW))
3229 return NULL;
3231 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
3232 &IID_IWICImagingFactory, (void **)&factory);
3233 if (hr != S_OK) return NULL;
3235 hr = IWICImagingFactory_CreatePalette(factory, &palette);
3236 if (hr == S_OK)
3238 hr = IWICBitmapDecoder_CopyPalette(decoder, palette);
3239 if (hr == S_OK)
3240 IWICPalette_GetColors(palette, 256, colors, &count);
3242 IWICPalette_Release(palette);
3245 IWICImagingFactory_Release(factory);
3247 if (count)
3249 PropertyItem *pal;
3250 UINT i;
3251 BYTE *rgb;
3253 pal = GdipAlloc(sizeof(*pal) + count * 3);
3254 if (!pal) return NULL;
3255 pal->type = PropertyTagTypeByte;
3256 pal->id = PropertyTagGlobalPalette;
3257 pal->value = pal + 1;
3258 pal->length = count * 3;
3260 rgb = pal->value;
3262 for (i = 0; i < count; i++)
3264 rgb[i*3] = (colors[i] >> 16) & 0xff;
3265 rgb[i*3 + 1] = (colors[i] >> 8) & 0xff;
3266 rgb[i*3 + 2] = colors[i] & 0xff;
3269 return pal;
3272 return NULL;
3275 static PropertyItem *get_gif_transparent_idx(IWICMetadataReader *reader)
3277 static const WCHAR transparency_flagW[] = { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 };
3278 static const WCHAR colorW[] = { 'T','r','a','n','s','p','a','r','e','n','t','C','o','l','o','r','I','n','d','e','x',0 };
3279 PropertyItem *index = NULL;
3281 if (get_bool_property(reader, &GUID_MetadataFormatGCE, transparency_flagW))
3283 index = get_property(reader, &GUID_MetadataFormatGCE, colorW);
3284 if (index)
3285 index->id = PropertyTagIndexTransparent;
3287 return index;
3290 static LONG get_gif_frame_delay(IWICBitmapFrameDecode *frame)
3292 static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
3293 HRESULT hr;
3294 IWICMetadataBlockReader *block_reader;
3295 IWICMetadataReader *reader;
3296 UINT block_count, i;
3297 PropertyItem *delay;
3298 LONG value = 0;
3300 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3301 if (hr == S_OK)
3303 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3304 if (hr == S_OK)
3306 for (i = 0; i < block_count; i++)
3308 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3309 if (hr == S_OK)
3311 delay = get_property(reader, &GUID_MetadataFormatGCE, delayW);
3312 if (delay)
3314 if (delay->type == PropertyTagTypeShort && delay->length == 2)
3315 value = *(SHORT *)delay->value;
3317 GdipFree(delay);
3319 IWICMetadataReader_Release(reader);
3323 IWICMetadataBlockReader_Release(block_reader);
3326 return value;
3329 static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
3331 HRESULT hr;
3332 IWICBitmapFrameDecode *frame;
3333 IWICMetadataBlockReader *block_reader;
3334 IWICMetadataReader *reader;
3335 UINT frame_count, block_count, i;
3336 PropertyItem *delay = NULL, *comment = NULL, *background = NULL;
3337 PropertyItem *transparent_idx = NULL, *loop = NULL, *palette = NULL;
3339 IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3340 if (frame_count > 1)
3342 delay = GdipAlloc(sizeof(*delay) + frame_count * sizeof(LONG));
3343 if (delay)
3345 LONG *value;
3347 delay->type = PropertyTagTypeLong;
3348 delay->id = PropertyTagFrameDelay;
3349 delay->length = frame_count * sizeof(LONG);
3350 delay->value = delay + 1;
3352 value = delay->value;
3354 for (i = 0; i < frame_count; i++)
3356 hr = IWICBitmapDecoder_GetFrame(decoder, i, &frame);
3357 if (hr == S_OK)
3359 value[i] = get_gif_frame_delay(frame);
3360 IWICBitmapFrameDecode_Release(frame);
3362 else value[i] = 0;
3367 hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3368 if (hr == S_OK)
3370 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3371 if (hr == S_OK)
3373 for (i = 0; i < block_count; i++)
3375 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3376 if (hr == S_OK)
3378 if (!comment)
3379 comment = get_gif_comment(reader);
3381 if (frame_count > 1 && !loop)
3382 loop = get_gif_loopcount(reader);
3384 if (!background)
3385 background = get_gif_background(reader);
3387 if (!palette)
3388 palette = get_gif_palette(decoder, reader);
3390 IWICMetadataReader_Release(reader);
3394 IWICMetadataBlockReader_Release(block_reader);
3397 if (frame_count > 1 && !loop)
3399 loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
3400 if (loop)
3402 loop->type = PropertyTagTypeShort;
3403 loop->id = PropertyTagLoopCount;
3404 loop->length = sizeof(SHORT);
3405 loop->value = loop + 1;
3406 *(SHORT *)loop->value = 1;
3410 if (delay) add_property(bitmap, delay);
3411 if (comment) add_property(bitmap, comment);
3412 if (loop) add_property(bitmap, loop);
3413 if (palette) add_property(bitmap, palette);
3414 if (background) add_property(bitmap, background);
3416 GdipFree(delay);
3417 GdipFree(comment);
3418 GdipFree(loop);
3419 GdipFree(palette);
3420 GdipFree(background);
3422 /* Win7 gdiplus always returns transparent color index from frame 0 */
3423 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
3424 if (hr != S_OK) return;
3426 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3427 if (hr == S_OK)
3429 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3430 if (hr == S_OK)
3432 for (i = 0; i < block_count; i++)
3434 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3435 if (hr == S_OK)
3437 if (!transparent_idx)
3438 transparent_idx = get_gif_transparent_idx(reader);
3440 IWICMetadataReader_Release(reader);
3444 IWICMetadataBlockReader_Release(block_reader);
3447 if (transparent_idx) add_property(bitmap, transparent_idx);
3448 GdipFree(transparent_idx);
3450 IWICBitmapFrameDecode_Release(frame);
3453 typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame);
3455 static GpStatus decode_image_wic(IStream *stream, GDIPCONST CLSID *clsid,
3456 UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
3458 GpStatus status=Ok;
3459 GpBitmap *bitmap;
3460 HRESULT hr;
3461 IWICBitmapDecoder *decoder;
3462 IWICBitmapFrameDecode *frame;
3463 IWICBitmapSource *source=NULL;
3464 IWICMetadataBlockReader *block_reader;
3465 WICPixelFormatGUID wic_format;
3466 PixelFormat gdip_format=0;
3467 ColorPalette *palette = NULL;
3468 WICBitmapPaletteType palette_type = WICBitmapPaletteTypeFixedHalftone256;
3469 int i;
3470 UINT width, height, frame_count;
3471 BitmapData lockeddata;
3472 WICRect wrc;
3473 HRESULT initresult;
3475 TRACE("%p,%s,%u,%p\n", stream, wine_dbgstr_guid(clsid), active_frame, image);
3477 initresult = CoInitialize(NULL);
3479 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
3480 &IID_IWICBitmapDecoder, (void**)&decoder);
3481 if (FAILED(hr)) goto end;
3483 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
3484 if (SUCCEEDED(hr))
3486 IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3487 hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
3490 if (SUCCEEDED(hr)) /* got frame */
3492 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
3494 if (SUCCEEDED(hr))
3496 IWICBitmapSource *bmp_source;
3497 IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICBitmapSource, (void **)&bmp_source);
3499 for (i=0; pixel_formats[i].wic_format; i++)
3501 if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format))
3503 source = bmp_source;
3504 gdip_format = pixel_formats[i].gdip_format;
3505 palette_type = pixel_formats[i].palette_type;
3506 break;
3509 if (!source)
3511 /* unknown format; fall back on 32bppARGB */
3512 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bmp_source, &source);
3513 gdip_format = PixelFormat32bppARGB;
3514 IWICBitmapSource_Release(bmp_source);
3516 TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format);
3519 if (SUCCEEDED(hr)) /* got source */
3521 hr = IWICBitmapSource_GetSize(source, &width, &height);
3523 if (SUCCEEDED(hr))
3524 status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
3525 NULL, &bitmap);
3527 if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
3529 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
3530 gdip_format, &lockeddata);
3531 if (status == Ok) /* locked bitmap */
3533 wrc.X = 0;
3534 wrc.Width = width;
3535 wrc.Height = 1;
3536 for (i=0; i<height; i++)
3538 wrc.Y = i;
3539 hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
3540 abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
3541 if (FAILED(hr)) break;
3544 GdipBitmapUnlockBits(bitmap, &lockeddata);
3547 if (SUCCEEDED(hr) && status == Ok)
3548 *image = (GpImage*)bitmap;
3549 else
3551 *image = NULL;
3552 GdipDisposeImage((GpImage*)bitmap);
3555 if (SUCCEEDED(hr) && status == Ok)
3557 double dpix, dpiy;
3558 hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy);
3559 if (SUCCEEDED(hr))
3561 bitmap->image.xres = dpix;
3562 bitmap->image.yres = dpiy;
3564 hr = S_OK;
3568 IWICBitmapSource_Release(source);
3571 if (SUCCEEDED(hr)) {
3572 bitmap->metadata_reader = NULL;
3574 if (metadata_reader)
3575 metadata_reader(bitmap, decoder, active_frame);
3576 else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK)
3578 UINT block_count = 0;
3579 if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count)
3580 IWICMetadataBlockReader_GetReaderByIndex(block_reader, 0, &bitmap->metadata_reader);
3581 IWICMetadataBlockReader_Release(block_reader);
3584 palette = get_palette(frame, palette_type);
3585 IWICBitmapFrameDecode_Release(frame);
3589 IWICBitmapDecoder_Release(decoder);
3591 end:
3592 if (SUCCEEDED(initresult)) CoUninitialize();
3594 if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
3596 if (status == Ok)
3598 /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
3599 bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB;
3600 bitmap->image.frame_count = frame_count;
3601 bitmap->image.current_frame = active_frame;
3602 bitmap->image.stream = stream;
3603 if (palette)
3605 GdipFree(bitmap->image.palette);
3606 bitmap->image.palette = palette;
3608 else
3610 if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite))
3611 bitmap->image.palette->Flags = 0;
3613 /* Pin the source stream */
3614 IStream_AddRef(stream);
3615 TRACE("=> %p\n", *image);
3618 return status;
3621 static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3623 return decode_image_wic(stream, &CLSID_WICIcoDecoder, active_frame, NULL, image);
3626 static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3628 GpStatus status;
3629 GpBitmap* bitmap;
3631 status = decode_image_wic(stream, &CLSID_WICBmpDecoder, active_frame, NULL, image);
3633 bitmap = (GpBitmap*)*image;
3635 if (status == Ok && bitmap->format == PixelFormat32bppARGB)
3637 /* WIC supports bmp files with alpha, but gdiplus does not */
3638 bitmap->format = PixelFormat32bppRGB;
3641 return status;
3644 static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3646 return decode_image_wic(stream, &CLSID_WICJpegDecoder, active_frame, NULL, image);
3649 static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3651 return decode_image_wic(stream, &CLSID_WICPngDecoder, active_frame, NULL, image);
3654 static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3656 return decode_image_wic(stream, &CLSID_WICGifDecoder, active_frame, gif_metadata_reader, image);
3659 static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3661 return decode_image_wic(stream, &CLSID_WICTiffDecoder, active_frame, NULL, image);
3664 static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3666 IPicture *pic;
3668 TRACE("%p %p\n", stream, image);
3670 if(!stream || !image)
3671 return InvalidParameter;
3673 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
3674 (LPVOID*) &pic) != S_OK){
3675 TRACE("Could not load picture\n");
3676 return GenericError;
3679 /* FIXME: missing initialization code */
3680 *image = GdipAlloc(sizeof(GpMetafile));
3681 if(!*image) return OutOfMemory;
3682 (*image)->type = ImageTypeMetafile;
3683 (*image)->stream = NULL;
3684 (*image)->picture = pic;
3685 (*image)->flags = ImageFlagsNone;
3686 (*image)->frame_count = 1;
3687 (*image)->current_frame = 0;
3688 (*image)->palette = NULL;
3690 TRACE("<-- %p\n", *image);
3692 return Ok;
3695 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
3696 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
3698 typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, UINT active_frame, GpImage **image);
3700 typedef struct image_codec {
3701 ImageCodecInfo info;
3702 encode_image_func encode_func;
3703 decode_image_func decode_func;
3704 } image_codec;
3706 typedef enum {
3707 BMP,
3708 JPEG,
3709 GIF,
3710 TIFF,
3711 EMF,
3712 WMF,
3713 PNG,
3714 ICO,
3715 NUM_CODECS
3716 } ImageFormat;
3718 static const struct image_codec codecs[NUM_CODECS];
3720 static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
3722 BYTE signature[8];
3723 const BYTE *pattern, *mask;
3724 LARGE_INTEGER seek;
3725 HRESULT hr;
3726 UINT bytesread;
3727 int i;
3728 DWORD j, sig;
3730 /* seek to the start of the stream */
3731 seek.QuadPart = 0;
3732 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
3733 if (FAILED(hr)) return hresult_to_status(hr);
3735 /* read the first 8 bytes */
3736 /* FIXME: This assumes all codecs have signatures <= 8 bytes in length */
3737 hr = IStream_Read(stream, signature, 8, &bytesread);
3738 if (FAILED(hr)) return hresult_to_status(hr);
3739 if (hr == S_FALSE || bytesread == 0) return GenericError;
3741 for (i = 0; i < NUM_CODECS; i++) {
3742 if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
3743 bytesread >= codecs[i].info.SigSize)
3745 for (sig=0; sig<codecs[i].info.SigCount; sig++)
3747 pattern = &codecs[i].info.SigPattern[codecs[i].info.SigSize*sig];
3748 mask = &codecs[i].info.SigMask[codecs[i].info.SigSize*sig];
3749 for (j=0; j<codecs[i].info.SigSize; j++)
3750 if ((signature[j] & mask[j]) != pattern[j])
3751 break;
3752 if (j == codecs[i].info.SigSize)
3754 *result = &codecs[i];
3755 return Ok;
3761 TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
3762 signature[0],signature[1],signature[2],signature[3],
3763 signature[4],signature[5],signature[6],signature[7]);
3765 return GenericError;
3768 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *dimensionID,
3769 UINT frame)
3771 GpStatus stat;
3772 LARGE_INTEGER seek;
3773 HRESULT hr;
3774 const struct image_codec *codec = NULL;
3775 GpImage *new_image;
3777 TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
3779 if (!image || !dimensionID)
3780 return InvalidParameter;
3782 if (frame >= image->frame_count)
3784 WARN("requested frame %u, but image has only %u\n", frame, image->frame_count);
3785 return InvalidParameter;
3788 if (image->type != ImageTypeBitmap && image->type != ImageTypeMetafile)
3790 WARN("invalid image type %d\n", image->type);
3791 return InvalidParameter;
3794 if (image->current_frame == frame)
3795 return Ok;
3797 if (!image->stream)
3799 TRACE("image doesn't have an associated stream\n");
3800 return Ok;
3803 /* choose an appropriate image decoder */
3804 stat = get_decoder_info(image->stream, &codec);
3805 if (stat != Ok)
3807 WARN("can't find decoder info\n");
3808 return stat;
3811 /* seek to the start of the stream */
3812 seek.QuadPart = 0;
3813 hr = IStream_Seek(image->stream, seek, STREAM_SEEK_SET, NULL);
3814 if (FAILED(hr))
3815 return hresult_to_status(hr);
3817 /* call on the image decoder to do the real work */
3818 stat = codec->decode_func(image->stream, &codec->info.Clsid, frame, &new_image);
3820 if (stat == Ok)
3822 memcpy(&new_image->format, &codec->info.FormatID, sizeof(GUID));
3823 free_image_data(image);
3824 if (image->type == ImageTypeBitmap)
3825 *(GpBitmap *)image = *(GpBitmap *)new_image;
3826 else if (image->type == ImageTypeMetafile)
3827 *(GpMetafile *)image = *(GpMetafile *)new_image;
3828 new_image->type = ~0;
3829 GdipFree(new_image);
3830 return Ok;
3833 return stat;
3836 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
3838 GpStatus stat;
3839 LARGE_INTEGER seek;
3840 HRESULT hr;
3841 const struct image_codec *codec=NULL;
3843 /* choose an appropriate image decoder */
3844 stat = get_decoder_info(stream, &codec);
3845 if (stat != Ok) return stat;
3847 /* seek to the start of the stream */
3848 seek.QuadPart = 0;
3849 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
3850 if (FAILED(hr)) return hresult_to_status(hr);
3852 /* call on the image decoder to do the real work */
3853 stat = codec->decode_func(stream, &codec->info.Clsid, 0, image);
3855 /* take note of the original data format */
3856 if (stat == Ok)
3858 memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
3859 return Ok;
3862 return stat;
3865 /* FIXME: no ICM */
3866 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
3868 TRACE("%p %p\n", stream, image);
3870 return GdipLoadImageFromStream(stream, image);
3873 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
3875 static int calls;
3877 TRACE("(%p,%u)\n", image, propId);
3879 if(!image)
3880 return InvalidParameter;
3882 if(!(calls++))
3883 FIXME("not implemented\n");
3885 return NotImplemented;
3888 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
3890 static int calls;
3892 if (!image || !item) return InvalidParameter;
3894 TRACE("(%p,%p:%#x,%u,%u,%p)\n", image, item, item->id, item->type, item->length, item->value);
3896 if(!(calls++))
3897 FIXME("not implemented\n");
3899 return Ok;
3902 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
3903 GDIPCONST CLSID *clsidEncoder,
3904 GDIPCONST EncoderParameters *encoderParams)
3906 GpStatus stat;
3907 IStream *stream;
3909 TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
3911 if (!image || !filename|| !clsidEncoder)
3912 return InvalidParameter;
3914 stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
3915 if (stat != Ok)
3916 return GenericError;
3918 stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
3920 IStream_Release(stream);
3921 return stat;
3924 /*************************************************************************
3925 * Encoding functions -
3926 * These functions encode an image in different image file formats.
3928 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
3929 #define BITMAP_FORMAT_JPEG 0xd8ff
3930 #define BITMAP_FORMAT_GIF 0x4947
3931 #define BITMAP_FORMAT_PNG 0x5089
3932 #define BITMAP_FORMAT_APM 0xcdd7
3934 static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
3935 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
3937 GpStatus stat;
3938 GpBitmap *bitmap;
3939 IWICBitmapEncoder *encoder;
3940 IWICBitmapFrameEncode *frameencode;
3941 IPropertyBag2 *encoderoptions;
3942 HRESULT hr;
3943 UINT width, height;
3944 PixelFormat gdipformat=0;
3945 const WICPixelFormatGUID *desired_wicformat;
3946 WICPixelFormatGUID wicformat;
3947 GpRect rc;
3948 BitmapData lockeddata;
3949 HRESULT initresult;
3950 UINT i;
3952 if (image->type != ImageTypeBitmap)
3953 return GenericError;
3955 bitmap = (GpBitmap*)image;
3957 GdipGetImageWidth(image, &width);
3958 GdipGetImageHeight(image, &height);
3960 rc.X = 0;
3961 rc.Y = 0;
3962 rc.Width = width;
3963 rc.Height = height;
3965 initresult = CoInitialize(NULL);
3967 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
3968 &IID_IWICBitmapEncoder, (void**)&encoder);
3969 if (FAILED(hr))
3971 if (SUCCEEDED(initresult)) CoUninitialize();
3972 return hresult_to_status(hr);
3975 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
3977 if (SUCCEEDED(hr))
3979 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
3982 if (SUCCEEDED(hr)) /* created frame */
3984 hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
3986 if (SUCCEEDED(hr))
3987 hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
3989 if (SUCCEEDED(hr))
3990 hr = IWICBitmapFrameEncode_SetResolution(frameencode, image->xres, image->yres);
3992 if (SUCCEEDED(hr))
3994 for (i=0; pixel_formats[i].wic_format; i++)
3996 if (pixel_formats[i].gdip_format == bitmap->format)
3998 desired_wicformat = pixel_formats[i].wic_format;
3999 gdipformat = bitmap->format;
4000 break;
4003 if (!gdipformat)
4005 desired_wicformat = &GUID_WICPixelFormat32bppBGRA;
4006 gdipformat = PixelFormat32bppARGB;
4009 memcpy(&wicformat, desired_wicformat, sizeof(GUID));
4010 hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
4013 if (SUCCEEDED(hr) && !IsEqualGUID(desired_wicformat, &wicformat))
4015 /* Encoder doesn't support this bitmap's format. */
4016 gdipformat = 0;
4017 for (i=0; pixel_formats[i].wic_format; i++)
4019 if (IsEqualGUID(&wicformat, pixel_formats[i].wic_format))
4021 gdipformat = pixel_formats[i].gdip_format;
4022 break;
4025 if (!gdipformat)
4027 ERR("Cannot support encoder format %s\n", debugstr_guid(&wicformat));
4028 hr = E_FAIL;
4032 if (SUCCEEDED(hr))
4034 stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
4035 &lockeddata);
4037 if (stat == Ok)
4039 UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
4040 BYTE *row;
4042 /* write one row at a time in case stride is negative */
4043 row = lockeddata.Scan0;
4044 for (i=0; i<lockeddata.Height; i++)
4046 hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
4047 if (FAILED(hr)) break;
4048 row += lockeddata.Stride;
4051 GdipBitmapUnlockBits(bitmap, &lockeddata);
4053 else
4054 hr = E_FAIL;
4057 if (SUCCEEDED(hr))
4058 hr = IWICBitmapFrameEncode_Commit(frameencode);
4060 IWICBitmapFrameEncode_Release(frameencode);
4061 IPropertyBag2_Release(encoderoptions);
4064 if (SUCCEEDED(hr))
4065 hr = IWICBitmapEncoder_Commit(encoder);
4067 IWICBitmapEncoder_Release(encoder);
4069 if (SUCCEEDED(initresult)) CoUninitialize();
4071 return hresult_to_status(hr);
4074 static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
4075 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4077 return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
4080 static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
4081 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4083 return encode_image_WIC(image, stream, &CLSID_WICTiffEncoder, params);
4086 static GpStatus encode_image_png(GpImage *image, IStream* stream,
4087 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4089 return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params);
4092 static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
4093 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4095 return encode_image_WIC(image, stream, &CLSID_WICJpegEncoder, params);
4098 /*****************************************************************************
4099 * GdipSaveImageToStream [GDIPLUS.@]
4101 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
4102 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4104 GpStatus stat;
4105 encode_image_func encode_image;
4106 int i;
4108 TRACE("%p %p %p %p\n", image, stream, clsid, params);
4110 if(!image || !stream)
4111 return InvalidParameter;
4113 /* select correct encoder */
4114 encode_image = NULL;
4115 for (i = 0; i < NUM_CODECS; i++) {
4116 if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
4117 IsEqualCLSID(clsid, &codecs[i].info.Clsid))
4118 encode_image = codecs[i].encode_func;
4120 if (encode_image == NULL)
4121 return UnknownImageFormat;
4123 stat = encode_image(image, stream, clsid, params);
4125 return stat;
4128 /*****************************************************************************
4129 * GdipSaveAdd [GDIPLUS.@]
4131 GpStatus WINGDIPAPI GdipSaveAdd(GpImage *image, GDIPCONST EncoderParameters *params)
4133 FIXME("(%p,%p): stub\n", image, params);
4134 return Ok;
4137 /*****************************************************************************
4138 * GdipGetImagePalette [GDIPLUS.@]
4140 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
4142 INT count;
4144 TRACE("(%p,%p,%i)\n", image, palette, size);
4146 if (!image || !palette)
4147 return InvalidParameter;
4149 count = image->palette ? image->palette->Count : 0;
4151 if (size < (sizeof(UINT)*2+sizeof(ARGB)*count))
4153 TRACE("<-- InsufficientBuffer\n");
4154 return InsufficientBuffer;
4157 if (image->palette)
4159 palette->Flags = image->palette->Flags;
4160 palette->Count = image->palette->Count;
4161 memcpy(palette->Entries, image->palette->Entries, sizeof(ARGB)*image->palette->Count);
4163 else
4165 palette->Flags = 0;
4166 palette->Count = 0;
4168 return Ok;
4171 /*****************************************************************************
4172 * GdipSetImagePalette [GDIPLUS.@]
4174 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
4175 GDIPCONST ColorPalette *palette)
4177 ColorPalette *new_palette;
4179 TRACE("(%p,%p)\n", image, palette);
4181 if(!image || !palette || palette->Count > 256)
4182 return InvalidParameter;
4184 new_palette = GdipAlloc(2 * sizeof(UINT) + palette->Count * sizeof(ARGB));
4185 if (!new_palette) return OutOfMemory;
4187 GdipFree(image->palette);
4188 image->palette = new_palette;
4189 image->palette->Flags = palette->Flags;
4190 image->palette->Count = palette->Count;
4191 memcpy(image->palette->Entries, palette->Entries, sizeof(ARGB)*palette->Count);
4193 return Ok;
4196 /*************************************************************************
4197 * Encoders -
4198 * Structures that represent which formats we support for encoding.
4201 /* ImageCodecInfo creation routines taken from libgdiplus */
4202 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */
4203 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
4204 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
4205 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
4206 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
4207 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
4209 static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
4210 static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
4211 static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
4212 static const WCHAR jpeg_format[] = {'J','P','E','G',0};
4213 static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
4214 static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
4216 static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
4217 static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
4218 static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
4219 static const WCHAR gif_format[] = {'G','I','F',0};
4220 static const BYTE gif_sig_pattern[12] = "GIF87aGIF89a";
4221 static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4223 static const WCHAR tiff_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'T','I','F','F', 0};
4224 static const WCHAR tiff_extension[] = {'*','.','T','I','F','F',';','*','.','T','I','F',0};
4225 static const WCHAR tiff_mimetype[] = {'i','m','a','g','e','/','t','i','f','f', 0};
4226 static const WCHAR tiff_format[] = {'T','I','F','F',0};
4227 static const BYTE tiff_sig_pattern[] = {0x49,0x49,42,0,0x4d,0x4d,0,42};
4228 static const BYTE tiff_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4230 static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
4231 static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
4232 static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
4233 static const WCHAR emf_format[] = {'E','M','F',0};
4234 static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
4235 static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
4237 static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
4238 static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
4239 static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
4240 static const WCHAR wmf_format[] = {'W','M','F',0};
4241 static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
4242 static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
4244 static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
4245 static const WCHAR png_extension[] = {'*','.','P','N','G',0};
4246 static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
4247 static const WCHAR png_format[] = {'P','N','G',0};
4248 static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
4249 static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4251 static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
4252 static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
4253 static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
4254 static const WCHAR ico_format[] = {'I','C','O',0};
4255 static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
4256 static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
4258 static const struct image_codec codecs[NUM_CODECS] = {
4260 { /* BMP */
4261 /* Clsid */ { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4262 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4263 /* CodecName */ bmp_codecname,
4264 /* DllName */ NULL,
4265 /* FormatDescription */ bmp_format,
4266 /* FilenameExtension */ bmp_extension,
4267 /* MimeType */ bmp_mimetype,
4268 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4269 /* Version */ 1,
4270 /* SigCount */ 1,
4271 /* SigSize */ 2,
4272 /* SigPattern */ bmp_sig_pattern,
4273 /* SigMask */ bmp_sig_mask,
4275 encode_image_BMP,
4276 decode_image_bmp
4279 { /* JPEG */
4280 /* Clsid */ { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4281 /* FormatID */ { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4282 /* CodecName */ jpeg_codecname,
4283 /* DllName */ NULL,
4284 /* FormatDescription */ jpeg_format,
4285 /* FilenameExtension */ jpeg_extension,
4286 /* MimeType */ jpeg_mimetype,
4287 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4288 /* Version */ 1,
4289 /* SigCount */ 1,
4290 /* SigSize */ 2,
4291 /* SigPattern */ jpeg_sig_pattern,
4292 /* SigMask */ jpeg_sig_mask,
4294 encode_image_jpeg,
4295 decode_image_jpeg
4298 { /* GIF */
4299 /* Clsid */ { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4300 /* FormatID */ { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4301 /* CodecName */ gif_codecname,
4302 /* DllName */ NULL,
4303 /* FormatDescription */ gif_format,
4304 /* FilenameExtension */ gif_extension,
4305 /* MimeType */ gif_mimetype,
4306 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4307 /* Version */ 1,
4308 /* SigCount */ 2,
4309 /* SigSize */ 6,
4310 /* SigPattern */ gif_sig_pattern,
4311 /* SigMask */ gif_sig_mask,
4313 NULL,
4314 decode_image_gif
4317 { /* TIFF */
4318 /* Clsid */ { 0x557cf405, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4319 /* FormatID */ { 0xb96b3cb1U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4320 /* CodecName */ tiff_codecname,
4321 /* DllName */ NULL,
4322 /* FormatDescription */ tiff_format,
4323 /* FilenameExtension */ tiff_extension,
4324 /* MimeType */ tiff_mimetype,
4325 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsEncoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4326 /* Version */ 1,
4327 /* SigCount */ 2,
4328 /* SigSize */ 4,
4329 /* SigPattern */ tiff_sig_pattern,
4330 /* SigMask */ tiff_sig_mask,
4332 encode_image_tiff,
4333 decode_image_tiff
4336 { /* EMF */
4337 /* Clsid */ { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4338 /* FormatID */ { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4339 /* CodecName */ emf_codecname,
4340 /* DllName */ NULL,
4341 /* FormatDescription */ emf_format,
4342 /* FilenameExtension */ emf_extension,
4343 /* MimeType */ emf_mimetype,
4344 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
4345 /* Version */ 1,
4346 /* SigCount */ 1,
4347 /* SigSize */ 4,
4348 /* SigPattern */ emf_sig_pattern,
4349 /* SigMask */ emf_sig_mask,
4351 NULL,
4352 decode_image_olepicture_metafile
4355 { /* WMF */
4356 /* Clsid */ { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4357 /* FormatID */ { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4358 /* CodecName */ wmf_codecname,
4359 /* DllName */ NULL,
4360 /* FormatDescription */ wmf_format,
4361 /* FilenameExtension */ wmf_extension,
4362 /* MimeType */ wmf_mimetype,
4363 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
4364 /* Version */ 1,
4365 /* SigCount */ 1,
4366 /* SigSize */ 2,
4367 /* SigPattern */ wmf_sig_pattern,
4368 /* SigMask */ wmf_sig_mask,
4370 NULL,
4371 decode_image_olepicture_metafile
4374 { /* PNG */
4375 /* Clsid */ { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4376 /* FormatID */ { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4377 /* CodecName */ png_codecname,
4378 /* DllName */ NULL,
4379 /* FormatDescription */ png_format,
4380 /* FilenameExtension */ png_extension,
4381 /* MimeType */ png_mimetype,
4382 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4383 /* Version */ 1,
4384 /* SigCount */ 1,
4385 /* SigSize */ 8,
4386 /* SigPattern */ png_sig_pattern,
4387 /* SigMask */ png_sig_mask,
4389 encode_image_png,
4390 decode_image_png
4393 { /* ICO */
4394 /* Clsid */ { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4395 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4396 /* CodecName */ ico_codecname,
4397 /* DllName */ NULL,
4398 /* FormatDescription */ ico_format,
4399 /* FilenameExtension */ ico_extension,
4400 /* MimeType */ ico_mimetype,
4401 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4402 /* Version */ 1,
4403 /* SigCount */ 1,
4404 /* SigSize */ 4,
4405 /* SigPattern */ ico_sig_pattern,
4406 /* SigMask */ ico_sig_mask,
4408 NULL,
4409 decode_image_icon
4413 /*****************************************************************************
4414 * GdipGetImageDecodersSize [GDIPLUS.@]
4416 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
4418 int decoder_count=0;
4419 int i;
4420 TRACE("%p %p\n", numDecoders, size);
4422 if (!numDecoders || !size)
4423 return InvalidParameter;
4425 for (i=0; i<NUM_CODECS; i++)
4427 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
4428 decoder_count++;
4431 *numDecoders = decoder_count;
4432 *size = decoder_count * sizeof(ImageCodecInfo);
4434 return Ok;
4437 /*****************************************************************************
4438 * GdipGetImageDecoders [GDIPLUS.@]
4440 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
4442 int i, decoder_count=0;
4443 TRACE("%u %u %p\n", numDecoders, size, decoders);
4445 if (!decoders ||
4446 size != numDecoders * sizeof(ImageCodecInfo))
4447 return GenericError;
4449 for (i=0; i<NUM_CODECS; i++)
4451 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
4453 if (decoder_count == numDecoders) return GenericError;
4454 memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
4455 decoder_count++;
4459 if (decoder_count < numDecoders) return GenericError;
4461 return Ok;
4464 /*****************************************************************************
4465 * GdipGetImageEncodersSize [GDIPLUS.@]
4467 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
4469 int encoder_count=0;
4470 int i;
4471 TRACE("%p %p\n", numEncoders, size);
4473 if (!numEncoders || !size)
4474 return InvalidParameter;
4476 for (i=0; i<NUM_CODECS; i++)
4478 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
4479 encoder_count++;
4482 *numEncoders = encoder_count;
4483 *size = encoder_count * sizeof(ImageCodecInfo);
4485 return Ok;
4488 /*****************************************************************************
4489 * GdipGetImageEncoders [GDIPLUS.@]
4491 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
4493 int i, encoder_count=0;
4494 TRACE("%u %u %p\n", numEncoders, size, encoders);
4496 if (!encoders ||
4497 size != numEncoders * sizeof(ImageCodecInfo))
4498 return GenericError;
4500 for (i=0; i<NUM_CODECS; i++)
4502 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
4504 if (encoder_count == numEncoders) return GenericError;
4505 memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
4506 encoder_count++;
4510 if (encoder_count < numEncoders) return GenericError;
4512 return Ok;
4515 GpStatus WINGDIPAPI GdipGetEncoderParameterListSize(GpImage *image,
4516 GDIPCONST CLSID* clsidEncoder, UINT *size)
4518 static int calls;
4520 TRACE("(%p,%s,%p)\n", image, debugstr_guid(clsidEncoder), size);
4522 if(!(calls++))
4523 FIXME("not implemented\n");
4525 *size = 0;
4527 return NotImplemented;
4530 static PixelFormat get_16bpp_format(HBITMAP hbm)
4532 BITMAPV4HEADER bmh;
4533 HDC hdc;
4534 PixelFormat result;
4536 hdc = CreateCompatibleDC(NULL);
4538 memset(&bmh, 0, sizeof(bmh));
4539 bmh.bV4Size = sizeof(bmh);
4540 bmh.bV4Width = 1;
4541 bmh.bV4Height = 1;
4542 bmh.bV4V4Compression = BI_BITFIELDS;
4543 bmh.bV4BitCount = 16;
4545 GetDIBits(hdc, hbm, 0, 0, NULL, (BITMAPINFO*)&bmh, DIB_RGB_COLORS);
4547 if (bmh.bV4RedMask == 0x7c00 &&
4548 bmh.bV4GreenMask == 0x3e0 &&
4549 bmh.bV4BlueMask == 0x1f)
4551 result = PixelFormat16bppRGB555;
4553 else if (bmh.bV4RedMask == 0xf800 &&
4554 bmh.bV4GreenMask == 0x7e0 &&
4555 bmh.bV4BlueMask == 0x1f)
4557 result = PixelFormat16bppRGB565;
4559 else
4561 FIXME("unrecognized bitfields %x,%x,%x\n", bmh.bV4RedMask,
4562 bmh.bV4GreenMask, bmh.bV4BlueMask);
4563 result = PixelFormatUndefined;
4566 DeleteDC(hdc);
4568 return result;
4571 /*****************************************************************************
4572 * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
4574 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
4576 BITMAP bm;
4577 GpStatus retval;
4578 PixelFormat format;
4579 BitmapData lockeddata;
4581 TRACE("%p %p %p\n", hbm, hpal, bitmap);
4583 if(!hbm || !bitmap)
4584 return InvalidParameter;
4586 if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm))
4587 return InvalidParameter;
4589 /* TODO: Figure out the correct format for 16, 32, 64 bpp */
4590 switch(bm.bmBitsPixel) {
4591 case 1:
4592 format = PixelFormat1bppIndexed;
4593 break;
4594 case 4:
4595 format = PixelFormat4bppIndexed;
4596 break;
4597 case 8:
4598 format = PixelFormat8bppIndexed;
4599 break;
4600 case 16:
4601 format = get_16bpp_format(hbm);
4602 if (format == PixelFormatUndefined)
4603 return InvalidParameter;
4604 break;
4605 case 24:
4606 format = PixelFormat24bppRGB;
4607 break;
4608 case 32:
4609 format = PixelFormat32bppRGB;
4610 break;
4611 case 48:
4612 format = PixelFormat48bppRGB;
4613 break;
4614 default:
4615 FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel);
4616 return InvalidParameter;
4619 retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, 0,
4620 format, NULL, bitmap);
4622 if (retval == Ok)
4624 retval = GdipBitmapLockBits(*bitmap, NULL, ImageLockModeWrite,
4625 format, &lockeddata);
4626 if (retval == Ok)
4628 HDC hdc;
4629 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
4630 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
4631 INT src_height;
4633 hdc = CreateCompatibleDC(NULL);
4635 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
4636 pbmi->bmiHeader.biBitCount = 0;
4638 GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
4640 src_height = abs(pbmi->bmiHeader.biHeight);
4641 pbmi->bmiHeader.biHeight = -src_height;
4643 GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
4645 DeleteDC(hdc);
4647 GdipBitmapUnlockBits(*bitmap, &lockeddata);
4650 if (retval == Ok && hpal)
4652 PALETTEENTRY entry[256];
4653 ColorPalette *palette=NULL;
4654 int i, num_palette_entries;
4656 num_palette_entries = GetPaletteEntries(hpal, 0, 256, entry);
4657 if (!num_palette_entries)
4658 retval = GenericError;
4660 palette = GdipAlloc(sizeof(ColorPalette) + sizeof(ARGB) * (num_palette_entries-1));
4661 if (!palette)
4662 retval = OutOfMemory;
4664 if (retval == Ok)
4666 palette->Flags = 0;
4667 palette->Count = num_palette_entries;
4669 for (i=0; i<num_palette_entries; i++)
4671 palette->Entries[i] = 0xff000000 | entry[i].peRed << 16 |
4672 entry[i].peGreen << 8 | entry[i].peBlue;
4675 retval = GdipSetImagePalette((GpImage*)*bitmap, palette);
4678 GdipFree(palette);
4681 if (retval != Ok)
4683 GdipDisposeImage((GpImage*)*bitmap);
4684 *bitmap = NULL;
4688 return retval;
4691 GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect)
4693 FIXME("(%p): stub\n", effect);
4694 /* note: According to Jose Roca's GDI+ Docs, this is not implemented
4695 * in Windows's gdiplus */
4696 return NotImplemented;
4699 /*****************************************************************************
4700 * GdipSetEffectParameters [GDIPLUS.@]
4702 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
4703 const VOID *params, const UINT size)
4705 static int calls;
4707 TRACE("(%p,%p,%u)\n", effect, params, size);
4709 if(!(calls++))
4710 FIXME("not implemented\n");
4712 return NotImplemented;
4715 /*****************************************************************************
4716 * GdipGetImageFlags [GDIPLUS.@]
4718 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
4720 TRACE("%p %p\n", image, flags);
4722 if(!image || !flags)
4723 return InvalidParameter;
4725 *flags = image->flags;
4727 return Ok;
4730 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
4732 TRACE("(%d, %p)\n", control, param);
4734 switch(control){
4735 case TestControlForceBilinear:
4736 if(param)
4737 FIXME("TestControlForceBilinear not handled\n");
4738 break;
4739 case TestControlNoICM:
4740 if(param)
4741 FIXME("TestControlNoICM not handled\n");
4742 break;
4743 case TestControlGetBuildNumber:
4744 *((DWORD*)param) = 3102;
4745 break;
4748 return Ok;
4751 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
4752 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
4753 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
4754 GpMetafile **metafile)
4756 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
4757 frameUnit, debugstr_w(desc), metafile);
4759 return NotImplemented;
4762 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
4763 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
4764 GDIPCONST WCHAR *desc, GpMetafile **metafile)
4766 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
4767 frameUnit, debugstr_w(desc), metafile);
4769 return NotImplemented;
4772 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
4774 TRACE("%p\n", image);
4776 return Ok;
4779 /*****************************************************************************
4780 * GdipGetImageThumbnail [GDIPLUS.@]
4782 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
4783 GpImage **ret_image, GetThumbnailImageAbort cb,
4784 VOID * cb_data)
4786 GpStatus stat;
4787 GpGraphics *graphics;
4788 UINT srcwidth, srcheight;
4790 TRACE("(%p %u %u %p %p %p)\n",
4791 image, width, height, ret_image, cb, cb_data);
4793 if (!image || !ret_image)
4794 return InvalidParameter;
4796 if (!width) width = 120;
4797 if (!height) height = 120;
4799 GdipGetImageWidth(image, &srcwidth);
4800 GdipGetImageHeight(image, &srcheight);
4802 stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
4803 NULL, (GpBitmap**)ret_image);
4805 if (stat == Ok)
4807 stat = GdipGetImageGraphicsContext(*ret_image, &graphics);
4809 if (stat == Ok)
4811 stat = GdipDrawImageRectRectI(graphics, image,
4812 0, 0, width, height, 0, 0, srcwidth, srcheight, UnitPixel,
4813 NULL, NULL, NULL);
4815 GdipDeleteGraphics(graphics);
4818 if (stat != Ok)
4820 GdipDisposeImage(*ret_image);
4821 *ret_image = NULL;
4825 return stat;
4828 /*****************************************************************************
4829 * GdipImageRotateFlip [GDIPLUS.@]
4831 GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
4833 GpBitmap *new_bitmap;
4834 GpBitmap *bitmap;
4835 int bpp, bytesperpixel;
4836 int rotate_90, flip_x, flip_y;
4837 int src_x_offset, src_y_offset;
4838 LPBYTE src_origin;
4839 UINT x, y, width, height;
4840 BitmapData src_lock, dst_lock;
4841 GpStatus stat;
4843 TRACE("(%p, %u)\n", image, type);
4845 if (!image)
4846 return InvalidParameter;
4848 rotate_90 = type&1;
4849 flip_x = (type&6) == 2 || (type&6) == 4;
4850 flip_y = (type&3) == 1 || (type&3) == 2;
4852 if (image->type != ImageTypeBitmap)
4854 FIXME("Not implemented for type %i\n", image->type);
4855 return NotImplemented;
4858 bitmap = (GpBitmap*)image;
4859 bpp = PIXELFORMATBPP(bitmap->format);
4861 if (bpp < 8)
4863 FIXME("Not implemented for %i bit images\n", bpp);
4864 return NotImplemented;
4867 if (rotate_90)
4869 width = bitmap->height;
4870 height = bitmap->width;
4872 else
4874 width = bitmap->width;
4875 height = bitmap->height;
4878 bytesperpixel = bpp/8;
4880 stat = GdipCreateBitmapFromScan0(width, height, 0, bitmap->format, NULL, &new_bitmap);
4882 if (stat != Ok)
4883 return stat;
4885 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format, &src_lock);
4887 if (stat == Ok)
4889 stat = GdipBitmapLockBits(new_bitmap, NULL, ImageLockModeWrite, bitmap->format, &dst_lock);
4891 if (stat == Ok)
4893 LPBYTE src_row, src_pixel;
4894 LPBYTE dst_row, dst_pixel;
4896 src_origin = src_lock.Scan0;
4897 if (flip_x) src_origin += bytesperpixel * (bitmap->width - 1);
4898 if (flip_y) src_origin += src_lock.Stride * (bitmap->height - 1);
4900 if (rotate_90)
4902 if (flip_y) src_x_offset = -src_lock.Stride;
4903 else src_x_offset = src_lock.Stride;
4904 if (flip_x) src_y_offset = -bytesperpixel;
4905 else src_y_offset = bytesperpixel;
4907 else
4909 if (flip_x) src_x_offset = -bytesperpixel;
4910 else src_x_offset = bytesperpixel;
4911 if (flip_y) src_y_offset = -src_lock.Stride;
4912 else src_y_offset = src_lock.Stride;
4915 src_row = src_origin;
4916 dst_row = dst_lock.Scan0;
4917 for (y=0; y<height; y++)
4919 src_pixel = src_row;
4920 dst_pixel = dst_row;
4921 for (x=0; x<width; x++)
4923 /* FIXME: This could probably be faster without memcpy. */
4924 memcpy(dst_pixel, src_pixel, bytesperpixel);
4925 dst_pixel += bytesperpixel;
4926 src_pixel += src_x_offset;
4928 src_row += src_y_offset;
4929 dst_row += dst_lock.Stride;
4932 GdipBitmapUnlockBits(new_bitmap, &dst_lock);
4935 GdipBitmapUnlockBits(bitmap, &src_lock);
4938 if (stat == Ok)
4939 move_bitmap(bitmap, new_bitmap, FALSE);
4940 else
4941 GdipDisposeImage((GpImage*)new_bitmap);
4943 return stat;
4946 /*****************************************************************************
4947 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
4950 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
4951 GpMetafile* metafile, BOOL* conversionSuccess,
4952 const WCHAR* filename, EmfType emfType,
4953 const WCHAR* description, GpMetafile** out_metafile)
4955 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
4956 return NotImplemented;