gdiplus: Move metafile functions to metafile.c.
[wine/multimedia.git] / dlls / gdiplus / image.c
blobd57498cb3d90962d2edd4b2f69c45ae580453d13
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 GdipCreateBitmapFromGraphics(INT width, INT height,
1518 GpGraphics* target, GpBitmap** bitmap)
1520 GpStatus ret;
1522 TRACE("(%d, %d, %p, %p)\n", width, height, target, bitmap);
1524 if(!target || !bitmap)
1525 return InvalidParameter;
1527 ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
1528 NULL, bitmap);
1530 if (ret == Ok)
1532 GdipGetDpiX(target, &(*bitmap)->image.xres);
1533 GdipGetDpiY(target, &(*bitmap)->image.yres);
1536 return ret;
1539 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
1541 GpStatus stat;
1542 ICONINFO iinfo;
1543 BITMAP bm;
1544 int ret;
1545 UINT width, height, stride;
1546 GpRect rect;
1547 BitmapData lockeddata;
1548 HDC screendc;
1549 BOOL has_alpha;
1550 int x, y;
1551 BITMAPINFOHEADER bih;
1552 DWORD *src;
1553 BYTE *dst_row;
1554 DWORD *dst;
1556 TRACE("%p, %p\n", hicon, bitmap);
1558 if(!bitmap || !GetIconInfo(hicon, &iinfo))
1559 return InvalidParameter;
1561 /* get the size of the icon */
1562 ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
1563 if (ret == 0) {
1564 DeleteObject(iinfo.hbmColor);
1565 DeleteObject(iinfo.hbmMask);
1566 return GenericError;
1569 width = bm.bmWidth;
1570 height = iinfo.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2;
1571 stride = width * 4;
1573 stat = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat32bppARGB, NULL, bitmap);
1574 if (stat != Ok) {
1575 DeleteObject(iinfo.hbmColor);
1576 DeleteObject(iinfo.hbmMask);
1577 return stat;
1580 rect.X = 0;
1581 rect.Y = 0;
1582 rect.Width = width;
1583 rect.Height = height;
1585 stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
1586 if (stat != Ok) {
1587 DeleteObject(iinfo.hbmColor);
1588 DeleteObject(iinfo.hbmMask);
1589 GdipDisposeImage((GpImage*)*bitmap);
1590 return stat;
1593 bih.biSize = sizeof(bih);
1594 bih.biWidth = width;
1595 bih.biHeight = iinfo.hbmColor ? -height: -height * 2;
1596 bih.biPlanes = 1;
1597 bih.biBitCount = 32;
1598 bih.biCompression = BI_RGB;
1599 bih.biSizeImage = 0;
1600 bih.biXPelsPerMeter = 0;
1601 bih.biYPelsPerMeter = 0;
1602 bih.biClrUsed = 0;
1603 bih.biClrImportant = 0;
1605 screendc = CreateCompatibleDC(0);
1606 if (iinfo.hbmColor)
1608 GetDIBits(screendc, iinfo.hbmColor, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1610 if (bm.bmBitsPixel == 32)
1612 has_alpha = FALSE;
1614 /* If any pixel has a non-zero alpha, ignore hbmMask */
1615 src = (DWORD*)lockeddata.Scan0;
1616 for (x=0; x<width && !has_alpha; x++)
1617 for (y=0; y<height && !has_alpha; y++)
1618 if ((*src++ & 0xff000000) != 0)
1619 has_alpha = TRUE;
1621 else has_alpha = FALSE;
1623 else
1625 GetDIBits(screendc, iinfo.hbmMask, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1626 has_alpha = FALSE;
1629 if (!has_alpha)
1631 if (iinfo.hbmMask)
1633 BYTE *bits = HeapAlloc(GetProcessHeap(), 0, height * stride);
1635 /* read alpha data from the mask */
1636 if (iinfo.hbmColor)
1637 GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1638 else
1639 GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1641 src = (DWORD*)bits;
1642 dst_row = lockeddata.Scan0;
1643 for (y=0; y<height; y++)
1645 dst = (DWORD*)dst_row;
1646 for (x=0; x<height; x++)
1648 DWORD src_value = *src++;
1649 if (src_value)
1650 *dst++ = 0;
1651 else
1652 *dst++ |= 0xff000000;
1654 dst_row += lockeddata.Stride;
1657 HeapFree(GetProcessHeap(), 0, bits);
1659 else
1661 /* set constant alpha of 255 */
1662 dst_row = lockeddata.Scan0;
1663 for (y=0; y<height; y++)
1665 dst = (DWORD*)dst_row;
1666 for (x=0; x<height; x++)
1667 *dst++ |= 0xff000000;
1668 dst_row += lockeddata.Stride;
1673 DeleteDC(screendc);
1675 DeleteObject(iinfo.hbmColor);
1676 DeleteObject(iinfo.hbmMask);
1678 GdipBitmapUnlockBits(*bitmap, &lockeddata);
1680 return Ok;
1683 static void generate_halftone_palette(ARGB *entries, UINT count)
1685 static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
1686 UINT i;
1688 for (i=0; i<8 && i<count; i++)
1690 entries[i] = 0xff000000;
1691 if (i&1) entries[i] |= 0x800000;
1692 if (i&2) entries[i] |= 0x8000;
1693 if (i&4) entries[i] |= 0x80;
1696 if (8 < count)
1697 entries[i] = 0xffc0c0c0;
1699 for (i=9; i<16 && i<count; i++)
1701 entries[i] = 0xff000000;
1702 if (i&1) entries[i] |= 0xff0000;
1703 if (i&2) entries[i] |= 0xff00;
1704 if (i&4) entries[i] |= 0xff;
1707 for (i=16; i<40 && i<count; i++)
1709 entries[i] = 0;
1712 for (i=40; i<256 && i<count; i++)
1714 entries[i] = 0xff000000;
1715 entries[i] |= halftone_values[(i-40)%6];
1716 entries[i] |= halftone_values[((i-40)/6)%6] << 8;
1717 entries[i] |= halftone_values[((i-40)/36)%6] << 16;
1721 static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
1723 HDC screendc = CreateCompatibleDC(0);
1725 if (!screendc) return GenericError;
1727 *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
1728 *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
1730 DeleteDC(screendc);
1732 return Ok;
1735 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
1736 PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
1738 HBITMAP hbitmap=NULL;
1739 INT row_size, dib_stride;
1740 BYTE *bits=NULL, *own_bits=NULL;
1741 REAL xres, yres;
1742 GpStatus stat;
1744 TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
1746 if (!bitmap) return InvalidParameter;
1748 if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
1749 *bitmap = NULL;
1750 return InvalidParameter;
1753 if(scan0 && !stride)
1754 return InvalidParameter;
1756 stat = get_screen_resolution(&xres, &yres);
1757 if (stat != Ok) return stat;
1759 row_size = (width * PIXELFORMATBPP(format)+7) / 8;
1760 dib_stride = (row_size + 3) & ~3;
1762 if(stride == 0)
1763 stride = dib_stride;
1765 if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
1767 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1768 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
1770 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1771 pbmi->bmiHeader.biWidth = width;
1772 pbmi->bmiHeader.biHeight = -height;
1773 pbmi->bmiHeader.biPlanes = 1;
1774 /* FIXME: use the rest of the data from format */
1775 pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
1776 pbmi->bmiHeader.biCompression = BI_RGB;
1777 pbmi->bmiHeader.biSizeImage = 0;
1778 pbmi->bmiHeader.biXPelsPerMeter = 0;
1779 pbmi->bmiHeader.biYPelsPerMeter = 0;
1780 pbmi->bmiHeader.biClrUsed = 0;
1781 pbmi->bmiHeader.biClrImportant = 0;
1783 hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1785 if (!hbitmap) return GenericError;
1787 stride = dib_stride;
1789 else
1791 /* Not a GDI format; don't try to make an HBITMAP. */
1792 if (scan0)
1793 bits = scan0;
1794 else
1796 INT size = abs(stride) * height;
1798 own_bits = bits = GdipAlloc(size);
1799 if (!own_bits) return OutOfMemory;
1801 if (stride < 0)
1802 bits += stride * (1 - height);
1806 *bitmap = GdipAlloc(sizeof(GpBitmap));
1807 if(!*bitmap)
1809 DeleteObject(hbitmap);
1810 GdipFree(own_bits);
1811 return OutOfMemory;
1814 (*bitmap)->image.type = ImageTypeBitmap;
1815 memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
1816 (*bitmap)->image.flags = ImageFlagsNone;
1817 (*bitmap)->image.frame_count = 1;
1818 (*bitmap)->image.current_frame = 0;
1819 (*bitmap)->image.palette = NULL;
1820 (*bitmap)->image.xres = xres;
1821 (*bitmap)->image.yres = yres;
1822 (*bitmap)->width = width;
1823 (*bitmap)->height = height;
1824 (*bitmap)->format = format;
1825 (*bitmap)->image.picture = NULL;
1826 (*bitmap)->image.stream = NULL;
1827 (*bitmap)->hbitmap = hbitmap;
1828 (*bitmap)->hdc = NULL;
1829 (*bitmap)->bits = bits;
1830 (*bitmap)->stride = stride;
1831 (*bitmap)->own_bits = own_bits;
1832 (*bitmap)->metadata_reader = NULL;
1833 (*bitmap)->prop_count = 0;
1834 (*bitmap)->prop_item = NULL;
1836 /* set format-related flags */
1837 if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed))
1838 (*bitmap)->image.flags |= ImageFlagsHasAlpha;
1840 if (format == PixelFormat1bppIndexed ||
1841 format == PixelFormat4bppIndexed ||
1842 format == PixelFormat8bppIndexed)
1844 (*bitmap)->image.palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * (1 << PIXELFORMATBPP(format)));
1846 if (!(*bitmap)->image.palette)
1848 GdipDisposeImage(&(*bitmap)->image);
1849 *bitmap = NULL;
1850 return OutOfMemory;
1853 (*bitmap)->image.palette->Count = 1 << PIXELFORMATBPP(format);
1855 if (format == PixelFormat1bppIndexed)
1857 (*bitmap)->image.palette->Flags = PaletteFlagsGrayScale;
1858 (*bitmap)->image.palette->Entries[0] = 0xff000000;
1859 (*bitmap)->image.palette->Entries[1] = 0xffffffff;
1861 else
1863 if (format == PixelFormat8bppIndexed)
1864 (*bitmap)->image.palette->Flags = PaletteFlagsHalftone;
1866 generate_halftone_palette((*bitmap)->image.palette->Entries,
1867 (*bitmap)->image.palette->Count);
1871 TRACE("<-- %p\n", *bitmap);
1873 return Ok;
1876 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
1877 GpBitmap **bitmap)
1879 GpStatus stat;
1881 TRACE("%p %p\n", stream, bitmap);
1883 stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
1885 if(stat != Ok)
1886 return stat;
1888 if((*bitmap)->image.type != ImageTypeBitmap){
1889 GdipDisposeImage(&(*bitmap)->image);
1890 *bitmap = NULL;
1891 return GenericError; /* FIXME: what error to return? */
1894 return Ok;
1897 /* FIXME: no icm */
1898 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
1899 GpBitmap **bitmap)
1901 TRACE("%p %p\n", stream, bitmap);
1903 return GdipCreateBitmapFromStream(stream, bitmap);
1906 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
1907 GpCachedBitmap **cachedbmp)
1909 GpStatus stat;
1911 TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
1913 if(!bitmap || !graphics || !cachedbmp)
1914 return InvalidParameter;
1916 *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
1917 if(!*cachedbmp)
1918 return OutOfMemory;
1920 stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
1921 if(stat != Ok){
1922 GdipFree(*cachedbmp);
1923 return stat;
1926 return Ok;
1929 GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon)
1931 GpStatus stat;
1932 BitmapData lockeddata;
1933 ULONG andstride, xorstride, bitssize;
1934 LPBYTE andbits, xorbits, androw, xorrow, srcrow;
1935 UINT x, y;
1937 TRACE("(%p, %p)\n", bitmap, hicon);
1939 if (!bitmap || !hicon)
1940 return InvalidParameter;
1942 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead,
1943 PixelFormat32bppPARGB, &lockeddata);
1944 if (stat == Ok)
1946 andstride = ((lockeddata.Width+31)/32)*4;
1947 xorstride = lockeddata.Width*4;
1948 bitssize = (andstride + xorstride) * lockeddata.Height;
1950 andbits = GdipAlloc(bitssize);
1952 if (andbits)
1954 xorbits = andbits + andstride * lockeddata.Height;
1956 for (y=0; y<lockeddata.Height; y++)
1958 srcrow = ((LPBYTE)lockeddata.Scan0) + lockeddata.Stride * y;
1960 androw = andbits + andstride * y;
1961 for (x=0; x<lockeddata.Width; x++)
1962 if (srcrow[3+4*x] >= 128)
1963 androw[x/8] |= 1 << (7-x%8);
1965 xorrow = xorbits + xorstride * y;
1966 memcpy(xorrow, srcrow, xorstride);
1969 *hicon = CreateIcon(NULL, lockeddata.Width, lockeddata.Height, 1, 32,
1970 andbits, xorbits);
1972 GdipFree(andbits);
1974 else
1975 stat = OutOfMemory;
1977 GdipBitmapUnlockBits(bitmap, &lockeddata);
1980 return stat;
1983 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
1985 TRACE("%p\n", cachedbmp);
1987 if(!cachedbmp)
1988 return InvalidParameter;
1990 GdipDisposeImage(cachedbmp->image);
1991 GdipFree(cachedbmp);
1993 return Ok;
1996 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
1997 GpCachedBitmap *cachedbmp, INT x, INT y)
1999 TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
2001 if(!graphics || !cachedbmp)
2002 return InvalidParameter;
2004 return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
2007 /* Internal utility function: Replace the image data of dst with that of src,
2008 * and free src. */
2009 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
2011 assert(src->image.type == ImageTypeBitmap);
2012 assert(dst->image.type == ImageTypeBitmap);
2014 GdipFree(dst->bitmapbits);
2015 GdipFree(dst->own_bits);
2016 DeleteDC(dst->hdc);
2017 DeleteObject(dst->hbitmap);
2019 if (clobber_palette)
2021 GdipFree(dst->image.palette);
2022 dst->image.palette = src->image.palette;
2024 else
2025 GdipFree(src->image.palette);
2027 dst->image.xres = src->image.xres;
2028 dst->image.yres = src->image.yres;
2029 dst->width = src->width;
2030 dst->height = src->height;
2031 dst->format = src->format;
2032 dst->hbitmap = src->hbitmap;
2033 dst->hdc = src->hdc;
2034 dst->bits = src->bits;
2035 dst->stride = src->stride;
2036 dst->own_bits = src->own_bits;
2037 if (dst->metadata_reader)
2038 IWICMetadataReader_Release(dst->metadata_reader);
2039 dst->metadata_reader = src->metadata_reader;
2040 GdipFree(dst->prop_item);
2041 dst->prop_item = src->prop_item;
2042 dst->prop_count = src->prop_count;
2043 if (dst->image.stream)
2044 IStream_Release(dst->image.stream);
2045 dst->image.stream = src->image.stream;
2046 dst->image.frame_count = src->image.frame_count;
2047 dst->image.current_frame = src->image.current_frame;
2048 dst->image.format = src->image.format;
2050 src->image.type = ~0;
2051 GdipFree(src);
2054 static GpStatus free_image_data(GpImage *image)
2056 if(!image)
2057 return InvalidParameter;
2059 if (image->type == ImageTypeBitmap)
2061 GdipFree(((GpBitmap*)image)->bitmapbits);
2062 GdipFree(((GpBitmap*)image)->own_bits);
2063 DeleteDC(((GpBitmap*)image)->hdc);
2064 DeleteObject(((GpBitmap*)image)->hbitmap);
2065 if (((GpBitmap*)image)->metadata_reader)
2066 IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader);
2067 GdipFree(((GpBitmap*)image)->prop_item);
2069 else if (image->type == ImageTypeMetafile)
2071 GpMetafile *metafile = (GpMetafile*)image;
2072 GdipFree(metafile->comment_data);
2073 DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
2074 if (!metafile->preserve_hemf)
2075 DeleteEnhMetaFile(metafile->hemf);
2076 if (metafile->record_graphics)
2078 WARN("metafile closed while recording\n");
2079 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
2080 metafile->record_graphics->image = NULL;
2081 metafile->record_graphics->busy = TRUE;
2084 else
2086 WARN("invalid image: %p\n", image);
2087 return ObjectBusy;
2089 if (image->picture)
2090 IPicture_Release(image->picture);
2091 if (image->stream)
2092 IStream_Release(image->stream);
2093 GdipFree(image->palette);
2095 return Ok;
2098 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
2100 GpStatus status;
2102 TRACE("%p\n", image);
2104 status = free_image_data(image);
2105 if (status != Ok) return status;
2106 image->type = ~0;
2107 GdipFree(image);
2109 return Ok;
2112 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
2114 static int calls;
2116 TRACE("(%p,%p)\n", image, item);
2118 if(!image || !item)
2119 return InvalidParameter;
2121 if (!(calls++))
2122 FIXME("not implemented\n");
2124 return NotImplemented;
2127 GpStatus WINGDIPAPI GdipGetImageItemData(GpImage *image, ImageItemData *item)
2129 static int calls;
2131 TRACE("(%p,%p)\n", image, item);
2133 if (!(calls++))
2134 FIXME("not implemented\n");
2136 return NotImplemented;
2139 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
2140 GpUnit *srcUnit)
2142 TRACE("%p %p %p\n", image, srcRect, srcUnit);
2144 if(!image || !srcRect || !srcUnit)
2145 return InvalidParameter;
2146 if(image->type == ImageTypeMetafile){
2147 *srcRect = ((GpMetafile*)image)->bounds;
2148 *srcUnit = ((GpMetafile*)image)->unit;
2150 else if(image->type == ImageTypeBitmap){
2151 srcRect->X = srcRect->Y = 0.0;
2152 srcRect->Width = (REAL) ((GpBitmap*)image)->width;
2153 srcRect->Height = (REAL) ((GpBitmap*)image)->height;
2154 *srcUnit = UnitPixel;
2156 else{
2157 srcRect->X = srcRect->Y = 0.0;
2158 srcRect->Width = ipicture_pixel_width(image->picture);
2159 srcRect->Height = ipicture_pixel_height(image->picture);
2160 *srcUnit = UnitPixel;
2163 TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
2164 srcRect->Width, srcRect->Height, *srcUnit);
2166 return Ok;
2169 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
2170 REAL *height)
2172 TRACE("%p %p %p\n", image, width, height);
2174 if(!image || !height || !width)
2175 return InvalidParameter;
2177 if(image->type == ImageTypeMetafile){
2178 *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2179 *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2181 else if(image->type == ImageTypeBitmap){
2182 *height = ((GpBitmap*)image)->height;
2183 *width = ((GpBitmap*)image)->width;
2185 else{
2186 *height = ipicture_pixel_height(image->picture);
2187 *width = ipicture_pixel_width(image->picture);
2190 TRACE("returning (%f, %f)\n", *height, *width);
2191 return Ok;
2194 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
2195 GpGraphics **graphics)
2197 HDC hdc;
2198 GpStatus stat;
2200 TRACE("%p %p\n", image, graphics);
2202 if(!image || !graphics)
2203 return InvalidParameter;
2205 if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
2207 hdc = ((GpBitmap*)image)->hdc;
2209 if(!hdc){
2210 hdc = CreateCompatibleDC(0);
2211 SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
2212 ((GpBitmap*)image)->hdc = hdc;
2215 stat = GdipCreateFromHDC(hdc, graphics);
2217 if (stat == Ok)
2219 (*graphics)->image = image;
2220 (*graphics)->xres = image->xres;
2221 (*graphics)->yres = image->yres;
2224 else if (image->type == ImageTypeMetafile)
2225 stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics);
2226 else
2227 stat = graphics_from_image(image, graphics);
2229 return stat;
2232 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
2234 TRACE("%p %p\n", image, height);
2236 if(!image || !height)
2237 return InvalidParameter;
2239 if(image->type == ImageTypeMetafile)
2240 *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2241 else if(image->type == ImageTypeBitmap)
2242 *height = ((GpBitmap*)image)->height;
2243 else
2244 *height = ipicture_pixel_height(image->picture);
2246 TRACE("returning %d\n", *height);
2248 return Ok;
2251 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
2253 if(!image || !res)
2254 return InvalidParameter;
2256 *res = image->xres;
2258 TRACE("(%p) <-- %0.2f\n", image, *res);
2260 return Ok;
2263 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
2265 TRACE("%p %p\n", image, size);
2267 if(!image || !size)
2268 return InvalidParameter;
2270 if (!image->palette || image->palette->Count == 0)
2271 *size = sizeof(ColorPalette);
2272 else
2273 *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette->Count;
2275 TRACE("<-- %u\n", *size);
2277 return Ok;
2280 /* FIXME: test this function for non-bitmap types */
2281 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
2283 TRACE("%p %p\n", image, format);
2285 if(!image || !format)
2286 return InvalidParameter;
2288 if(image->type != ImageTypeBitmap)
2289 *format = PixelFormat24bppRGB;
2290 else
2291 *format = ((GpBitmap*) image)->format;
2293 return Ok;
2296 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
2298 TRACE("(%p, %p)\n", image, format);
2300 if(!image || !format)
2301 return InvalidParameter;
2303 memcpy(format, &image->format, sizeof(GUID));
2305 return Ok;
2308 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
2310 TRACE("%p %p\n", image, type);
2312 if(!image || !type)
2313 return InvalidParameter;
2315 *type = image->type;
2317 return Ok;
2320 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
2322 if(!image || !res)
2323 return InvalidParameter;
2325 *res = image->yres;
2327 TRACE("(%p) <-- %0.2f\n", image, *res);
2329 return Ok;
2332 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
2334 TRACE("%p %p\n", image, width);
2336 if(!image || !width)
2337 return InvalidParameter;
2339 if(image->type == ImageTypeMetafile)
2340 *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2341 else if(image->type == ImageTypeBitmap)
2342 *width = ((GpBitmap*)image)->width;
2343 else
2344 *width = ipicture_pixel_width(image->picture);
2346 TRACE("returning %d\n", *width);
2348 return Ok;
2351 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num)
2353 TRACE("(%p, %p)\n", image, num);
2355 if (!image || !num) return InvalidParameter;
2357 *num = 0;
2359 if (image->type == ImageTypeBitmap)
2361 if (((GpBitmap *)image)->prop_item)
2363 *num = ((GpBitmap *)image)->prop_count;
2364 return Ok;
2367 if (((GpBitmap *)image)->metadata_reader)
2368 IWICMetadataReader_GetCount(((GpBitmap *)image)->metadata_reader, num);
2371 return Ok;
2374 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID *list)
2376 HRESULT hr;
2377 IWICMetadataReader *reader;
2378 IWICEnumMetadataItem *enumerator;
2379 UINT prop_count, i, items_returned;
2381 TRACE("(%p, %u, %p)\n", image, num, list);
2383 if (!image || !list) return InvalidParameter;
2385 if (image->type != ImageTypeBitmap)
2387 FIXME("Not implemented for type %d\n", image->type);
2388 return NotImplemented;
2391 if (((GpBitmap *)image)->prop_item)
2393 if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter;
2395 for (i = 0; i < num; i++)
2397 list[i] = ((GpBitmap *)image)->prop_item[i].id;
2400 return Ok;
2403 reader = ((GpBitmap *)image)->metadata_reader;
2404 if (!reader)
2406 if (num != 0) return InvalidParameter;
2407 return Ok;
2410 hr = IWICMetadataReader_GetCount(reader, &prop_count);
2411 if (FAILED(hr)) return hresult_to_status(hr);
2413 if (num != prop_count) return InvalidParameter;
2415 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2416 if (FAILED(hr)) return hresult_to_status(hr);
2418 IWICEnumMetadataItem_Reset(enumerator);
2420 for (i = 0; i < num; i++)
2422 PROPVARIANT id;
2424 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, NULL, &items_returned);
2425 if (hr != S_OK) break;
2427 if (id.vt != VT_UI2)
2429 FIXME("not supported propvariant type for id: %u\n", id.vt);
2430 list[i] = 0;
2431 continue;
2433 list[i] = id.u.uiVal;
2436 IWICEnumMetadataItem_Release(enumerator);
2438 return hr == S_OK ? Ok : hresult_to_status(hr);
2441 static UINT propvariant_size(PROPVARIANT *value)
2443 switch (value->vt & ~VT_VECTOR)
2445 case VT_EMPTY:
2446 return 0;
2447 case VT_I1:
2448 case VT_UI1:
2449 if (!(value->vt & VT_VECTOR)) return 1;
2450 return value->u.caub.cElems;
2451 case VT_I2:
2452 case VT_UI2:
2453 if (!(value->vt & VT_VECTOR)) return 2;
2454 return value->u.caui.cElems * 2;
2455 case VT_I4:
2456 case VT_UI4:
2457 case VT_R4:
2458 if (!(value->vt & VT_VECTOR)) return 4;
2459 return value->u.caul.cElems * 4;
2460 case VT_I8:
2461 case VT_UI8:
2462 case VT_R8:
2463 if (!(value->vt & VT_VECTOR)) return 8;
2464 return value->u.cauh.cElems * 8;
2465 case VT_LPSTR:
2466 return value->u.pszVal ? strlen(value->u.pszVal) + 1 : 0;
2467 case VT_BLOB:
2468 return value->u.blob.cbSize;
2469 default:
2470 FIXME("not supported variant type %d\n", value->vt);
2471 return 0;
2475 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID propid, UINT *size)
2477 HRESULT hr;
2478 IWICMetadataReader *reader;
2479 PROPVARIANT id, value;
2481 TRACE("(%p,%#x,%p)\n", image, propid, size);
2483 if (!size || !image) return InvalidParameter;
2485 if (image->type != ImageTypeBitmap)
2487 FIXME("Not implemented for type %d\n", image->type);
2488 return NotImplemented;
2491 if (((GpBitmap *)image)->prop_item)
2493 UINT i;
2495 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2497 if (propid == ((GpBitmap *)image)->prop_item[i].id)
2499 *size = sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2500 return Ok;
2504 return PropertyNotFound;
2507 reader = ((GpBitmap *)image)->metadata_reader;
2508 if (!reader) return PropertyNotFound;
2510 id.vt = VT_UI2;
2511 id.u.uiVal = propid;
2512 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2513 if (FAILED(hr)) return PropertyNotFound;
2515 *size = propvariant_size(&value);
2516 if (*size) *size += sizeof(PropertyItem);
2517 PropVariantClear(&value);
2519 return Ok;
2522 #ifndef PropertyTagTypeSByte
2523 #define PropertyTagTypeSByte 6
2524 #define PropertyTagTypeSShort 8
2525 #define PropertyTagTypeFloat 11
2526 #define PropertyTagTypeDouble 12
2527 #endif
2529 static UINT vt_to_itemtype(UINT vt)
2531 static const struct
2533 UINT vt, type;
2534 } vt2type[] =
2536 { VT_I1, PropertyTagTypeSByte },
2537 { VT_UI1, PropertyTagTypeByte },
2538 { VT_I2, PropertyTagTypeSShort },
2539 { VT_UI2, PropertyTagTypeShort },
2540 { VT_I4, PropertyTagTypeSLONG },
2541 { VT_UI4, PropertyTagTypeLong },
2542 { VT_I8, PropertyTagTypeSRational },
2543 { VT_UI8, PropertyTagTypeRational },
2544 { VT_R4, PropertyTagTypeFloat },
2545 { VT_R8, PropertyTagTypeDouble },
2546 { VT_LPSTR, PropertyTagTypeASCII },
2547 { VT_BLOB, PropertyTagTypeUndefined }
2549 UINT i;
2550 for (i = 0; i < sizeof(vt2type)/sizeof(vt2type[0]); i++)
2552 if (vt2type[i].vt == vt) return vt2type[i].type;
2554 FIXME("not supported variant type %u\n", vt);
2555 return 0;
2558 static GpStatus propvariant_to_item(PROPVARIANT *value, PropertyItem *item,
2559 UINT size, PROPID id)
2561 UINT item_size, item_type;
2563 item_size = propvariant_size(value);
2564 if (size != item_size + sizeof(PropertyItem)) return InvalidParameter;
2566 item_type = vt_to_itemtype(value->vt & ~VT_VECTOR);
2567 if (!item_type) return InvalidParameter;
2569 item->value = item + 1;
2571 switch (value->vt & ~VT_VECTOR)
2573 case VT_I1:
2574 case VT_UI1:
2575 if (!(value->vt & VT_VECTOR))
2576 *(BYTE *)item->value = value->u.bVal;
2577 else
2578 memcpy(item->value, value->u.caub.pElems, item_size);
2579 break;
2580 case VT_I2:
2581 case VT_UI2:
2582 if (!(value->vt & VT_VECTOR))
2583 *(USHORT *)item->value = value->u.uiVal;
2584 else
2585 memcpy(item->value, value->u.caui.pElems, item_size);
2586 break;
2587 case VT_I4:
2588 case VT_UI4:
2589 case VT_R4:
2590 if (!(value->vt & VT_VECTOR))
2591 *(ULONG *)item->value = value->u.ulVal;
2592 else
2593 memcpy(item->value, value->u.caul.pElems, item_size);
2594 break;
2595 case VT_I8:
2596 case VT_UI8:
2597 case VT_R8:
2598 if (!(value->vt & VT_VECTOR))
2599 *(ULONGLONG *)item->value = value->u.uhVal.QuadPart;
2600 else
2601 memcpy(item->value, value->u.cauh.pElems, item_size);
2602 break;
2603 case VT_LPSTR:
2604 memcpy(item->value, value->u.pszVal, item_size);
2605 break;
2606 case VT_BLOB:
2607 memcpy(item->value, value->u.blob.pBlobData, item_size);
2608 break;
2609 default:
2610 FIXME("not supported variant type %d\n", value->vt);
2611 return InvalidParameter;
2614 item->length = item_size;
2615 item->type = item_type;
2616 item->id = id;
2618 return Ok;
2621 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID propid, UINT size,
2622 PropertyItem *buffer)
2624 GpStatus stat;
2625 HRESULT hr;
2626 IWICMetadataReader *reader;
2627 PROPVARIANT id, value;
2629 TRACE("(%p,%#x,%u,%p)\n", image, propid, size, buffer);
2631 if (!image || !buffer) return InvalidParameter;
2633 if (image->type != ImageTypeBitmap)
2635 FIXME("Not implemented for type %d\n", image->type);
2636 return NotImplemented;
2639 if (((GpBitmap *)image)->prop_item)
2641 UINT i;
2643 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2645 if (propid == ((GpBitmap *)image)->prop_item[i].id)
2647 if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length)
2648 return InvalidParameter;
2650 *buffer = ((GpBitmap *)image)->prop_item[i];
2651 buffer->value = buffer + 1;
2652 memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length);
2653 return Ok;
2657 return PropertyNotFound;
2660 reader = ((GpBitmap *)image)->metadata_reader;
2661 if (!reader) return PropertyNotFound;
2663 id.vt = VT_UI2;
2664 id.u.uiVal = propid;
2665 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2666 if (FAILED(hr)) return PropertyNotFound;
2668 stat = propvariant_to_item(&value, buffer, size, propid);
2669 PropVariantClear(&value);
2671 return stat;
2674 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT *size, UINT *count)
2676 HRESULT hr;
2677 IWICMetadataReader *reader;
2678 IWICEnumMetadataItem *enumerator;
2679 UINT prop_count, prop_size, i;
2680 PROPVARIANT id, value;
2682 TRACE("(%p,%p,%p)\n", image, size, count);
2684 if (!image || !size || !count) return InvalidParameter;
2686 if (image->type != ImageTypeBitmap)
2688 FIXME("Not implemented for type %d\n", image->type);
2689 return NotImplemented;
2692 if (((GpBitmap *)image)->prop_item)
2694 *count = ((GpBitmap *)image)->prop_count;
2695 *size = 0;
2697 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2699 *size += sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2702 return Ok;
2705 reader = ((GpBitmap *)image)->metadata_reader;
2706 if (!reader) return PropertyNotFound;
2708 hr = IWICMetadataReader_GetCount(reader, &prop_count);
2709 if (FAILED(hr)) return hresult_to_status(hr);
2711 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2712 if (FAILED(hr)) return hresult_to_status(hr);
2714 IWICEnumMetadataItem_Reset(enumerator);
2716 prop_size = 0;
2718 PropVariantInit(&id);
2719 PropVariantInit(&value);
2721 for (i = 0; i < prop_count; i++)
2723 UINT items_returned, item_size;
2725 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2726 if (hr != S_OK) break;
2728 item_size = propvariant_size(&value);
2729 if (item_size) prop_size += sizeof(PropertyItem) + item_size;
2731 PropVariantClear(&id);
2732 PropVariantClear(&value);
2735 IWICEnumMetadataItem_Release(enumerator);
2737 if (hr != S_OK) return PropertyNotFound;
2739 *count = prop_count;
2740 *size = prop_size;
2741 return Ok;
2744 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
2745 UINT count, PropertyItem *buf)
2747 GpStatus status;
2748 HRESULT hr;
2749 IWICMetadataReader *reader;
2750 IWICEnumMetadataItem *enumerator;
2751 UINT prop_count, prop_size, i;
2752 PROPVARIANT id, value;
2753 char *item_value;
2755 TRACE("(%p,%u,%u,%p)\n", image, size, count, buf);
2757 if (!image || !buf) return InvalidParameter;
2759 if (image->type != ImageTypeBitmap)
2761 FIXME("Not implemented for type %d\n", image->type);
2762 return NotImplemented;
2765 status = GdipGetPropertySize(image, &prop_size, &prop_count);
2766 if (status != Ok) return status;
2768 if (prop_count != count || prop_size != size) return InvalidParameter;
2770 if (((GpBitmap *)image)->prop_item)
2772 memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size);
2774 item_value = (char *)(buf + prop_count);
2776 for (i = 0; i < prop_count; i++)
2778 buf[i].value = item_value;
2779 item_value += buf[i].length;
2782 return Ok;
2785 reader = ((GpBitmap *)image)->metadata_reader;
2786 if (!reader) return PropertyNotFound;
2788 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2789 if (FAILED(hr)) return hresult_to_status(hr);
2791 IWICEnumMetadataItem_Reset(enumerator);
2793 item_value = (char *)(buf + prop_count);
2795 PropVariantInit(&id);
2796 PropVariantInit(&value);
2798 for (i = 0; i < prop_count; i++)
2800 PropertyItem *item;
2801 UINT items_returned, item_size;
2803 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2804 if (hr != S_OK) break;
2806 if (id.vt != VT_UI2)
2808 FIXME("not supported propvariant type for id: %u\n", id.vt);
2809 continue;
2812 item_size = propvariant_size(&value);
2813 if (item_size)
2815 item = HeapAlloc(GetProcessHeap(), 0, item_size + sizeof(*item));
2817 propvariant_to_item(&value, item, item_size + sizeof(*item), id.u.uiVal);
2818 buf[i].id = item->id;
2819 buf[i].type = item->type;
2820 buf[i].length = item_size;
2821 buf[i].value = item_value;
2822 memcpy(item_value, item->value, item_size);
2823 item_value += item_size;
2825 HeapFree(GetProcessHeap(), 0, item);
2828 PropVariantClear(&id);
2829 PropVariantClear(&value);
2832 IWICEnumMetadataItem_Release(enumerator);
2834 if (hr != S_OK) return PropertyNotFound;
2836 return Ok;
2839 struct image_format_dimension
2841 const GUID *format;
2842 const GUID *dimension;
2845 static const struct image_format_dimension image_format_dimensions[] =
2847 {&ImageFormatGIF, &FrameDimensionTime},
2848 {&ImageFormatIcon, &FrameDimensionResolution},
2849 {NULL}
2852 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
2853 GDIPCONST GUID* dimensionID, UINT* count)
2855 TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
2857 if(!image || !count)
2858 return InvalidParameter;
2860 if (!dimensionID ||
2861 IsEqualGUID(dimensionID, &image->format) ||
2862 IsEqualGUID(dimensionID, &FrameDimensionPage) ||
2863 IsEqualGUID(dimensionID, &FrameDimensionTime))
2865 *count = image->frame_count;
2866 return Ok;
2869 return InvalidParameter;
2872 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
2873 UINT* count)
2875 TRACE("(%p, %p)\n", image, count);
2877 /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
2879 if(!image || !count)
2880 return InvalidParameter;
2882 *count = 1;
2884 return Ok;
2887 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
2888 GUID* dimensionIDs, UINT count)
2890 int i;
2891 const GUID *result=NULL;
2893 TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
2895 if(!image || !dimensionIDs || count != 1)
2896 return InvalidParameter;
2898 for (i=0; image_format_dimensions[i].format; i++)
2900 if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
2902 result = image_format_dimensions[i].dimension;
2903 break;
2907 if (!result)
2908 result = &FrameDimensionPage;
2910 memcpy(dimensionIDs, result, sizeof(GUID));
2912 return Ok;
2915 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
2916 GpImage **image)
2918 GpStatus stat;
2919 IStream *stream;
2921 TRACE("(%s) %p\n", debugstr_w(filename), image);
2923 if (!filename || !image)
2924 return InvalidParameter;
2926 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
2928 if (stat != Ok)
2929 return stat;
2931 stat = GdipLoadImageFromStream(stream, image);
2933 IStream_Release(stream);
2935 return stat;
2938 /* FIXME: no icm handling */
2939 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
2941 TRACE("(%s) %p\n", debugstr_w(filename), image);
2943 return GdipLoadImageFromFile(filename, image);
2946 static void add_property(GpBitmap *bitmap, PropertyItem *item)
2948 UINT prop_size, prop_count;
2949 PropertyItem *prop_item;
2951 if (bitmap->prop_item == NULL)
2953 prop_size = prop_count = 0;
2954 prop_item = GdipAlloc(item->length + sizeof(PropertyItem));
2955 if (!prop_item) return;
2957 else
2959 UINT i;
2960 char *item_value;
2962 GdipGetPropertySize((GpImage *)bitmap, &prop_size, &prop_count);
2964 prop_item = GdipAlloc(prop_size + item->length + sizeof(PropertyItem));
2965 if (!prop_item) return;
2966 memcpy(prop_item, bitmap->prop_item, sizeof(PropertyItem) * bitmap->prop_count);
2967 prop_size -= sizeof(PropertyItem) * bitmap->prop_count;
2968 memcpy(prop_item + prop_count + 1, bitmap->prop_item + prop_count, prop_size);
2970 item_value = (char *)(prop_item + prop_count + 1);
2972 for (i = 0; i < prop_count; i++)
2974 prop_item[i].value = item_value;
2975 item_value += prop_item[i].length;
2979 prop_item[prop_count].id = item->id;
2980 prop_item[prop_count].type = item->type;
2981 prop_item[prop_count].length = item->length;
2982 prop_item[prop_count].value = (char *)(prop_item + prop_count + 1) + prop_size;
2983 memcpy(prop_item[prop_count].value, item->value, item->length);
2985 GdipFree(bitmap->prop_item);
2986 bitmap->prop_item = prop_item;
2987 bitmap->prop_count++;
2990 static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
2992 HRESULT hr;
2993 GUID format;
2994 PROPVARIANT id, value;
2995 BOOL ret = FALSE;
2997 IWICMetadataReader_GetMetadataFormat(reader, &format);
2998 if (!IsEqualGUID(&format, guid)) return FALSE;
3000 PropVariantInit(&id);
3001 PropVariantInit(&value);
3003 id.vt = VT_LPWSTR;
3004 id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3005 if (!id.u.pwszVal) return FALSE;
3006 lstrcpyW(id.u.pwszVal, prop_name);
3007 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3008 if (hr == S_OK && value.vt == VT_BOOL)
3009 ret = value.u.boolVal;
3011 PropVariantClear(&id);
3012 PropVariantClear(&value);
3014 return ret;
3017 static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3019 HRESULT hr;
3020 GUID format;
3021 PROPVARIANT id, value;
3022 PropertyItem *item = NULL;
3024 IWICMetadataReader_GetMetadataFormat(reader, &format);
3025 if (!IsEqualGUID(&format, guid)) return NULL;
3027 PropVariantInit(&id);
3028 PropVariantInit(&value);
3030 id.vt = VT_LPWSTR;
3031 id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3032 if (!id.u.pwszVal) return NULL;
3033 lstrcpyW(id.u.pwszVal, prop_name);
3034 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3035 if (hr == S_OK)
3037 UINT item_size = propvariant_size(&value);
3038 if (item_size)
3040 item_size += sizeof(*item);
3041 item = GdipAlloc(item_size);
3042 if (propvariant_to_item(&value, item, item_size, 0) != Ok)
3044 GdipFree(item);
3045 item = NULL;
3050 PropVariantClear(&id);
3051 PropVariantClear(&value);
3053 return item;
3056 static PropertyItem *get_gif_comment(IWICMetadataReader *reader)
3058 static const WCHAR textentryW[] = { 'T','e','x','t','E','n','t','r','y',0 };
3059 PropertyItem *comment;
3061 comment = get_property(reader, &GUID_MetadataFormatGifComment, textentryW);
3062 if (comment)
3063 comment->id = PropertyTagExifUserComment;
3065 return comment;
3068 static PropertyItem *get_gif_loopcount(IWICMetadataReader *reader)
3070 static const WCHAR applicationW[] = { 'A','p','p','l','i','c','a','t','i','o','n',0 };
3071 static const WCHAR dataW[] = { 'D','a','t','a',0 };
3072 PropertyItem *appext = NULL, *appdata = NULL, *loop = NULL;
3074 appext = get_property(reader, &GUID_MetadataFormatAPE, applicationW);
3075 if (appext)
3077 if (appext->type == PropertyTagTypeByte && appext->length == 11 &&
3078 (!memcmp(appext->value, "NETSCAPE2.0", 11) || !memcmp(appext->value, "ANIMEXTS1.0", 11)))
3080 appdata = get_property(reader, &GUID_MetadataFormatAPE, dataW);
3081 if (appdata)
3083 if (appdata->type == PropertyTagTypeByte && appdata->length == 4)
3085 BYTE *data = appdata->value;
3086 if (data[0] == 3 && data[1] == 1)
3088 loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
3089 if (loop)
3091 loop->type = PropertyTagTypeShort;
3092 loop->id = PropertyTagLoopCount;
3093 loop->length = sizeof(SHORT);
3094 loop->value = loop + 1;
3095 *(SHORT *)loop->value = data[2] | (data[3] << 8);
3103 GdipFree(appext);
3104 GdipFree(appdata);
3106 return loop;
3109 static PropertyItem *get_gif_background(IWICMetadataReader *reader)
3111 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 };
3112 PropertyItem *background;
3114 background = get_property(reader, &GUID_MetadataFormatLSD, backgroundW);
3115 if (background)
3116 background->id = PropertyTagIndexBackground;
3118 return background;
3121 static PropertyItem *get_gif_palette(IWICBitmapDecoder *decoder, IWICMetadataReader *reader)
3123 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 };
3124 HRESULT hr;
3125 IWICImagingFactory *factory;
3126 IWICPalette *palette;
3127 UINT count = 0;
3128 WICColor colors[256];
3130 if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW))
3131 return NULL;
3133 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
3134 &IID_IWICImagingFactory, (void **)&factory);
3135 if (hr != S_OK) return NULL;
3137 hr = IWICImagingFactory_CreatePalette(factory, &palette);
3138 if (hr == S_OK)
3140 hr = IWICBitmapDecoder_CopyPalette(decoder, palette);
3141 if (hr == S_OK)
3142 IWICPalette_GetColors(palette, 256, colors, &count);
3144 IWICPalette_Release(palette);
3147 IWICImagingFactory_Release(factory);
3149 if (count)
3151 PropertyItem *pal;
3152 UINT i;
3153 BYTE *rgb;
3155 pal = GdipAlloc(sizeof(*pal) + count * 3);
3156 if (!pal) return NULL;
3157 pal->type = PropertyTagTypeByte;
3158 pal->id = PropertyTagGlobalPalette;
3159 pal->value = pal + 1;
3160 pal->length = count * 3;
3162 rgb = pal->value;
3164 for (i = 0; i < count; i++)
3166 rgb[i*3] = (colors[i] >> 16) & 0xff;
3167 rgb[i*3 + 1] = (colors[i] >> 8) & 0xff;
3168 rgb[i*3 + 2] = colors[i] & 0xff;
3171 return pal;
3174 return NULL;
3177 static PropertyItem *get_gif_transparent_idx(IWICMetadataReader *reader)
3179 static const WCHAR transparency_flagW[] = { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 };
3180 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 };
3181 PropertyItem *index = NULL;
3183 if (get_bool_property(reader, &GUID_MetadataFormatGCE, transparency_flagW))
3185 index = get_property(reader, &GUID_MetadataFormatGCE, colorW);
3186 if (index)
3187 index->id = PropertyTagIndexTransparent;
3189 return index;
3192 static LONG get_gif_frame_delay(IWICBitmapFrameDecode *frame)
3194 static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
3195 HRESULT hr;
3196 IWICMetadataBlockReader *block_reader;
3197 IWICMetadataReader *reader;
3198 UINT block_count, i;
3199 PropertyItem *delay;
3200 LONG value = 0;
3202 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3203 if (hr == S_OK)
3205 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3206 if (hr == S_OK)
3208 for (i = 0; i < block_count; i++)
3210 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3211 if (hr == S_OK)
3213 delay = get_property(reader, &GUID_MetadataFormatGCE, delayW);
3214 if (delay)
3216 if (delay->type == PropertyTagTypeShort && delay->length == 2)
3217 value = *(SHORT *)delay->value;
3219 GdipFree(delay);
3221 IWICMetadataReader_Release(reader);
3225 IWICMetadataBlockReader_Release(block_reader);
3228 return value;
3231 static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
3233 HRESULT hr;
3234 IWICBitmapFrameDecode *frame;
3235 IWICMetadataBlockReader *block_reader;
3236 IWICMetadataReader *reader;
3237 UINT frame_count, block_count, i;
3238 PropertyItem *delay = NULL, *comment = NULL, *background = NULL;
3239 PropertyItem *transparent_idx = NULL, *loop = NULL, *palette = NULL;
3241 IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3242 if (frame_count > 1)
3244 delay = GdipAlloc(sizeof(*delay) + frame_count * sizeof(LONG));
3245 if (delay)
3247 LONG *value;
3249 delay->type = PropertyTagTypeLong;
3250 delay->id = PropertyTagFrameDelay;
3251 delay->length = frame_count * sizeof(LONG);
3252 delay->value = delay + 1;
3254 value = delay->value;
3256 for (i = 0; i < frame_count; i++)
3258 hr = IWICBitmapDecoder_GetFrame(decoder, i, &frame);
3259 if (hr == S_OK)
3261 value[i] = get_gif_frame_delay(frame);
3262 IWICBitmapFrameDecode_Release(frame);
3264 else value[i] = 0;
3269 hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3270 if (hr == S_OK)
3272 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3273 if (hr == S_OK)
3275 for (i = 0; i < block_count; i++)
3277 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3278 if (hr == S_OK)
3280 if (!comment)
3281 comment = get_gif_comment(reader);
3283 if (frame_count > 1 && !loop)
3284 loop = get_gif_loopcount(reader);
3286 if (!background)
3287 background = get_gif_background(reader);
3289 if (!palette)
3290 palette = get_gif_palette(decoder, reader);
3292 IWICMetadataReader_Release(reader);
3296 IWICMetadataBlockReader_Release(block_reader);
3299 if (frame_count > 1 && !loop)
3301 loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
3302 if (loop)
3304 loop->type = PropertyTagTypeShort;
3305 loop->id = PropertyTagLoopCount;
3306 loop->length = sizeof(SHORT);
3307 loop->value = loop + 1;
3308 *(SHORT *)loop->value = 1;
3312 if (delay) add_property(bitmap, delay);
3313 if (comment) add_property(bitmap, comment);
3314 if (loop) add_property(bitmap, loop);
3315 if (palette) add_property(bitmap, palette);
3316 if (background) add_property(bitmap, background);
3318 GdipFree(delay);
3319 GdipFree(comment);
3320 GdipFree(loop);
3321 GdipFree(palette);
3322 GdipFree(background);
3324 /* Win7 gdiplus always returns transparent color index from frame 0 */
3325 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
3326 if (hr != S_OK) return;
3328 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3329 if (hr == S_OK)
3331 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3332 if (hr == S_OK)
3334 for (i = 0; i < block_count; i++)
3336 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3337 if (hr == S_OK)
3339 if (!transparent_idx)
3340 transparent_idx = get_gif_transparent_idx(reader);
3342 IWICMetadataReader_Release(reader);
3346 IWICMetadataBlockReader_Release(block_reader);
3349 if (transparent_idx) add_property(bitmap, transparent_idx);
3350 GdipFree(transparent_idx);
3352 IWICBitmapFrameDecode_Release(frame);
3355 typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame);
3357 static GpStatus decode_image_wic(IStream *stream, GDIPCONST CLSID *clsid,
3358 UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
3360 GpStatus status=Ok;
3361 GpBitmap *bitmap;
3362 HRESULT hr;
3363 IWICBitmapDecoder *decoder;
3364 IWICBitmapFrameDecode *frame;
3365 IWICBitmapSource *source=NULL;
3366 IWICMetadataBlockReader *block_reader;
3367 WICPixelFormatGUID wic_format;
3368 PixelFormat gdip_format=0;
3369 ColorPalette *palette = NULL;
3370 WICBitmapPaletteType palette_type = WICBitmapPaletteTypeFixedHalftone256;
3371 int i;
3372 UINT width, height, frame_count;
3373 BitmapData lockeddata;
3374 WICRect wrc;
3375 HRESULT initresult;
3377 TRACE("%p,%s,%u,%p\n", stream, wine_dbgstr_guid(clsid), active_frame, image);
3379 initresult = CoInitialize(NULL);
3381 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
3382 &IID_IWICBitmapDecoder, (void**)&decoder);
3383 if (FAILED(hr)) goto end;
3385 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
3386 if (SUCCEEDED(hr))
3388 IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3389 hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
3392 if (SUCCEEDED(hr)) /* got frame */
3394 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
3396 if (SUCCEEDED(hr))
3398 IWICBitmapSource *bmp_source;
3399 IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICBitmapSource, (void **)&bmp_source);
3401 for (i=0; pixel_formats[i].wic_format; i++)
3403 if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format))
3405 source = bmp_source;
3406 gdip_format = pixel_formats[i].gdip_format;
3407 palette_type = pixel_formats[i].palette_type;
3408 break;
3411 if (!source)
3413 /* unknown format; fall back on 32bppARGB */
3414 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bmp_source, &source);
3415 gdip_format = PixelFormat32bppARGB;
3416 IWICBitmapSource_Release(bmp_source);
3418 TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format);
3421 if (SUCCEEDED(hr)) /* got source */
3423 hr = IWICBitmapSource_GetSize(source, &width, &height);
3425 if (SUCCEEDED(hr))
3426 status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
3427 NULL, &bitmap);
3429 if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
3431 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
3432 gdip_format, &lockeddata);
3433 if (status == Ok) /* locked bitmap */
3435 wrc.X = 0;
3436 wrc.Width = width;
3437 wrc.Height = 1;
3438 for (i=0; i<height; i++)
3440 wrc.Y = i;
3441 hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
3442 abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
3443 if (FAILED(hr)) break;
3446 GdipBitmapUnlockBits(bitmap, &lockeddata);
3449 if (SUCCEEDED(hr) && status == Ok)
3450 *image = (GpImage*)bitmap;
3451 else
3453 *image = NULL;
3454 GdipDisposeImage((GpImage*)bitmap);
3457 if (SUCCEEDED(hr) && status == Ok)
3459 double dpix, dpiy;
3460 hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy);
3461 if (SUCCEEDED(hr))
3463 bitmap->image.xres = dpix;
3464 bitmap->image.yres = dpiy;
3466 hr = S_OK;
3470 IWICBitmapSource_Release(source);
3473 if (SUCCEEDED(hr)) {
3474 bitmap->metadata_reader = NULL;
3476 if (metadata_reader)
3477 metadata_reader(bitmap, decoder, active_frame);
3478 else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK)
3480 UINT block_count = 0;
3481 if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count)
3482 IWICMetadataBlockReader_GetReaderByIndex(block_reader, 0, &bitmap->metadata_reader);
3483 IWICMetadataBlockReader_Release(block_reader);
3486 palette = get_palette(frame, palette_type);
3487 IWICBitmapFrameDecode_Release(frame);
3491 IWICBitmapDecoder_Release(decoder);
3493 end:
3494 if (SUCCEEDED(initresult)) CoUninitialize();
3496 if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
3498 if (status == Ok)
3500 /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
3501 bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB;
3502 bitmap->image.frame_count = frame_count;
3503 bitmap->image.current_frame = active_frame;
3504 bitmap->image.stream = stream;
3505 if (palette)
3507 GdipFree(bitmap->image.palette);
3508 bitmap->image.palette = palette;
3510 else
3512 if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite))
3513 bitmap->image.palette->Flags = 0;
3515 /* Pin the source stream */
3516 IStream_AddRef(stream);
3517 TRACE("=> %p\n", *image);
3520 return status;
3523 static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3525 return decode_image_wic(stream, &CLSID_WICIcoDecoder, active_frame, NULL, image);
3528 static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3530 GpStatus status;
3531 GpBitmap* bitmap;
3533 status = decode_image_wic(stream, &CLSID_WICBmpDecoder, active_frame, NULL, image);
3535 bitmap = (GpBitmap*)*image;
3537 if (status == Ok && bitmap->format == PixelFormat32bppARGB)
3539 /* WIC supports bmp files with alpha, but gdiplus does not */
3540 bitmap->format = PixelFormat32bppRGB;
3543 return status;
3546 static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3548 return decode_image_wic(stream, &CLSID_WICJpegDecoder, active_frame, NULL, image);
3551 static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3553 return decode_image_wic(stream, &CLSID_WICPngDecoder, active_frame, NULL, image);
3556 static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3558 return decode_image_wic(stream, &CLSID_WICGifDecoder, active_frame, gif_metadata_reader, image);
3561 static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3563 return decode_image_wic(stream, &CLSID_WICTiffDecoder, active_frame, NULL, image);
3566 static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3568 IPicture *pic;
3570 TRACE("%p %p\n", stream, image);
3572 if(!stream || !image)
3573 return InvalidParameter;
3575 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
3576 (LPVOID*) &pic) != S_OK){
3577 TRACE("Could not load picture\n");
3578 return GenericError;
3581 /* FIXME: missing initialization code */
3582 *image = GdipAlloc(sizeof(GpMetafile));
3583 if(!*image) return OutOfMemory;
3584 (*image)->type = ImageTypeMetafile;
3585 (*image)->stream = NULL;
3586 (*image)->picture = pic;
3587 (*image)->flags = ImageFlagsNone;
3588 (*image)->frame_count = 1;
3589 (*image)->current_frame = 0;
3590 (*image)->palette = NULL;
3592 TRACE("<-- %p\n", *image);
3594 return Ok;
3597 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
3598 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
3600 typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, UINT active_frame, GpImage **image);
3602 typedef struct image_codec {
3603 ImageCodecInfo info;
3604 encode_image_func encode_func;
3605 decode_image_func decode_func;
3606 } image_codec;
3608 typedef enum {
3609 BMP,
3610 JPEG,
3611 GIF,
3612 TIFF,
3613 EMF,
3614 WMF,
3615 PNG,
3616 ICO,
3617 NUM_CODECS
3618 } ImageFormat;
3620 static const struct image_codec codecs[NUM_CODECS];
3622 static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
3624 BYTE signature[8];
3625 const BYTE *pattern, *mask;
3626 LARGE_INTEGER seek;
3627 HRESULT hr;
3628 UINT bytesread;
3629 int i;
3630 DWORD j, sig;
3632 /* seek to the start of the stream */
3633 seek.QuadPart = 0;
3634 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
3635 if (FAILED(hr)) return hresult_to_status(hr);
3637 /* read the first 8 bytes */
3638 /* FIXME: This assumes all codecs have signatures <= 8 bytes in length */
3639 hr = IStream_Read(stream, signature, 8, &bytesread);
3640 if (FAILED(hr)) return hresult_to_status(hr);
3641 if (hr == S_FALSE || bytesread == 0) return GenericError;
3643 for (i = 0; i < NUM_CODECS; i++) {
3644 if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
3645 bytesread >= codecs[i].info.SigSize)
3647 for (sig=0; sig<codecs[i].info.SigCount; sig++)
3649 pattern = &codecs[i].info.SigPattern[codecs[i].info.SigSize*sig];
3650 mask = &codecs[i].info.SigMask[codecs[i].info.SigSize*sig];
3651 for (j=0; j<codecs[i].info.SigSize; j++)
3652 if ((signature[j] & mask[j]) != pattern[j])
3653 break;
3654 if (j == codecs[i].info.SigSize)
3656 *result = &codecs[i];
3657 return Ok;
3663 TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
3664 signature[0],signature[1],signature[2],signature[3],
3665 signature[4],signature[5],signature[6],signature[7]);
3667 return GenericError;
3670 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *dimensionID,
3671 UINT frame)
3673 GpStatus stat;
3674 LARGE_INTEGER seek;
3675 HRESULT hr;
3676 const struct image_codec *codec = NULL;
3677 GpImage *new_image;
3679 TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
3681 if (!image || !dimensionID)
3682 return InvalidParameter;
3684 if (frame >= image->frame_count)
3686 WARN("requested frame %u, but image has only %u\n", frame, image->frame_count);
3687 return InvalidParameter;
3690 if (image->type != ImageTypeBitmap && image->type != ImageTypeMetafile)
3692 WARN("invalid image type %d\n", image->type);
3693 return InvalidParameter;
3696 if (image->current_frame == frame)
3697 return Ok;
3699 if (!image->stream)
3701 TRACE("image doesn't have an associated stream\n");
3702 return Ok;
3705 /* choose an appropriate image decoder */
3706 stat = get_decoder_info(image->stream, &codec);
3707 if (stat != Ok)
3709 WARN("can't find decoder info\n");
3710 return stat;
3713 /* seek to the start of the stream */
3714 seek.QuadPart = 0;
3715 hr = IStream_Seek(image->stream, seek, STREAM_SEEK_SET, NULL);
3716 if (FAILED(hr))
3717 return hresult_to_status(hr);
3719 /* call on the image decoder to do the real work */
3720 stat = codec->decode_func(image->stream, &codec->info.Clsid, frame, &new_image);
3722 if (stat == Ok)
3724 memcpy(&new_image->format, &codec->info.FormatID, sizeof(GUID));
3725 free_image_data(image);
3726 if (image->type == ImageTypeBitmap)
3727 *(GpBitmap *)image = *(GpBitmap *)new_image;
3728 else if (image->type == ImageTypeMetafile)
3729 *(GpMetafile *)image = *(GpMetafile *)new_image;
3730 new_image->type = ~0;
3731 GdipFree(new_image);
3732 return Ok;
3735 return stat;
3738 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
3740 GpStatus stat;
3741 LARGE_INTEGER seek;
3742 HRESULT hr;
3743 const struct image_codec *codec=NULL;
3745 /* choose an appropriate image decoder */
3746 stat = get_decoder_info(stream, &codec);
3747 if (stat != Ok) return stat;
3749 /* seek to the start of the stream */
3750 seek.QuadPart = 0;
3751 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
3752 if (FAILED(hr)) return hresult_to_status(hr);
3754 /* call on the image decoder to do the real work */
3755 stat = codec->decode_func(stream, &codec->info.Clsid, 0, image);
3757 /* take note of the original data format */
3758 if (stat == Ok)
3760 memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
3761 return Ok;
3764 return stat;
3767 /* FIXME: no ICM */
3768 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
3770 TRACE("%p %p\n", stream, image);
3772 return GdipLoadImageFromStream(stream, image);
3775 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
3777 static int calls;
3779 TRACE("(%p,%u)\n", image, propId);
3781 if(!image)
3782 return InvalidParameter;
3784 if(!(calls++))
3785 FIXME("not implemented\n");
3787 return NotImplemented;
3790 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
3792 static int calls;
3794 if (!image || !item) return InvalidParameter;
3796 TRACE("(%p,%p:%#x,%u,%u,%p)\n", image, item, item->id, item->type, item->length, item->value);
3798 if(!(calls++))
3799 FIXME("not implemented\n");
3801 return Ok;
3804 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
3805 GDIPCONST CLSID *clsidEncoder,
3806 GDIPCONST EncoderParameters *encoderParams)
3808 GpStatus stat;
3809 IStream *stream;
3811 TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
3813 if (!image || !filename|| !clsidEncoder)
3814 return InvalidParameter;
3816 stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
3817 if (stat != Ok)
3818 return GenericError;
3820 stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
3822 IStream_Release(stream);
3823 return stat;
3826 /*************************************************************************
3827 * Encoding functions -
3828 * These functions encode an image in different image file formats.
3830 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
3831 #define BITMAP_FORMAT_JPEG 0xd8ff
3832 #define BITMAP_FORMAT_GIF 0x4947
3833 #define BITMAP_FORMAT_PNG 0x5089
3834 #define BITMAP_FORMAT_APM 0xcdd7
3836 static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
3837 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
3839 GpStatus stat;
3840 GpBitmap *bitmap;
3841 IWICBitmapEncoder *encoder;
3842 IWICBitmapFrameEncode *frameencode;
3843 IPropertyBag2 *encoderoptions;
3844 HRESULT hr;
3845 UINT width, height;
3846 PixelFormat gdipformat=0;
3847 const WICPixelFormatGUID *desired_wicformat;
3848 WICPixelFormatGUID wicformat;
3849 GpRect rc;
3850 BitmapData lockeddata;
3851 HRESULT initresult;
3852 UINT i;
3854 if (image->type != ImageTypeBitmap)
3855 return GenericError;
3857 bitmap = (GpBitmap*)image;
3859 GdipGetImageWidth(image, &width);
3860 GdipGetImageHeight(image, &height);
3862 rc.X = 0;
3863 rc.Y = 0;
3864 rc.Width = width;
3865 rc.Height = height;
3867 initresult = CoInitialize(NULL);
3869 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
3870 &IID_IWICBitmapEncoder, (void**)&encoder);
3871 if (FAILED(hr))
3873 if (SUCCEEDED(initresult)) CoUninitialize();
3874 return hresult_to_status(hr);
3877 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
3879 if (SUCCEEDED(hr))
3881 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
3884 if (SUCCEEDED(hr)) /* created frame */
3886 hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
3888 if (SUCCEEDED(hr))
3889 hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
3891 if (SUCCEEDED(hr))
3892 hr = IWICBitmapFrameEncode_SetResolution(frameencode, image->xres, image->yres);
3894 if (SUCCEEDED(hr))
3896 for (i=0; pixel_formats[i].wic_format; i++)
3898 if (pixel_formats[i].gdip_format == bitmap->format)
3900 desired_wicformat = pixel_formats[i].wic_format;
3901 gdipformat = bitmap->format;
3902 break;
3905 if (!gdipformat)
3907 desired_wicformat = &GUID_WICPixelFormat32bppBGRA;
3908 gdipformat = PixelFormat32bppARGB;
3911 memcpy(&wicformat, desired_wicformat, sizeof(GUID));
3912 hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
3915 if (SUCCEEDED(hr) && !IsEqualGUID(desired_wicformat, &wicformat))
3917 /* Encoder doesn't support this bitmap's format. */
3918 gdipformat = 0;
3919 for (i=0; pixel_formats[i].wic_format; i++)
3921 if (IsEqualGUID(&wicformat, pixel_formats[i].wic_format))
3923 gdipformat = pixel_formats[i].gdip_format;
3924 break;
3927 if (!gdipformat)
3929 ERR("Cannot support encoder format %s\n", debugstr_guid(&wicformat));
3930 hr = E_FAIL;
3934 if (SUCCEEDED(hr))
3936 stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
3937 &lockeddata);
3939 if (stat == Ok)
3941 UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
3942 BYTE *row;
3944 /* write one row at a time in case stride is negative */
3945 row = lockeddata.Scan0;
3946 for (i=0; i<lockeddata.Height; i++)
3948 hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
3949 if (FAILED(hr)) break;
3950 row += lockeddata.Stride;
3953 GdipBitmapUnlockBits(bitmap, &lockeddata);
3955 else
3956 hr = E_FAIL;
3959 if (SUCCEEDED(hr))
3960 hr = IWICBitmapFrameEncode_Commit(frameencode);
3962 IWICBitmapFrameEncode_Release(frameencode);
3963 IPropertyBag2_Release(encoderoptions);
3966 if (SUCCEEDED(hr))
3967 hr = IWICBitmapEncoder_Commit(encoder);
3969 IWICBitmapEncoder_Release(encoder);
3971 if (SUCCEEDED(initresult)) CoUninitialize();
3973 return hresult_to_status(hr);
3976 static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
3977 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
3979 return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
3982 static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
3983 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
3985 return encode_image_WIC(image, stream, &CLSID_WICTiffEncoder, params);
3988 static GpStatus encode_image_png(GpImage *image, IStream* stream,
3989 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
3991 return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params);
3994 static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
3995 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
3997 return encode_image_WIC(image, stream, &CLSID_WICJpegEncoder, params);
4000 /*****************************************************************************
4001 * GdipSaveImageToStream [GDIPLUS.@]
4003 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
4004 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4006 GpStatus stat;
4007 encode_image_func encode_image;
4008 int i;
4010 TRACE("%p %p %p %p\n", image, stream, clsid, params);
4012 if(!image || !stream)
4013 return InvalidParameter;
4015 /* select correct encoder */
4016 encode_image = NULL;
4017 for (i = 0; i < NUM_CODECS; i++) {
4018 if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
4019 IsEqualCLSID(clsid, &codecs[i].info.Clsid))
4020 encode_image = codecs[i].encode_func;
4022 if (encode_image == NULL)
4023 return UnknownImageFormat;
4025 stat = encode_image(image, stream, clsid, params);
4027 return stat;
4030 /*****************************************************************************
4031 * GdipSaveAdd [GDIPLUS.@]
4033 GpStatus WINGDIPAPI GdipSaveAdd(GpImage *image, GDIPCONST EncoderParameters *params)
4035 FIXME("(%p,%p): stub\n", image, params);
4036 return Ok;
4039 /*****************************************************************************
4040 * GdipGetImagePalette [GDIPLUS.@]
4042 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
4044 INT count;
4046 TRACE("(%p,%p,%i)\n", image, palette, size);
4048 if (!image || !palette)
4049 return InvalidParameter;
4051 count = image->palette ? image->palette->Count : 0;
4053 if (size < (sizeof(UINT)*2+sizeof(ARGB)*count))
4055 TRACE("<-- InsufficientBuffer\n");
4056 return InsufficientBuffer;
4059 if (image->palette)
4061 palette->Flags = image->palette->Flags;
4062 palette->Count = image->palette->Count;
4063 memcpy(palette->Entries, image->palette->Entries, sizeof(ARGB)*image->palette->Count);
4065 else
4067 palette->Flags = 0;
4068 palette->Count = 0;
4070 return Ok;
4073 /*****************************************************************************
4074 * GdipSetImagePalette [GDIPLUS.@]
4076 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
4077 GDIPCONST ColorPalette *palette)
4079 ColorPalette *new_palette;
4081 TRACE("(%p,%p)\n", image, palette);
4083 if(!image || !palette || palette->Count > 256)
4084 return InvalidParameter;
4086 new_palette = GdipAlloc(2 * sizeof(UINT) + palette->Count * sizeof(ARGB));
4087 if (!new_palette) return OutOfMemory;
4089 GdipFree(image->palette);
4090 image->palette = new_palette;
4091 image->palette->Flags = palette->Flags;
4092 image->palette->Count = palette->Count;
4093 memcpy(image->palette->Entries, palette->Entries, sizeof(ARGB)*palette->Count);
4095 return Ok;
4098 /*************************************************************************
4099 * Encoders -
4100 * Structures that represent which formats we support for encoding.
4103 /* ImageCodecInfo creation routines taken from libgdiplus */
4104 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */
4105 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
4106 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
4107 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
4108 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
4109 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
4111 static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
4112 static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
4113 static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
4114 static const WCHAR jpeg_format[] = {'J','P','E','G',0};
4115 static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
4116 static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
4118 static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
4119 static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
4120 static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
4121 static const WCHAR gif_format[] = {'G','I','F',0};
4122 static const BYTE gif_sig_pattern[12] = "GIF87aGIF89a";
4123 static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4125 static const WCHAR tiff_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'T','I','F','F', 0};
4126 static const WCHAR tiff_extension[] = {'*','.','T','I','F','F',';','*','.','T','I','F',0};
4127 static const WCHAR tiff_mimetype[] = {'i','m','a','g','e','/','t','i','f','f', 0};
4128 static const WCHAR tiff_format[] = {'T','I','F','F',0};
4129 static const BYTE tiff_sig_pattern[] = {0x49,0x49,42,0,0x4d,0x4d,0,42};
4130 static const BYTE tiff_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4132 static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
4133 static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
4134 static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
4135 static const WCHAR emf_format[] = {'E','M','F',0};
4136 static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
4137 static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
4139 static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
4140 static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
4141 static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
4142 static const WCHAR wmf_format[] = {'W','M','F',0};
4143 static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
4144 static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
4146 static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
4147 static const WCHAR png_extension[] = {'*','.','P','N','G',0};
4148 static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
4149 static const WCHAR png_format[] = {'P','N','G',0};
4150 static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
4151 static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4153 static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
4154 static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
4155 static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
4156 static const WCHAR ico_format[] = {'I','C','O',0};
4157 static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
4158 static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
4160 static const struct image_codec codecs[NUM_CODECS] = {
4162 { /* BMP */
4163 /* Clsid */ { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4164 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4165 /* CodecName */ bmp_codecname,
4166 /* DllName */ NULL,
4167 /* FormatDescription */ bmp_format,
4168 /* FilenameExtension */ bmp_extension,
4169 /* MimeType */ bmp_mimetype,
4170 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4171 /* Version */ 1,
4172 /* SigCount */ 1,
4173 /* SigSize */ 2,
4174 /* SigPattern */ bmp_sig_pattern,
4175 /* SigMask */ bmp_sig_mask,
4177 encode_image_BMP,
4178 decode_image_bmp
4181 { /* JPEG */
4182 /* Clsid */ { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4183 /* FormatID */ { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4184 /* CodecName */ jpeg_codecname,
4185 /* DllName */ NULL,
4186 /* FormatDescription */ jpeg_format,
4187 /* FilenameExtension */ jpeg_extension,
4188 /* MimeType */ jpeg_mimetype,
4189 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4190 /* Version */ 1,
4191 /* SigCount */ 1,
4192 /* SigSize */ 2,
4193 /* SigPattern */ jpeg_sig_pattern,
4194 /* SigMask */ jpeg_sig_mask,
4196 encode_image_jpeg,
4197 decode_image_jpeg
4200 { /* GIF */
4201 /* Clsid */ { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4202 /* FormatID */ { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4203 /* CodecName */ gif_codecname,
4204 /* DllName */ NULL,
4205 /* FormatDescription */ gif_format,
4206 /* FilenameExtension */ gif_extension,
4207 /* MimeType */ gif_mimetype,
4208 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4209 /* Version */ 1,
4210 /* SigCount */ 2,
4211 /* SigSize */ 6,
4212 /* SigPattern */ gif_sig_pattern,
4213 /* SigMask */ gif_sig_mask,
4215 NULL,
4216 decode_image_gif
4219 { /* TIFF */
4220 /* Clsid */ { 0x557cf405, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4221 /* FormatID */ { 0xb96b3cb1U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4222 /* CodecName */ tiff_codecname,
4223 /* DllName */ NULL,
4224 /* FormatDescription */ tiff_format,
4225 /* FilenameExtension */ tiff_extension,
4226 /* MimeType */ tiff_mimetype,
4227 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsEncoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4228 /* Version */ 1,
4229 /* SigCount */ 2,
4230 /* SigSize */ 4,
4231 /* SigPattern */ tiff_sig_pattern,
4232 /* SigMask */ tiff_sig_mask,
4234 encode_image_tiff,
4235 decode_image_tiff
4238 { /* EMF */
4239 /* Clsid */ { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4240 /* FormatID */ { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4241 /* CodecName */ emf_codecname,
4242 /* DllName */ NULL,
4243 /* FormatDescription */ emf_format,
4244 /* FilenameExtension */ emf_extension,
4245 /* MimeType */ emf_mimetype,
4246 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
4247 /* Version */ 1,
4248 /* SigCount */ 1,
4249 /* SigSize */ 4,
4250 /* SigPattern */ emf_sig_pattern,
4251 /* SigMask */ emf_sig_mask,
4253 NULL,
4254 decode_image_olepicture_metafile
4257 { /* WMF */
4258 /* Clsid */ { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4259 /* FormatID */ { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4260 /* CodecName */ wmf_codecname,
4261 /* DllName */ NULL,
4262 /* FormatDescription */ wmf_format,
4263 /* FilenameExtension */ wmf_extension,
4264 /* MimeType */ wmf_mimetype,
4265 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
4266 /* Version */ 1,
4267 /* SigCount */ 1,
4268 /* SigSize */ 2,
4269 /* SigPattern */ wmf_sig_pattern,
4270 /* SigMask */ wmf_sig_mask,
4272 NULL,
4273 decode_image_olepicture_metafile
4276 { /* PNG */
4277 /* Clsid */ { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4278 /* FormatID */ { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4279 /* CodecName */ png_codecname,
4280 /* DllName */ NULL,
4281 /* FormatDescription */ png_format,
4282 /* FilenameExtension */ png_extension,
4283 /* MimeType */ png_mimetype,
4284 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4285 /* Version */ 1,
4286 /* SigCount */ 1,
4287 /* SigSize */ 8,
4288 /* SigPattern */ png_sig_pattern,
4289 /* SigMask */ png_sig_mask,
4291 encode_image_png,
4292 decode_image_png
4295 { /* ICO */
4296 /* Clsid */ { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4297 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4298 /* CodecName */ ico_codecname,
4299 /* DllName */ NULL,
4300 /* FormatDescription */ ico_format,
4301 /* FilenameExtension */ ico_extension,
4302 /* MimeType */ ico_mimetype,
4303 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4304 /* Version */ 1,
4305 /* SigCount */ 1,
4306 /* SigSize */ 4,
4307 /* SigPattern */ ico_sig_pattern,
4308 /* SigMask */ ico_sig_mask,
4310 NULL,
4311 decode_image_icon
4315 /*****************************************************************************
4316 * GdipGetImageDecodersSize [GDIPLUS.@]
4318 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
4320 int decoder_count=0;
4321 int i;
4322 TRACE("%p %p\n", numDecoders, size);
4324 if (!numDecoders || !size)
4325 return InvalidParameter;
4327 for (i=0; i<NUM_CODECS; i++)
4329 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
4330 decoder_count++;
4333 *numDecoders = decoder_count;
4334 *size = decoder_count * sizeof(ImageCodecInfo);
4336 return Ok;
4339 /*****************************************************************************
4340 * GdipGetImageDecoders [GDIPLUS.@]
4342 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
4344 int i, decoder_count=0;
4345 TRACE("%u %u %p\n", numDecoders, size, decoders);
4347 if (!decoders ||
4348 size != numDecoders * sizeof(ImageCodecInfo))
4349 return GenericError;
4351 for (i=0; i<NUM_CODECS; i++)
4353 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
4355 if (decoder_count == numDecoders) return GenericError;
4356 memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
4357 decoder_count++;
4361 if (decoder_count < numDecoders) return GenericError;
4363 return Ok;
4366 /*****************************************************************************
4367 * GdipGetImageEncodersSize [GDIPLUS.@]
4369 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
4371 int encoder_count=0;
4372 int i;
4373 TRACE("%p %p\n", numEncoders, size);
4375 if (!numEncoders || !size)
4376 return InvalidParameter;
4378 for (i=0; i<NUM_CODECS; i++)
4380 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
4381 encoder_count++;
4384 *numEncoders = encoder_count;
4385 *size = encoder_count * sizeof(ImageCodecInfo);
4387 return Ok;
4390 /*****************************************************************************
4391 * GdipGetImageEncoders [GDIPLUS.@]
4393 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
4395 int i, encoder_count=0;
4396 TRACE("%u %u %p\n", numEncoders, size, encoders);
4398 if (!encoders ||
4399 size != numEncoders * sizeof(ImageCodecInfo))
4400 return GenericError;
4402 for (i=0; i<NUM_CODECS; i++)
4404 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
4406 if (encoder_count == numEncoders) return GenericError;
4407 memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
4408 encoder_count++;
4412 if (encoder_count < numEncoders) return GenericError;
4414 return Ok;
4417 GpStatus WINGDIPAPI GdipGetEncoderParameterListSize(GpImage *image,
4418 GDIPCONST CLSID* clsidEncoder, UINT *size)
4420 static int calls;
4422 TRACE("(%p,%s,%p)\n", image, debugstr_guid(clsidEncoder), size);
4424 if(!(calls++))
4425 FIXME("not implemented\n");
4427 *size = 0;
4429 return NotImplemented;
4432 static PixelFormat get_16bpp_format(HBITMAP hbm)
4434 BITMAPV4HEADER bmh;
4435 HDC hdc;
4436 PixelFormat result;
4438 hdc = CreateCompatibleDC(NULL);
4440 memset(&bmh, 0, sizeof(bmh));
4441 bmh.bV4Size = sizeof(bmh);
4442 bmh.bV4Width = 1;
4443 bmh.bV4Height = 1;
4444 bmh.bV4V4Compression = BI_BITFIELDS;
4445 bmh.bV4BitCount = 16;
4447 GetDIBits(hdc, hbm, 0, 0, NULL, (BITMAPINFO*)&bmh, DIB_RGB_COLORS);
4449 if (bmh.bV4RedMask == 0x7c00 &&
4450 bmh.bV4GreenMask == 0x3e0 &&
4451 bmh.bV4BlueMask == 0x1f)
4453 result = PixelFormat16bppRGB555;
4455 else if (bmh.bV4RedMask == 0xf800 &&
4456 bmh.bV4GreenMask == 0x7e0 &&
4457 bmh.bV4BlueMask == 0x1f)
4459 result = PixelFormat16bppRGB565;
4461 else
4463 FIXME("unrecognized bitfields %x,%x,%x\n", bmh.bV4RedMask,
4464 bmh.bV4GreenMask, bmh.bV4BlueMask);
4465 result = PixelFormatUndefined;
4468 DeleteDC(hdc);
4470 return result;
4473 /*****************************************************************************
4474 * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
4476 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
4478 BITMAP bm;
4479 GpStatus retval;
4480 PixelFormat format;
4481 BitmapData lockeddata;
4483 TRACE("%p %p %p\n", hbm, hpal, bitmap);
4485 if(!hbm || !bitmap)
4486 return InvalidParameter;
4488 if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm))
4489 return InvalidParameter;
4491 /* TODO: Figure out the correct format for 16, 32, 64 bpp */
4492 switch(bm.bmBitsPixel) {
4493 case 1:
4494 format = PixelFormat1bppIndexed;
4495 break;
4496 case 4:
4497 format = PixelFormat4bppIndexed;
4498 break;
4499 case 8:
4500 format = PixelFormat8bppIndexed;
4501 break;
4502 case 16:
4503 format = get_16bpp_format(hbm);
4504 if (format == PixelFormatUndefined)
4505 return InvalidParameter;
4506 break;
4507 case 24:
4508 format = PixelFormat24bppRGB;
4509 break;
4510 case 32:
4511 format = PixelFormat32bppRGB;
4512 break;
4513 case 48:
4514 format = PixelFormat48bppRGB;
4515 break;
4516 default:
4517 FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel);
4518 return InvalidParameter;
4521 retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, 0,
4522 format, NULL, bitmap);
4524 if (retval == Ok)
4526 retval = GdipBitmapLockBits(*bitmap, NULL, ImageLockModeWrite,
4527 format, &lockeddata);
4528 if (retval == Ok)
4530 HDC hdc;
4531 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
4532 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
4533 INT src_height;
4535 hdc = CreateCompatibleDC(NULL);
4537 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
4538 pbmi->bmiHeader.biBitCount = 0;
4540 GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
4542 src_height = abs(pbmi->bmiHeader.biHeight);
4543 pbmi->bmiHeader.biHeight = -src_height;
4545 GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
4547 DeleteDC(hdc);
4549 GdipBitmapUnlockBits(*bitmap, &lockeddata);
4552 if (retval == Ok && hpal)
4554 PALETTEENTRY entry[256];
4555 ColorPalette *palette=NULL;
4556 int i, num_palette_entries;
4558 num_palette_entries = GetPaletteEntries(hpal, 0, 256, entry);
4559 if (!num_palette_entries)
4560 retval = GenericError;
4562 palette = GdipAlloc(sizeof(ColorPalette) + sizeof(ARGB) * (num_palette_entries-1));
4563 if (!palette)
4564 retval = OutOfMemory;
4566 if (retval == Ok)
4568 palette->Flags = 0;
4569 palette->Count = num_palette_entries;
4571 for (i=0; i<num_palette_entries; i++)
4573 palette->Entries[i] = 0xff000000 | entry[i].peRed << 16 |
4574 entry[i].peGreen << 8 | entry[i].peBlue;
4577 retval = GdipSetImagePalette((GpImage*)*bitmap, palette);
4580 GdipFree(palette);
4583 if (retval != Ok)
4585 GdipDisposeImage((GpImage*)*bitmap);
4586 *bitmap = NULL;
4590 return retval;
4593 GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect)
4595 FIXME("(%p): stub\n", effect);
4596 /* note: According to Jose Roca's GDI+ Docs, this is not implemented
4597 * in Windows's gdiplus */
4598 return NotImplemented;
4601 /*****************************************************************************
4602 * GdipSetEffectParameters [GDIPLUS.@]
4604 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
4605 const VOID *params, const UINT size)
4607 static int calls;
4609 TRACE("(%p,%p,%u)\n", effect, params, size);
4611 if(!(calls++))
4612 FIXME("not implemented\n");
4614 return NotImplemented;
4617 /*****************************************************************************
4618 * GdipGetImageFlags [GDIPLUS.@]
4620 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
4622 TRACE("%p %p\n", image, flags);
4624 if(!image || !flags)
4625 return InvalidParameter;
4627 *flags = image->flags;
4629 return Ok;
4632 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
4634 TRACE("(%d, %p)\n", control, param);
4636 switch(control){
4637 case TestControlForceBilinear:
4638 if(param)
4639 FIXME("TestControlForceBilinear not handled\n");
4640 break;
4641 case TestControlNoICM:
4642 if(param)
4643 FIXME("TestControlNoICM not handled\n");
4644 break;
4645 case TestControlGetBuildNumber:
4646 *((DWORD*)param) = 3102;
4647 break;
4650 return Ok;
4653 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
4655 TRACE("%p\n", image);
4657 return Ok;
4660 /*****************************************************************************
4661 * GdipGetImageThumbnail [GDIPLUS.@]
4663 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
4664 GpImage **ret_image, GetThumbnailImageAbort cb,
4665 VOID * cb_data)
4667 GpStatus stat;
4668 GpGraphics *graphics;
4669 UINT srcwidth, srcheight;
4671 TRACE("(%p %u %u %p %p %p)\n",
4672 image, width, height, ret_image, cb, cb_data);
4674 if (!image || !ret_image)
4675 return InvalidParameter;
4677 if (!width) width = 120;
4678 if (!height) height = 120;
4680 GdipGetImageWidth(image, &srcwidth);
4681 GdipGetImageHeight(image, &srcheight);
4683 stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
4684 NULL, (GpBitmap**)ret_image);
4686 if (stat == Ok)
4688 stat = GdipGetImageGraphicsContext(*ret_image, &graphics);
4690 if (stat == Ok)
4692 stat = GdipDrawImageRectRectI(graphics, image,
4693 0, 0, width, height, 0, 0, srcwidth, srcheight, UnitPixel,
4694 NULL, NULL, NULL);
4696 GdipDeleteGraphics(graphics);
4699 if (stat != Ok)
4701 GdipDisposeImage(*ret_image);
4702 *ret_image = NULL;
4706 return stat;
4709 /*****************************************************************************
4710 * GdipImageRotateFlip [GDIPLUS.@]
4712 GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
4714 GpBitmap *new_bitmap;
4715 GpBitmap *bitmap;
4716 int bpp, bytesperpixel;
4717 int rotate_90, flip_x, flip_y;
4718 int src_x_offset, src_y_offset;
4719 LPBYTE src_origin;
4720 UINT x, y, width, height;
4721 BitmapData src_lock, dst_lock;
4722 GpStatus stat;
4724 TRACE("(%p, %u)\n", image, type);
4726 if (!image)
4727 return InvalidParameter;
4729 rotate_90 = type&1;
4730 flip_x = (type&6) == 2 || (type&6) == 4;
4731 flip_y = (type&3) == 1 || (type&3) == 2;
4733 if (image->type != ImageTypeBitmap)
4735 FIXME("Not implemented for type %i\n", image->type);
4736 return NotImplemented;
4739 bitmap = (GpBitmap*)image;
4740 bpp = PIXELFORMATBPP(bitmap->format);
4742 if (bpp < 8)
4744 FIXME("Not implemented for %i bit images\n", bpp);
4745 return NotImplemented;
4748 if (rotate_90)
4750 width = bitmap->height;
4751 height = bitmap->width;
4753 else
4755 width = bitmap->width;
4756 height = bitmap->height;
4759 bytesperpixel = bpp/8;
4761 stat = GdipCreateBitmapFromScan0(width, height, 0, bitmap->format, NULL, &new_bitmap);
4763 if (stat != Ok)
4764 return stat;
4766 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format, &src_lock);
4768 if (stat == Ok)
4770 stat = GdipBitmapLockBits(new_bitmap, NULL, ImageLockModeWrite, bitmap->format, &dst_lock);
4772 if (stat == Ok)
4774 LPBYTE src_row, src_pixel;
4775 LPBYTE dst_row, dst_pixel;
4777 src_origin = src_lock.Scan0;
4778 if (flip_x) src_origin += bytesperpixel * (bitmap->width - 1);
4779 if (flip_y) src_origin += src_lock.Stride * (bitmap->height - 1);
4781 if (rotate_90)
4783 if (flip_y) src_x_offset = -src_lock.Stride;
4784 else src_x_offset = src_lock.Stride;
4785 if (flip_x) src_y_offset = -bytesperpixel;
4786 else src_y_offset = bytesperpixel;
4788 else
4790 if (flip_x) src_x_offset = -bytesperpixel;
4791 else src_x_offset = bytesperpixel;
4792 if (flip_y) src_y_offset = -src_lock.Stride;
4793 else src_y_offset = src_lock.Stride;
4796 src_row = src_origin;
4797 dst_row = dst_lock.Scan0;
4798 for (y=0; y<height; y++)
4800 src_pixel = src_row;
4801 dst_pixel = dst_row;
4802 for (x=0; x<width; x++)
4804 /* FIXME: This could probably be faster without memcpy. */
4805 memcpy(dst_pixel, src_pixel, bytesperpixel);
4806 dst_pixel += bytesperpixel;
4807 src_pixel += src_x_offset;
4809 src_row += src_y_offset;
4810 dst_row += dst_lock.Stride;
4813 GdipBitmapUnlockBits(new_bitmap, &dst_lock);
4816 GdipBitmapUnlockBits(bitmap, &src_lock);
4819 if (stat == Ok)
4820 move_bitmap(bitmap, new_bitmap, FALSE);
4821 else
4822 GdipDisposeImage((GpImage*)new_bitmap);
4824 return stat;