gdiplus: Don't use CoCreateInstance in encode_image_wic.
[wine/multimedia.git] / dlls / gdiplus / image.c
bloba7f4385670ef84cae202f9c6d8ce0e400b637a0a
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 HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
45 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
47 static const struct
49 const WICPixelFormatGUID *wic_format;
50 PixelFormat gdip_format;
51 /* predefined palette type to use for pixel format conversions */
52 WICBitmapPaletteType palette_type;
53 } pixel_formats[] =
55 { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
56 { &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
57 { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 },
58 { &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedHalftone256 },
59 { &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555, WICBitmapPaletteTypeFixedHalftone256 },
60 { &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
61 { &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
62 { &GUID_WICPixelFormat32bppBGRA, PixelFormat32bppARGB, WICBitmapPaletteTypeFixedHalftone256 },
63 { &GUID_WICPixelFormat32bppPBGRA, PixelFormat32bppPARGB, WICBitmapPaletteTypeFixedHalftone256 },
64 { NULL }
67 static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteType palette_type)
69 HRESULT hr;
70 IWICImagingFactory *factory;
71 IWICPalette *wic_palette;
72 ColorPalette *palette = NULL;
74 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
75 if (hr != S_OK) return NULL;
77 hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
78 if (hr == S_OK)
80 hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
81 if (frame)
82 hr = IWICBitmapFrameDecode_CopyPalette(frame, wic_palette);
83 if (hr != S_OK)
85 TRACE("using predefined palette %#x\n", palette_type);
86 hr = IWICPalette_InitializePredefined(wic_palette, palette_type, FALSE);
88 if (hr == S_OK)
90 UINT count;
91 BOOL mono, gray;
93 IWICPalette_IsBlackWhite(wic_palette, &mono);
94 IWICPalette_IsGrayscale(wic_palette, &gray);
96 IWICPalette_GetColorCount(wic_palette, &count);
97 palette = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(UINT) + count * sizeof(ARGB));
98 IWICPalette_GetColors(wic_palette, count, palette->Entries, &palette->Count);
100 if (mono)
101 palette->Flags = 0;
102 else if (gray)
103 palette->Flags = PaletteFlagsGrayScale;
104 else
105 palette->Flags = PaletteFlagsHalftone;
107 IWICPalette_Release(wic_palette);
109 IWICImagingFactory_Release(factory);
110 return palette;
113 static INT ipicture_pixel_height(IPicture *pic)
115 HDC hdcref;
116 OLE_YSIZE_HIMETRIC y;
118 IPicture_get_Height(pic, &y);
120 hdcref = CreateCompatibleDC(0);
121 y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
122 DeleteDC(hdcref);
124 return y;
127 static INT ipicture_pixel_width(IPicture *pic)
129 HDC hdcref;
130 OLE_XSIZE_HIMETRIC x;
132 IPicture_get_Width(pic, &x);
134 hdcref = CreateCompatibleDC(0);
135 x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
136 DeleteDC(hdcref);
138 return x;
141 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
142 RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
144 FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
146 * Note: According to Jose Roca's GDI+ docs, this function is not
147 * implemented in Windows's GDI+.
149 return NotImplemented;
152 GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
153 INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
154 GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
156 FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
158 * Note: According to Jose Roca's GDI+ docs, this function is not
159 * implemented in Windows's GDI+.
161 return NotImplemented;
164 static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
166 *index = (row[x/8]>>(7-x%8)) & 1;
169 static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x)
171 if (x & 1)
172 *index = row[x/2]&0xf;
173 else
174 *index = row[x/2]>>4;
177 static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
179 *index = row[x];
182 static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
183 const BYTE *row, UINT x)
185 *r = *g = *b = row[x*2+1];
186 *a = 255;
189 static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
190 const BYTE *row, UINT x)
192 WORD pixel = *((const WORD*)(row)+x);
193 *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
194 *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
195 *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
196 *a = 255;
199 static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
200 const BYTE *row, UINT x)
202 WORD pixel = *((const WORD*)(row)+x);
203 *r = (pixel>>8&0xf8)|(pixel>>13&0x7);
204 *g = (pixel>>3&0xfc)|(pixel>>9&0x3);
205 *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
206 *a = 255;
209 static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
210 const BYTE *row, UINT x)
212 WORD pixel = *((const WORD*)(row)+x);
213 *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
214 *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
215 *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
216 if ((pixel&0x8000) == 0x8000)
217 *a = 255;
218 else
219 *a = 0;
222 static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
223 const BYTE *row, UINT x)
225 *r = row[x*3+2];
226 *g = row[x*3+1];
227 *b = row[x*3];
228 *a = 255;
231 static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
232 const BYTE *row, UINT x)
234 *r = row[x*4+2];
235 *g = row[x*4+1];
236 *b = row[x*4];
237 *a = 255;
240 static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
241 const BYTE *row, UINT x)
243 *r = row[x*4+2];
244 *g = row[x*4+1];
245 *b = row[x*4];
246 *a = row[x*4+3];
249 static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
250 const BYTE *row, UINT x)
252 *a = row[x*4+3];
253 if (*a == 0)
254 *r = *g = *b = 0;
255 else
257 *r = row[x*4+2] * 255 / *a;
258 *g = row[x*4+1] * 255 / *a;
259 *b = row[x*4] * 255 / *a;
263 static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
264 const BYTE *row, UINT x)
266 *r = row[x*6+5];
267 *g = row[x*6+3];
268 *b = row[x*6+1];
269 *a = 255;
272 static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
273 const BYTE *row, UINT x)
275 *r = row[x*8+5];
276 *g = row[x*8+3];
277 *b = row[x*8+1];
278 *a = row[x*8+7];
281 static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
282 const BYTE *row, UINT x)
284 *a = row[x*8+7];
285 if (*a == 0)
286 *r = *g = *b = 0;
287 else
289 *r = row[x*8+5] * 255 / *a;
290 *g = row[x*8+3] * 255 / *a;
291 *b = row[x*8+1] * 255 / *a;
295 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
296 ARGB *color)
298 BYTE r, g, b, a;
299 BYTE index;
300 BYTE *row;
302 if(!bitmap || !color ||
303 x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
304 return InvalidParameter;
306 row = bitmap->bits+bitmap->stride*y;
308 switch (bitmap->format)
310 case PixelFormat1bppIndexed:
311 getpixel_1bppIndexed(&index,row,x);
312 break;
313 case PixelFormat4bppIndexed:
314 getpixel_4bppIndexed(&index,row,x);
315 break;
316 case PixelFormat8bppIndexed:
317 getpixel_8bppIndexed(&index,row,x);
318 break;
319 case PixelFormat16bppGrayScale:
320 getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
321 break;
322 case PixelFormat16bppRGB555:
323 getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
324 break;
325 case PixelFormat16bppRGB565:
326 getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
327 break;
328 case PixelFormat16bppARGB1555:
329 getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
330 break;
331 case PixelFormat24bppRGB:
332 getpixel_24bppRGB(&r,&g,&b,&a,row,x);
333 break;
334 case PixelFormat32bppRGB:
335 getpixel_32bppRGB(&r,&g,&b,&a,row,x);
336 break;
337 case PixelFormat32bppARGB:
338 getpixel_32bppARGB(&r,&g,&b,&a,row,x);
339 break;
340 case PixelFormat32bppPARGB:
341 getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
342 break;
343 case PixelFormat48bppRGB:
344 getpixel_48bppRGB(&r,&g,&b,&a,row,x);
345 break;
346 case PixelFormat64bppARGB:
347 getpixel_64bppARGB(&r,&g,&b,&a,row,x);
348 break;
349 case PixelFormat64bppPARGB:
350 getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
351 break;
352 default:
353 FIXME("not implemented for format 0x%x\n", bitmap->format);
354 return NotImplemented;
357 if (bitmap->format & PixelFormatIndexed)
358 *color = bitmap->image.palette->Entries[index];
359 else
360 *color = a<<24|r<<16|g<<8|b;
362 return Ok;
365 static inline UINT get_palette_index(BYTE r, BYTE g, BYTE b, BYTE a, ColorPalette *palette)
367 BYTE index = 0;
368 int best_distance = 0x7fff;
369 int distance;
370 UINT i;
372 if (!palette) return 0;
373 /* This algorithm scans entire palette,
374 computes difference from desired color (all color components have equal weight)
375 and returns the index of color with least difference.
377 Note: Maybe it could be replaced with a better algorithm for better image quality
378 and performance, though better algorithm would probably need some pre-built lookup
379 tables and thus may actually be slower if this method is called only few times per
380 every image.
382 for(i=0;i<palette->Count;i++) {
383 ARGB color=palette->Entries[i];
384 distance=abs(b-(color & 0xff)) + abs(g-(color>>8 & 0xff)) + abs(r-(color>>16 & 0xff)) + abs(a-(color>>24 & 0xff));
385 if (distance<best_distance) {
386 best_distance=distance;
387 index=i;
390 return index;
393 static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
394 BYTE *row, UINT x, ColorPalette *palette)
396 BYTE index = get_palette_index(r,g,b,a,palette);
397 row[x]=index;
400 static inline void setpixel_1bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
401 BYTE *row, UINT x, ColorPalette *palette)
403 row[x/8] = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,palette)<<(7-x%8));
406 static inline void setpixel_4bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
407 BYTE *row, UINT x, ColorPalette *palette)
409 if (x & 1)
410 row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,palette);
411 else
412 row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,palette)<<4;
415 static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
416 BYTE *row, UINT x)
418 *((WORD*)(row)+x) = (r+g+b)*85;
421 static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
422 BYTE *row, UINT x)
424 *((WORD*)(row)+x) = (r<<7&0x7c00)|
425 (g<<2&0x03e0)|
426 (b>>3&0x001f);
429 static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
430 BYTE *row, UINT x)
432 *((WORD*)(row)+x) = (r<<8&0xf800)|
433 (g<<3&0x07e0)|
434 (b>>3&0x001f);
437 static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
438 BYTE *row, UINT x)
440 *((WORD*)(row)+x) = (a<<8&0x8000)|
441 (r<<7&0x7c00)|
442 (g<<2&0x03e0)|
443 (b>>3&0x001f);
446 static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
447 BYTE *row, UINT x)
449 row[x*3+2] = r;
450 row[x*3+1] = g;
451 row[x*3] = b;
454 static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
455 BYTE *row, UINT x)
457 *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
460 static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
461 BYTE *row, UINT x)
463 *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
466 static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
467 BYTE *row, UINT x)
469 r = r * a / 255;
470 g = g * a / 255;
471 b = b * a / 255;
472 *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
475 static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
476 BYTE *row, UINT x)
478 row[x*6+5] = row[x*6+4] = r;
479 row[x*6+3] = row[x*6+2] = g;
480 row[x*6+1] = row[x*6] = b;
483 static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
484 BYTE *row, UINT x)
486 UINT64 a64=a, r64=r, g64=g, b64=b;
487 *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
490 static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
491 BYTE *row, UINT x)
493 UINT64 a64, r64, g64, b64;
494 a64 = a * 257;
495 r64 = r * a / 255;
496 g64 = g * a / 255;
497 b64 = b * a / 255;
498 *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
501 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
502 ARGB color)
504 BYTE a, r, g, b;
505 BYTE *row;
507 if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
508 return InvalidParameter;
510 a = color>>24;
511 r = color>>16;
512 g = color>>8;
513 b = color;
515 row = bitmap->bits + bitmap->stride * y;
517 switch (bitmap->format)
519 case PixelFormat16bppGrayScale:
520 setpixel_16bppGrayScale(r,g,b,a,row,x);
521 break;
522 case PixelFormat16bppRGB555:
523 setpixel_16bppRGB555(r,g,b,a,row,x);
524 break;
525 case PixelFormat16bppRGB565:
526 setpixel_16bppRGB565(r,g,b,a,row,x);
527 break;
528 case PixelFormat16bppARGB1555:
529 setpixel_16bppARGB1555(r,g,b,a,row,x);
530 break;
531 case PixelFormat24bppRGB:
532 setpixel_24bppRGB(r,g,b,a,row,x);
533 break;
534 case PixelFormat32bppRGB:
535 setpixel_32bppRGB(r,g,b,a,row,x);
536 break;
537 case PixelFormat32bppARGB:
538 setpixel_32bppARGB(r,g,b,a,row,x);
539 break;
540 case PixelFormat32bppPARGB:
541 setpixel_32bppPARGB(r,g,b,a,row,x);
542 break;
543 case PixelFormat48bppRGB:
544 setpixel_48bppRGB(r,g,b,a,row,x);
545 break;
546 case PixelFormat64bppARGB:
547 setpixel_64bppARGB(r,g,b,a,row,x);
548 break;
549 case PixelFormat64bppPARGB:
550 setpixel_64bppPARGB(r,g,b,a,row,x);
551 break;
552 case PixelFormat8bppIndexed:
553 setpixel_8bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
554 break;
555 case PixelFormat4bppIndexed:
556 setpixel_4bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
557 break;
558 case PixelFormat1bppIndexed:
559 setpixel_1bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
560 break;
561 default:
562 FIXME("not implemented for format 0x%x\n", bitmap->format);
563 return NotImplemented;
566 return Ok;
569 GpStatus convert_pixels(INT width, INT height,
570 INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
571 INT src_stride, const BYTE *src_bits, PixelFormat src_format,
572 ColorPalette *palette)
574 INT x, y;
576 if (src_format == dst_format ||
577 (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32))
579 UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8;
580 for (y=0; y<height; y++)
581 memcpy(dst_bits+dst_stride*y, src_bits+src_stride*y, widthbytes);
582 return Ok;
585 #define convert_indexed_to_rgb(getpixel_function, setpixel_function) do { \
586 for (y=0; y<height; y++) \
587 for (x=0; x<width; x++) { \
588 BYTE index; \
589 ARGB argb; \
590 BYTE *color = (BYTE *)&argb; \
591 getpixel_function(&index, src_bits+src_stride*y, x); \
592 argb = (palette && index < palette->Count) ? palette->Entries[index] : 0; \
593 setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
595 return Ok; \
596 } while (0);
598 #define convert_rgb_to_rgb(getpixel_function, setpixel_function) do { \
599 for (y=0; y<height; y++) \
600 for (x=0; x<width; x++) { \
601 BYTE r, g, b, a; \
602 getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
603 setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x); \
605 return Ok; \
606 } while (0);
608 #define convert_rgb_to_indexed(getpixel_function, setpixel_function) do { \
609 for (y=0; y<height; y++) \
610 for (x=0; x<width; x++) { \
611 BYTE r, g, b, a; \
612 getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
613 setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x, palette); \
615 return Ok; \
616 } while (0);
618 switch (src_format)
620 case PixelFormat1bppIndexed:
621 switch (dst_format)
623 case PixelFormat16bppGrayScale:
624 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppGrayScale);
625 case PixelFormat16bppRGB555:
626 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB555);
627 case PixelFormat16bppRGB565:
628 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB565);
629 case PixelFormat16bppARGB1555:
630 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppARGB1555);
631 case PixelFormat24bppRGB:
632 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_24bppRGB);
633 case PixelFormat32bppRGB:
634 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppRGB);
635 case PixelFormat32bppARGB:
636 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppARGB);
637 case PixelFormat32bppPARGB:
638 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppPARGB);
639 case PixelFormat48bppRGB:
640 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_48bppRGB);
641 case PixelFormat64bppARGB:
642 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_64bppARGB);
643 default:
644 break;
646 break;
647 case PixelFormat4bppIndexed:
648 switch (dst_format)
650 case PixelFormat16bppGrayScale:
651 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppGrayScale);
652 case PixelFormat16bppRGB555:
653 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB555);
654 case PixelFormat16bppRGB565:
655 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB565);
656 case PixelFormat16bppARGB1555:
657 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppARGB1555);
658 case PixelFormat24bppRGB:
659 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_24bppRGB);
660 case PixelFormat32bppRGB:
661 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppRGB);
662 case PixelFormat32bppARGB:
663 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppARGB);
664 case PixelFormat32bppPARGB:
665 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppPARGB);
666 case PixelFormat48bppRGB:
667 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_48bppRGB);
668 case PixelFormat64bppARGB:
669 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_64bppARGB);
670 default:
671 break;
673 break;
674 case PixelFormat8bppIndexed:
675 switch (dst_format)
677 case PixelFormat16bppGrayScale:
678 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppGrayScale);
679 case PixelFormat16bppRGB555:
680 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB555);
681 case PixelFormat16bppRGB565:
682 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB565);
683 case PixelFormat16bppARGB1555:
684 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppARGB1555);
685 case PixelFormat24bppRGB:
686 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_24bppRGB);
687 case PixelFormat32bppRGB:
688 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppRGB);
689 case PixelFormat32bppARGB:
690 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppARGB);
691 case PixelFormat32bppPARGB:
692 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppPARGB);
693 case PixelFormat48bppRGB:
694 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_48bppRGB);
695 case PixelFormat64bppARGB:
696 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_64bppARGB);
697 default:
698 break;
700 break;
701 case PixelFormat16bppGrayScale:
702 switch (dst_format)
704 case PixelFormat1bppIndexed:
705 convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_1bppIndexed);
706 case PixelFormat8bppIndexed:
707 convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_8bppIndexed);
708 case PixelFormat16bppRGB555:
709 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB555);
710 case PixelFormat16bppRGB565:
711 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB565);
712 case PixelFormat16bppARGB1555:
713 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppARGB1555);
714 case PixelFormat24bppRGB:
715 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_24bppRGB);
716 case PixelFormat32bppRGB:
717 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppRGB);
718 case PixelFormat32bppARGB:
719 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppARGB);
720 case PixelFormat32bppPARGB:
721 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppPARGB);
722 case PixelFormat48bppRGB:
723 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_48bppRGB);
724 case PixelFormat64bppARGB:
725 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_64bppARGB);
726 default:
727 break;
729 break;
730 case PixelFormat16bppRGB555:
731 switch (dst_format)
733 case PixelFormat1bppIndexed:
734 convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_1bppIndexed);
735 case PixelFormat8bppIndexed:
736 convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_8bppIndexed);
737 case PixelFormat16bppGrayScale:
738 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppGrayScale);
739 case PixelFormat16bppRGB565:
740 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppRGB565);
741 case PixelFormat16bppARGB1555:
742 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppARGB1555);
743 case PixelFormat24bppRGB:
744 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_24bppRGB);
745 case PixelFormat32bppRGB:
746 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppRGB);
747 case PixelFormat32bppARGB:
748 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppARGB);
749 case PixelFormat32bppPARGB:
750 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppPARGB);
751 case PixelFormat48bppRGB:
752 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_48bppRGB);
753 case PixelFormat64bppARGB:
754 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_64bppARGB);
755 default:
756 break;
758 break;
759 case PixelFormat16bppRGB565:
760 switch (dst_format)
762 case PixelFormat1bppIndexed:
763 convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_1bppIndexed);
764 case PixelFormat8bppIndexed:
765 convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_8bppIndexed);
766 case PixelFormat16bppGrayScale:
767 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppGrayScale);
768 case PixelFormat16bppRGB555:
769 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppRGB555);
770 case PixelFormat16bppARGB1555:
771 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppARGB1555);
772 case PixelFormat24bppRGB:
773 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_24bppRGB);
774 case PixelFormat32bppRGB:
775 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppRGB);
776 case PixelFormat32bppARGB:
777 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppARGB);
778 case PixelFormat32bppPARGB:
779 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppPARGB);
780 case PixelFormat48bppRGB:
781 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_48bppRGB);
782 case PixelFormat64bppARGB:
783 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_64bppARGB);
784 default:
785 break;
787 break;
788 case PixelFormat16bppARGB1555:
789 switch (dst_format)
791 case PixelFormat1bppIndexed:
792 convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_1bppIndexed);
793 case PixelFormat8bppIndexed:
794 convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_8bppIndexed);
795 case PixelFormat16bppGrayScale:
796 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppGrayScale);
797 case PixelFormat16bppRGB555:
798 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB555);
799 case PixelFormat16bppRGB565:
800 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB565);
801 case PixelFormat24bppRGB:
802 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_24bppRGB);
803 case PixelFormat32bppRGB:
804 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppRGB);
805 case PixelFormat32bppARGB:
806 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppARGB);
807 case PixelFormat32bppPARGB:
808 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppPARGB);
809 case PixelFormat48bppRGB:
810 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_48bppRGB);
811 case PixelFormat64bppARGB:
812 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_64bppARGB);
813 default:
814 break;
816 break;
817 case PixelFormat24bppRGB:
818 switch (dst_format)
820 case PixelFormat1bppIndexed:
821 convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_1bppIndexed);
822 case PixelFormat8bppIndexed:
823 convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_8bppIndexed);
824 case PixelFormat16bppGrayScale:
825 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppGrayScale);
826 case PixelFormat16bppRGB555:
827 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB555);
828 case PixelFormat16bppRGB565:
829 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB565);
830 case PixelFormat16bppARGB1555:
831 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppARGB1555);
832 case PixelFormat32bppRGB:
833 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppRGB);
834 case PixelFormat32bppARGB:
835 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppARGB);
836 case PixelFormat32bppPARGB:
837 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppPARGB);
838 case PixelFormat48bppRGB:
839 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_48bppRGB);
840 case PixelFormat64bppARGB:
841 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_64bppARGB);
842 default:
843 break;
845 break;
846 case PixelFormat32bppRGB:
847 switch (dst_format)
849 case PixelFormat1bppIndexed:
850 convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_1bppIndexed);
851 case PixelFormat8bppIndexed:
852 convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_8bppIndexed);
853 case PixelFormat16bppGrayScale:
854 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppGrayScale);
855 case PixelFormat16bppRGB555:
856 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB555);
857 case PixelFormat16bppRGB565:
858 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB565);
859 case PixelFormat16bppARGB1555:
860 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppARGB1555);
861 case PixelFormat24bppRGB:
862 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_24bppRGB);
863 case PixelFormat32bppARGB:
864 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppARGB);
865 case PixelFormat32bppPARGB:
866 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppPARGB);
867 case PixelFormat48bppRGB:
868 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_48bppRGB);
869 case PixelFormat64bppARGB:
870 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_64bppARGB);
871 default:
872 break;
874 break;
875 case PixelFormat32bppARGB:
876 switch (dst_format)
878 case PixelFormat1bppIndexed:
879 convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_1bppIndexed);
880 case PixelFormat8bppIndexed:
881 convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_8bppIndexed);
882 case PixelFormat16bppGrayScale:
883 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppGrayScale);
884 case PixelFormat16bppRGB555:
885 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB555);
886 case PixelFormat16bppRGB565:
887 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB565);
888 case PixelFormat16bppARGB1555:
889 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppARGB1555);
890 case PixelFormat24bppRGB:
891 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_24bppRGB);
892 case PixelFormat32bppPARGB:
893 convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
894 return Ok;
895 case PixelFormat48bppRGB:
896 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_48bppRGB);
897 case PixelFormat64bppARGB:
898 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_64bppARGB);
899 default:
900 break;
902 break;
903 case PixelFormat32bppPARGB:
904 switch (dst_format)
906 case PixelFormat1bppIndexed:
907 convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_1bppIndexed);
908 case PixelFormat8bppIndexed:
909 convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_8bppIndexed);
910 case PixelFormat16bppGrayScale:
911 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppGrayScale);
912 case PixelFormat16bppRGB555:
913 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB555);
914 case PixelFormat16bppRGB565:
915 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB565);
916 case PixelFormat16bppARGB1555:
917 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppARGB1555);
918 case PixelFormat24bppRGB:
919 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_24bppRGB);
920 case PixelFormat32bppRGB:
921 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppRGB);
922 case PixelFormat32bppARGB:
923 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppARGB);
924 case PixelFormat48bppRGB:
925 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_48bppRGB);
926 case PixelFormat64bppARGB:
927 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_64bppARGB);
928 default:
929 break;
931 break;
932 case PixelFormat48bppRGB:
933 switch (dst_format)
935 case PixelFormat1bppIndexed:
936 convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_1bppIndexed);
937 case PixelFormat8bppIndexed:
938 convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_8bppIndexed);
939 case PixelFormat16bppGrayScale:
940 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppGrayScale);
941 case PixelFormat16bppRGB555:
942 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB555);
943 case PixelFormat16bppRGB565:
944 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB565);
945 case PixelFormat16bppARGB1555:
946 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppARGB1555);
947 case PixelFormat24bppRGB:
948 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_24bppRGB);
949 case PixelFormat32bppRGB:
950 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppRGB);
951 case PixelFormat32bppARGB:
952 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppARGB);
953 case PixelFormat32bppPARGB:
954 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppPARGB);
955 case PixelFormat64bppARGB:
956 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_64bppARGB);
957 default:
958 break;
960 break;
961 case PixelFormat64bppARGB:
962 switch (dst_format)
964 case PixelFormat1bppIndexed:
965 convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_1bppIndexed);
966 case PixelFormat8bppIndexed:
967 convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_8bppIndexed);
968 case PixelFormat16bppGrayScale:
969 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppGrayScale);
970 case PixelFormat16bppRGB555:
971 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB555);
972 case PixelFormat16bppRGB565:
973 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB565);
974 case PixelFormat16bppARGB1555:
975 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppARGB1555);
976 case PixelFormat24bppRGB:
977 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_24bppRGB);
978 case PixelFormat32bppRGB:
979 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppRGB);
980 case PixelFormat32bppARGB:
981 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppARGB);
982 case PixelFormat32bppPARGB:
983 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppPARGB);
984 case PixelFormat48bppRGB:
985 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_48bppRGB);
986 default:
987 break;
989 break;
990 case PixelFormat64bppPARGB:
991 switch (dst_format)
993 case PixelFormat1bppIndexed:
994 convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_1bppIndexed);
995 case PixelFormat8bppIndexed:
996 convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_8bppIndexed);
997 case PixelFormat16bppGrayScale:
998 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppGrayScale);
999 case PixelFormat16bppRGB555:
1000 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB555);
1001 case PixelFormat16bppRGB565:
1002 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB565);
1003 case PixelFormat16bppARGB1555:
1004 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppARGB1555);
1005 case PixelFormat24bppRGB:
1006 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_24bppRGB);
1007 case PixelFormat32bppRGB:
1008 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppRGB);
1009 case PixelFormat32bppARGB:
1010 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppARGB);
1011 case PixelFormat32bppPARGB:
1012 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppPARGB);
1013 case PixelFormat48bppRGB:
1014 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_48bppRGB);
1015 case PixelFormat64bppARGB:
1016 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_64bppARGB);
1017 default:
1018 break;
1020 break;
1021 default:
1022 break;
1025 #undef convert_indexed_to_rgb
1026 #undef convert_rgb_to_rgb
1028 return NotImplemented;
1031 /* This function returns a pointer to an array of pixels that represents the
1032 * bitmap. The *entire* bitmap is locked according to the lock mode specified by
1033 * flags. It is correct behavior that a user who calls this function with write
1034 * privileges can write to the whole bitmap (not just the area in rect).
1036 * FIXME: only used portion of format is bits per pixel. */
1037 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
1038 UINT flags, PixelFormat format, BitmapData* lockeddata)
1040 INT bitspp = PIXELFORMATBPP(format);
1041 GpRect act_rect; /* actual rect to be used */
1042 GpStatus stat;
1044 TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
1046 if(!lockeddata || !bitmap)
1047 return InvalidParameter;
1049 if(rect){
1050 if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
1051 (rect->Y + rect->Height > bitmap->height) || !flags)
1052 return InvalidParameter;
1054 act_rect = *rect;
1056 else{
1057 act_rect.X = act_rect.Y = 0;
1058 act_rect.Width = bitmap->width;
1059 act_rect.Height = bitmap->height;
1062 if(bitmap->lockmode)
1064 WARN("bitmap is already locked and cannot be locked again\n");
1065 return WrongState;
1068 if (bitmap->bits && bitmap->format == format && !(flags & ImageLockModeUserInputBuf))
1070 /* no conversion is necessary; just use the bits directly */
1071 lockeddata->Width = act_rect.Width;
1072 lockeddata->Height = act_rect.Height;
1073 lockeddata->PixelFormat = format;
1074 lockeddata->Reserved = flags;
1075 lockeddata->Stride = bitmap->stride;
1076 lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
1077 bitmap->stride * act_rect.Y;
1079 bitmap->lockmode = flags | ImageLockModeRead;
1080 bitmap->numlocks++;
1082 return Ok;
1085 /* Make sure we can convert to the requested format. */
1086 if (flags & ImageLockModeRead)
1088 stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL);
1089 if (stat == NotImplemented)
1091 FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
1092 return NotImplemented;
1096 /* If we're opening for writing, make sure we'll be able to write back in
1097 * the original format. */
1098 if (flags & ImageLockModeWrite)
1100 stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL);
1101 if (stat == NotImplemented)
1103 FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
1104 return NotImplemented;
1108 lockeddata->Width = act_rect.Width;
1109 lockeddata->Height = act_rect.Height;
1110 lockeddata->PixelFormat = format;
1111 lockeddata->Reserved = flags;
1113 if(!(flags & ImageLockModeUserInputBuf))
1115 lockeddata->Stride = (((act_rect.Width * bitspp + 7) / 8) + 3) & ~3;
1117 bitmap->bitmapbits = GdipAlloc(lockeddata->Stride * act_rect.Height);
1119 if (!bitmap->bitmapbits) return OutOfMemory;
1121 lockeddata->Scan0 = bitmap->bitmapbits;
1124 if (flags & ImageLockModeRead)
1126 static BOOL fixme = FALSE;
1128 if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
1130 FIXME("Cannot copy rows that don't start at a whole byte.\n");
1131 fixme = TRUE;
1134 stat = convert_pixels(act_rect.Width, act_rect.Height,
1135 lockeddata->Stride, lockeddata->Scan0, format,
1136 bitmap->stride,
1137 bitmap->bits + bitmap->stride * act_rect.Y + PIXELFORMATBPP(bitmap->format) * act_rect.X / 8,
1138 bitmap->format, bitmap->image.palette);
1140 if (stat != Ok)
1142 GdipFree(bitmap->bitmapbits);
1143 bitmap->bitmapbits = NULL;
1144 return stat;
1148 bitmap->lockmode = flags | ImageLockModeRead;
1149 bitmap->numlocks++;
1150 bitmap->lockx = act_rect.X;
1151 bitmap->locky = act_rect.Y;
1153 return Ok;
1156 GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi)
1158 TRACE("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
1160 if (!bitmap || xdpi == 0.0 || ydpi == 0.0)
1161 return InvalidParameter;
1163 bitmap->image.xres = xdpi;
1164 bitmap->image.yres = ydpi;
1166 return Ok;
1169 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
1170 BitmapData* lockeddata)
1172 GpStatus stat;
1173 static BOOL fixme = FALSE;
1175 TRACE("(%p,%p)\n", bitmap, lockeddata);
1177 if(!bitmap || !lockeddata)
1178 return InvalidParameter;
1180 if(!bitmap->lockmode)
1181 return WrongState;
1183 if(!(lockeddata->Reserved & ImageLockModeWrite)){
1184 if(!(--bitmap->numlocks))
1185 bitmap->lockmode = 0;
1187 GdipFree(bitmap->bitmapbits);
1188 bitmap->bitmapbits = NULL;
1189 return Ok;
1192 if (!bitmap->bitmapbits && !(lockeddata->Reserved & ImageLockModeUserInputBuf))
1194 /* we passed a direct reference; no need to do anything */
1195 bitmap->lockmode = 0;
1196 bitmap->numlocks = 0;
1197 return Ok;
1200 if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
1202 FIXME("Cannot copy rows that don't start at a whole byte.\n");
1203 fixme = TRUE;
1206 stat = convert_pixels(lockeddata->Width, lockeddata->Height,
1207 bitmap->stride,
1208 bitmap->bits + bitmap->stride * bitmap->locky + PIXELFORMATBPP(bitmap->format) * bitmap->lockx / 8,
1209 bitmap->format,
1210 lockeddata->Stride, lockeddata->Scan0, lockeddata->PixelFormat, NULL);
1212 if (stat != Ok)
1214 ERR("failed to convert pixels; this should never happen\n");
1217 GdipFree(bitmap->bitmapbits);
1218 bitmap->bitmapbits = NULL;
1219 bitmap->lockmode = 0;
1220 bitmap->numlocks = 0;
1222 return stat;
1225 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
1226 PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1228 Rect area;
1229 GpStatus stat;
1231 TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1233 if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap ||
1234 x < 0 || y < 0 ||
1235 x + width > srcBitmap->width || y + height > srcBitmap->height)
1237 TRACE("<-- InvalidParameter\n");
1238 return InvalidParameter;
1241 if (format == PixelFormatDontCare)
1242 format = srcBitmap->format;
1244 area.X = gdip_round(x);
1245 area.Y = gdip_round(y);
1246 area.Width = gdip_round(width);
1247 area.Height = gdip_round(height);
1249 stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap);
1250 if (stat == Ok)
1252 stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format,
1253 srcBitmap->stride,
1254 srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8,
1255 srcBitmap->format, srcBitmap->image.palette);
1257 if (stat == Ok && srcBitmap->image.palette)
1259 ColorPalette *src_palette, *dst_palette;
1261 src_palette = srcBitmap->image.palette;
1263 dst_palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * src_palette->Count);
1265 if (dst_palette)
1267 dst_palette->Flags = src_palette->Flags;
1268 dst_palette->Count = src_palette->Count;
1269 memcpy(dst_palette->Entries, src_palette->Entries, sizeof(ARGB) * src_palette->Count);
1271 GdipFree((*dstBitmap)->image.palette);
1272 (*dstBitmap)->image.palette = dst_palette;
1274 else
1275 stat = OutOfMemory;
1278 if (stat != Ok)
1279 GdipDisposeImage((GpImage*)*dstBitmap);
1282 if (stat != Ok)
1283 *dstBitmap = NULL;
1285 return stat;
1288 GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
1289 PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1291 TRACE("(%i,%i,%i,%i,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1293 return GdipCloneBitmapArea(x, y, width, height, format, srcBitmap, dstBitmap);
1296 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
1298 GpStatus stat = GenericError;
1300 TRACE("%p, %p\n", image, cloneImage);
1302 if (!image || !cloneImage)
1303 return InvalidParameter;
1305 if (image->picture)
1307 IStream* stream;
1308 HRESULT hr;
1309 INT size;
1310 LARGE_INTEGER move;
1312 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
1313 if (FAILED(hr))
1314 return GenericError;
1316 hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
1317 if(FAILED(hr))
1319 WARN("Failed to save image on stream\n");
1320 goto out;
1323 /* Set seek pointer back to the beginning of the picture */
1324 move.QuadPart = 0;
1325 hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
1326 if (FAILED(hr))
1327 goto out;
1329 stat = GdipLoadImageFromStream(stream, cloneImage);
1330 if (stat != Ok) WARN("Failed to load image from stream\n");
1332 out:
1333 IStream_Release(stream);
1334 return stat;
1336 else if (image->type == ImageTypeBitmap)
1338 GpBitmap *bitmap = (GpBitmap *)image;
1340 return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height,
1341 bitmap->format, bitmap, (GpBitmap **)cloneImage);
1343 else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
1345 GpMetafile *result, *metafile;
1347 metafile = (GpMetafile*)image;
1349 result = GdipAlloc(sizeof(*result));
1350 if (!result)
1351 return OutOfMemory;
1353 result->image.type = ImageTypeMetafile;
1354 result->image.format = image->format;
1355 result->image.flags = image->flags;
1356 result->image.frame_count = 1;
1357 result->image.xres = image->xres;
1358 result->image.yres = image->yres;
1359 result->bounds = metafile->bounds;
1360 result->unit = metafile->unit;
1361 result->metafile_type = metafile->metafile_type;
1362 result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
1364 if (!result->hemf)
1366 GdipFree(result);
1367 return OutOfMemory;
1370 *cloneImage = &result->image;
1371 return Ok;
1373 else
1375 WARN("GpImage with no image data (metafile in wrong state?)\n");
1376 return InvalidParameter;
1380 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
1381 GpBitmap **bitmap)
1383 GpStatus stat;
1384 IStream *stream;
1386 TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1388 if(!filename || !bitmap)
1389 return InvalidParameter;
1391 *bitmap = NULL;
1393 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
1395 if(stat != Ok)
1396 return stat;
1398 stat = GdipCreateBitmapFromStream(stream, bitmap);
1400 IStream_Release(stream);
1402 return stat;
1405 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info,
1406 VOID *bits, GpBitmap **bitmap)
1408 DWORD height, stride;
1409 PixelFormat format;
1411 FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
1413 if (!info || !bits || !bitmap)
1414 return InvalidParameter;
1416 height = abs(info->bmiHeader.biHeight);
1417 stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
1419 if(info->bmiHeader.biHeight > 0) /* bottom-up */
1421 bits = (BYTE*)bits + (height - 1) * stride;
1422 stride = -stride;
1425 switch(info->bmiHeader.biBitCount) {
1426 case 1:
1427 format = PixelFormat1bppIndexed;
1428 break;
1429 case 4:
1430 format = PixelFormat4bppIndexed;
1431 break;
1432 case 8:
1433 format = PixelFormat8bppIndexed;
1434 break;
1435 case 16:
1436 format = PixelFormat16bppRGB555;
1437 break;
1438 case 24:
1439 format = PixelFormat24bppRGB;
1440 break;
1441 case 32:
1442 format = PixelFormat32bppRGB;
1443 break;
1444 default:
1445 FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
1446 *bitmap = NULL;
1447 return InvalidParameter;
1450 return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
1451 bits, bitmap);
1455 /* FIXME: no icm */
1456 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename,
1457 GpBitmap **bitmap)
1459 TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1461 return GdipCreateBitmapFromFile(filename, bitmap);
1464 GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
1465 GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
1467 HBITMAP hbm;
1468 GpStatus stat = InvalidParameter;
1470 TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
1472 if(!lpBitmapName || !bitmap)
1473 return InvalidParameter;
1475 /* load DIB */
1476 hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
1477 LR_CREATEDIBSECTION);
1479 if(hbm){
1480 stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
1481 DeleteObject(hbm);
1484 return stat;
1487 static inline DWORD blend_argb_no_bkgnd_alpha(DWORD src, DWORD bkgnd)
1489 BYTE b = (BYTE)src;
1490 BYTE g = (BYTE)(src >> 8);
1491 BYTE r = (BYTE)(src >> 16);
1492 DWORD alpha = (BYTE)(src >> 24);
1493 return ((b + ((BYTE)bkgnd * (255 - alpha) + 127) / 255) |
1494 (g + ((BYTE)(bkgnd >> 8) * (255 - alpha) + 127) / 255) << 8 |
1495 (r + ((BYTE)(bkgnd >> 16) * (255 - alpha) + 127) / 255) << 16 |
1496 (alpha << 24));
1499 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
1500 HBITMAP* hbmReturn, ARGB background)
1502 GpStatus stat;
1503 HBITMAP result;
1504 UINT width, height;
1505 BITMAPINFOHEADER bih;
1506 LPBYTE bits;
1507 BitmapData lockeddata;
1508 TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
1510 if (!bitmap || !hbmReturn) return InvalidParameter;
1512 GdipGetImageWidth((GpImage*)bitmap, &width);
1513 GdipGetImageHeight((GpImage*)bitmap, &height);
1515 bih.biSize = sizeof(bih);
1516 bih.biWidth = width;
1517 bih.biHeight = height;
1518 bih.biPlanes = 1;
1519 bih.biBitCount = 32;
1520 bih.biCompression = BI_RGB;
1521 bih.biSizeImage = 0;
1522 bih.biXPelsPerMeter = 0;
1523 bih.biYPelsPerMeter = 0;
1524 bih.biClrUsed = 0;
1525 bih.biClrImportant = 0;
1527 result = CreateDIBSection(0, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1529 if (result)
1531 lockeddata.Stride = -width * 4;
1532 lockeddata.Scan0 = bits + (width * 4 * (height - 1));
1534 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead|ImageLockModeUserInputBuf,
1535 PixelFormat32bppPARGB, &lockeddata);
1537 if (stat == Ok)
1538 stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
1540 if (stat == Ok && (background & 0xffffff))
1542 DWORD *ptr;
1543 UINT i;
1544 for (ptr = (DWORD*)bits, i = 0; i < width * height; ptr++, i++)
1546 if ((*ptr & 0xff000000) == 0xff000000) continue;
1547 *ptr = blend_argb_no_bkgnd_alpha(*ptr, background);
1551 else
1552 stat = GenericError;
1554 if (stat != Ok && result)
1556 DeleteObject(result);
1557 result = NULL;
1560 *hbmReturn = result;
1562 return stat;
1565 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
1566 GpGraphics* target, GpBitmap** bitmap)
1568 GpStatus ret;
1570 TRACE("(%d, %d, %p, %p)\n", width, height, target, bitmap);
1572 if(!target || !bitmap)
1573 return InvalidParameter;
1575 ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
1576 NULL, bitmap);
1578 if (ret == Ok)
1580 GdipGetDpiX(target, &(*bitmap)->image.xres);
1581 GdipGetDpiY(target, &(*bitmap)->image.yres);
1584 return ret;
1587 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
1589 GpStatus stat;
1590 ICONINFO iinfo;
1591 BITMAP bm;
1592 int ret;
1593 UINT width, height, stride;
1594 GpRect rect;
1595 BitmapData lockeddata;
1596 HDC screendc;
1597 BOOL has_alpha;
1598 int x, y;
1599 BITMAPINFOHEADER bih;
1600 DWORD *src;
1601 BYTE *dst_row;
1602 DWORD *dst;
1604 TRACE("%p, %p\n", hicon, bitmap);
1606 if(!bitmap || !GetIconInfo(hicon, &iinfo))
1607 return InvalidParameter;
1609 /* get the size of the icon */
1610 ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
1611 if (ret == 0) {
1612 DeleteObject(iinfo.hbmColor);
1613 DeleteObject(iinfo.hbmMask);
1614 return GenericError;
1617 width = bm.bmWidth;
1618 height = iinfo.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2;
1619 stride = width * 4;
1621 stat = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat32bppARGB, NULL, bitmap);
1622 if (stat != Ok) {
1623 DeleteObject(iinfo.hbmColor);
1624 DeleteObject(iinfo.hbmMask);
1625 return stat;
1628 rect.X = 0;
1629 rect.Y = 0;
1630 rect.Width = width;
1631 rect.Height = height;
1633 stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
1634 if (stat != Ok) {
1635 DeleteObject(iinfo.hbmColor);
1636 DeleteObject(iinfo.hbmMask);
1637 GdipDisposeImage((GpImage*)*bitmap);
1638 return stat;
1641 bih.biSize = sizeof(bih);
1642 bih.biWidth = width;
1643 bih.biHeight = iinfo.hbmColor ? -height: -height * 2;
1644 bih.biPlanes = 1;
1645 bih.biBitCount = 32;
1646 bih.biCompression = BI_RGB;
1647 bih.biSizeImage = 0;
1648 bih.biXPelsPerMeter = 0;
1649 bih.biYPelsPerMeter = 0;
1650 bih.biClrUsed = 0;
1651 bih.biClrImportant = 0;
1653 screendc = CreateCompatibleDC(0);
1654 if (iinfo.hbmColor)
1656 GetDIBits(screendc, iinfo.hbmColor, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1658 if (bm.bmBitsPixel == 32)
1660 has_alpha = FALSE;
1662 /* If any pixel has a non-zero alpha, ignore hbmMask */
1663 src = (DWORD*)lockeddata.Scan0;
1664 for (x=0; x<width && !has_alpha; x++)
1665 for (y=0; y<height && !has_alpha; y++)
1666 if ((*src++ & 0xff000000) != 0)
1667 has_alpha = TRUE;
1669 else has_alpha = FALSE;
1671 else
1673 GetDIBits(screendc, iinfo.hbmMask, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1674 has_alpha = FALSE;
1677 if (!has_alpha)
1679 if (iinfo.hbmMask)
1681 BYTE *bits = HeapAlloc(GetProcessHeap(), 0, height * stride);
1683 /* read alpha data from the mask */
1684 if (iinfo.hbmColor)
1685 GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1686 else
1687 GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1689 src = (DWORD*)bits;
1690 dst_row = lockeddata.Scan0;
1691 for (y=0; y<height; y++)
1693 dst = (DWORD*)dst_row;
1694 for (x=0; x<height; x++)
1696 DWORD src_value = *src++;
1697 if (src_value)
1698 *dst++ = 0;
1699 else
1700 *dst++ |= 0xff000000;
1702 dst_row += lockeddata.Stride;
1705 HeapFree(GetProcessHeap(), 0, bits);
1707 else
1709 /* set constant alpha of 255 */
1710 dst_row = lockeddata.Scan0;
1711 for (y=0; y<height; y++)
1713 dst = (DWORD*)dst_row;
1714 for (x=0; x<height; x++)
1715 *dst++ |= 0xff000000;
1716 dst_row += lockeddata.Stride;
1721 DeleteDC(screendc);
1723 DeleteObject(iinfo.hbmColor);
1724 DeleteObject(iinfo.hbmMask);
1726 GdipBitmapUnlockBits(*bitmap, &lockeddata);
1728 return Ok;
1731 static void generate_halftone_palette(ARGB *entries, UINT count)
1733 static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
1734 UINT i;
1736 for (i=0; i<8 && i<count; i++)
1738 entries[i] = 0xff000000;
1739 if (i&1) entries[i] |= 0x800000;
1740 if (i&2) entries[i] |= 0x8000;
1741 if (i&4) entries[i] |= 0x80;
1744 if (8 < count)
1745 entries[i] = 0xffc0c0c0;
1747 for (i=9; i<16 && i<count; i++)
1749 entries[i] = 0xff000000;
1750 if (i&1) entries[i] |= 0xff0000;
1751 if (i&2) entries[i] |= 0xff00;
1752 if (i&4) entries[i] |= 0xff;
1755 for (i=16; i<40 && i<count; i++)
1757 entries[i] = 0;
1760 for (i=40; i<256 && i<count; i++)
1762 entries[i] = 0xff000000;
1763 entries[i] |= halftone_values[(i-40)%6];
1764 entries[i] |= halftone_values[((i-40)/6)%6] << 8;
1765 entries[i] |= halftone_values[((i-40)/36)%6] << 16;
1769 static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
1771 HDC screendc = CreateCompatibleDC(0);
1773 if (!screendc) return GenericError;
1775 *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
1776 *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
1778 DeleteDC(screendc);
1780 return Ok;
1783 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
1784 PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
1786 HBITMAP hbitmap=NULL;
1787 INT row_size, dib_stride;
1788 BYTE *bits=NULL, *own_bits=NULL;
1789 REAL xres, yres;
1790 GpStatus stat;
1792 TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
1794 if (!bitmap) return InvalidParameter;
1796 if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
1797 *bitmap = NULL;
1798 return InvalidParameter;
1801 if(scan0 && !stride)
1802 return InvalidParameter;
1804 stat = get_screen_resolution(&xres, &yres);
1805 if (stat != Ok) return stat;
1807 row_size = (width * PIXELFORMATBPP(format)+7) / 8;
1808 dib_stride = (row_size + 3) & ~3;
1810 if(stride == 0)
1811 stride = dib_stride;
1813 if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
1815 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1816 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
1818 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1819 pbmi->bmiHeader.biWidth = width;
1820 pbmi->bmiHeader.biHeight = -height;
1821 pbmi->bmiHeader.biPlanes = 1;
1822 /* FIXME: use the rest of the data from format */
1823 pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
1824 pbmi->bmiHeader.biCompression = BI_RGB;
1825 pbmi->bmiHeader.biSizeImage = 0;
1826 pbmi->bmiHeader.biXPelsPerMeter = 0;
1827 pbmi->bmiHeader.biYPelsPerMeter = 0;
1828 pbmi->bmiHeader.biClrUsed = 0;
1829 pbmi->bmiHeader.biClrImportant = 0;
1831 hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1833 if (!hbitmap) return GenericError;
1835 stride = dib_stride;
1837 else
1839 /* Not a GDI format; don't try to make an HBITMAP. */
1840 if (scan0)
1841 bits = scan0;
1842 else
1844 INT size = abs(stride) * height;
1846 own_bits = bits = GdipAlloc(size);
1847 if (!own_bits) return OutOfMemory;
1849 if (stride < 0)
1850 bits += stride * (1 - height);
1854 *bitmap = GdipAlloc(sizeof(GpBitmap));
1855 if(!*bitmap)
1857 DeleteObject(hbitmap);
1858 GdipFree(own_bits);
1859 return OutOfMemory;
1862 (*bitmap)->image.type = ImageTypeBitmap;
1863 memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
1864 (*bitmap)->image.flags = ImageFlagsNone;
1865 (*bitmap)->image.frame_count = 1;
1866 (*bitmap)->image.current_frame = 0;
1867 (*bitmap)->image.palette = NULL;
1868 (*bitmap)->image.xres = xres;
1869 (*bitmap)->image.yres = yres;
1870 (*bitmap)->width = width;
1871 (*bitmap)->height = height;
1872 (*bitmap)->format = format;
1873 (*bitmap)->image.picture = NULL;
1874 (*bitmap)->image.stream = NULL;
1875 (*bitmap)->hbitmap = hbitmap;
1876 (*bitmap)->hdc = NULL;
1877 (*bitmap)->bits = bits;
1878 (*bitmap)->stride = stride;
1879 (*bitmap)->own_bits = own_bits;
1880 (*bitmap)->metadata_reader = NULL;
1881 (*bitmap)->prop_count = 0;
1882 (*bitmap)->prop_item = NULL;
1884 /* set format-related flags */
1885 if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed))
1886 (*bitmap)->image.flags |= ImageFlagsHasAlpha;
1888 if (format == PixelFormat1bppIndexed ||
1889 format == PixelFormat4bppIndexed ||
1890 format == PixelFormat8bppIndexed)
1892 (*bitmap)->image.palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * (1 << PIXELFORMATBPP(format)));
1894 if (!(*bitmap)->image.palette)
1896 GdipDisposeImage(&(*bitmap)->image);
1897 *bitmap = NULL;
1898 return OutOfMemory;
1901 (*bitmap)->image.palette->Count = 1 << PIXELFORMATBPP(format);
1903 if (format == PixelFormat1bppIndexed)
1905 (*bitmap)->image.palette->Flags = PaletteFlagsGrayScale;
1906 (*bitmap)->image.palette->Entries[0] = 0xff000000;
1907 (*bitmap)->image.palette->Entries[1] = 0xffffffff;
1909 else
1911 if (format == PixelFormat8bppIndexed)
1912 (*bitmap)->image.palette->Flags = PaletteFlagsHalftone;
1914 generate_halftone_palette((*bitmap)->image.palette->Entries,
1915 (*bitmap)->image.palette->Count);
1919 TRACE("<-- %p\n", *bitmap);
1921 return Ok;
1924 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
1925 GpBitmap **bitmap)
1927 GpStatus stat;
1929 TRACE("%p %p\n", stream, bitmap);
1931 stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
1933 if(stat != Ok)
1934 return stat;
1936 if((*bitmap)->image.type != ImageTypeBitmap){
1937 GdipDisposeImage(&(*bitmap)->image);
1938 *bitmap = NULL;
1939 return GenericError; /* FIXME: what error to return? */
1942 return Ok;
1945 /* FIXME: no icm */
1946 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
1947 GpBitmap **bitmap)
1949 TRACE("%p %p\n", stream, bitmap);
1951 return GdipCreateBitmapFromStream(stream, bitmap);
1954 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
1955 GpCachedBitmap **cachedbmp)
1957 GpStatus stat;
1959 TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
1961 if(!bitmap || !graphics || !cachedbmp)
1962 return InvalidParameter;
1964 *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
1965 if(!*cachedbmp)
1966 return OutOfMemory;
1968 stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
1969 if(stat != Ok){
1970 GdipFree(*cachedbmp);
1971 return stat;
1974 return Ok;
1977 GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon)
1979 GpStatus stat;
1980 BitmapData lockeddata;
1981 ULONG andstride, xorstride, bitssize;
1982 LPBYTE andbits, xorbits, androw, xorrow, srcrow;
1983 UINT x, y;
1985 TRACE("(%p, %p)\n", bitmap, hicon);
1987 if (!bitmap || !hicon)
1988 return InvalidParameter;
1990 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead,
1991 PixelFormat32bppPARGB, &lockeddata);
1992 if (stat == Ok)
1994 andstride = ((lockeddata.Width+31)/32)*4;
1995 xorstride = lockeddata.Width*4;
1996 bitssize = (andstride + xorstride) * lockeddata.Height;
1998 andbits = GdipAlloc(bitssize);
2000 if (andbits)
2002 xorbits = andbits + andstride * lockeddata.Height;
2004 for (y=0; y<lockeddata.Height; y++)
2006 srcrow = ((LPBYTE)lockeddata.Scan0) + lockeddata.Stride * y;
2008 androw = andbits + andstride * y;
2009 for (x=0; x<lockeddata.Width; x++)
2010 if (srcrow[3+4*x] >= 128)
2011 androw[x/8] |= 1 << (7-x%8);
2013 xorrow = xorbits + xorstride * y;
2014 memcpy(xorrow, srcrow, xorstride);
2017 *hicon = CreateIcon(NULL, lockeddata.Width, lockeddata.Height, 1, 32,
2018 andbits, xorbits);
2020 GdipFree(andbits);
2022 else
2023 stat = OutOfMemory;
2025 GdipBitmapUnlockBits(bitmap, &lockeddata);
2028 return stat;
2031 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
2033 TRACE("%p\n", cachedbmp);
2035 if(!cachedbmp)
2036 return InvalidParameter;
2038 GdipDisposeImage(cachedbmp->image);
2039 GdipFree(cachedbmp);
2041 return Ok;
2044 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
2045 GpCachedBitmap *cachedbmp, INT x, INT y)
2047 TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
2049 if(!graphics || !cachedbmp)
2050 return InvalidParameter;
2052 return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
2055 /* Internal utility function: Replace the image data of dst with that of src,
2056 * and free src. */
2057 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
2059 assert(src->image.type == ImageTypeBitmap);
2060 assert(dst->image.type == ImageTypeBitmap);
2062 GdipFree(dst->bitmapbits);
2063 GdipFree(dst->own_bits);
2064 DeleteDC(dst->hdc);
2065 DeleteObject(dst->hbitmap);
2067 if (clobber_palette)
2069 GdipFree(dst->image.palette);
2070 dst->image.palette = src->image.palette;
2072 else
2073 GdipFree(src->image.palette);
2075 dst->image.xres = src->image.xres;
2076 dst->image.yres = src->image.yres;
2077 dst->width = src->width;
2078 dst->height = src->height;
2079 dst->format = src->format;
2080 dst->hbitmap = src->hbitmap;
2081 dst->hdc = src->hdc;
2082 dst->bits = src->bits;
2083 dst->stride = src->stride;
2084 dst->own_bits = src->own_bits;
2085 if (dst->metadata_reader)
2086 IWICMetadataReader_Release(dst->metadata_reader);
2087 dst->metadata_reader = src->metadata_reader;
2088 GdipFree(dst->prop_item);
2089 dst->prop_item = src->prop_item;
2090 dst->prop_count = src->prop_count;
2091 if (dst->image.stream)
2092 IStream_Release(dst->image.stream);
2093 dst->image.stream = src->image.stream;
2094 dst->image.frame_count = src->image.frame_count;
2095 dst->image.current_frame = src->image.current_frame;
2096 dst->image.format = src->image.format;
2098 src->image.type = ~0;
2099 GdipFree(src);
2102 static GpStatus free_image_data(GpImage *image)
2104 if(!image)
2105 return InvalidParameter;
2107 if (image->type == ImageTypeBitmap)
2109 GdipFree(((GpBitmap*)image)->bitmapbits);
2110 GdipFree(((GpBitmap*)image)->own_bits);
2111 DeleteDC(((GpBitmap*)image)->hdc);
2112 DeleteObject(((GpBitmap*)image)->hbitmap);
2113 if (((GpBitmap*)image)->metadata_reader)
2114 IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader);
2115 GdipFree(((GpBitmap*)image)->prop_item);
2117 else if (image->type == ImageTypeMetafile)
2119 GpMetafile *metafile = (GpMetafile*)image;
2120 GdipFree(metafile->comment_data);
2121 DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
2122 if (!metafile->preserve_hemf)
2123 DeleteEnhMetaFile(metafile->hemf);
2124 if (metafile->record_graphics)
2126 WARN("metafile closed while recording\n");
2127 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
2128 metafile->record_graphics->image = NULL;
2129 metafile->record_graphics->busy = TRUE;
2132 else
2134 WARN("invalid image: %p\n", image);
2135 return ObjectBusy;
2137 if (image->picture)
2138 IPicture_Release(image->picture);
2139 if (image->stream)
2140 IStream_Release(image->stream);
2141 GdipFree(image->palette);
2143 return Ok;
2146 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
2148 GpStatus status;
2150 TRACE("%p\n", image);
2152 status = free_image_data(image);
2153 if (status != Ok) return status;
2154 image->type = ~0;
2155 GdipFree(image);
2157 return Ok;
2160 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
2162 static int calls;
2164 TRACE("(%p,%p)\n", image, item);
2166 if(!image || !item)
2167 return InvalidParameter;
2169 if (!(calls++))
2170 FIXME("not implemented\n");
2172 return NotImplemented;
2175 GpStatus WINGDIPAPI GdipGetImageItemData(GpImage *image, ImageItemData *item)
2177 static int calls;
2179 TRACE("(%p,%p)\n", image, item);
2181 if (!(calls++))
2182 FIXME("not implemented\n");
2184 return NotImplemented;
2187 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
2188 GpUnit *srcUnit)
2190 TRACE("%p %p %p\n", image, srcRect, srcUnit);
2192 if(!image || !srcRect || !srcUnit)
2193 return InvalidParameter;
2194 if(image->type == ImageTypeMetafile){
2195 *srcRect = ((GpMetafile*)image)->bounds;
2196 *srcUnit = ((GpMetafile*)image)->unit;
2198 else if(image->type == ImageTypeBitmap){
2199 srcRect->X = srcRect->Y = 0.0;
2200 srcRect->Width = (REAL) ((GpBitmap*)image)->width;
2201 srcRect->Height = (REAL) ((GpBitmap*)image)->height;
2202 *srcUnit = UnitPixel;
2204 else{
2205 srcRect->X = srcRect->Y = 0.0;
2206 srcRect->Width = ipicture_pixel_width(image->picture);
2207 srcRect->Height = ipicture_pixel_height(image->picture);
2208 *srcUnit = UnitPixel;
2211 TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
2212 srcRect->Width, srcRect->Height, *srcUnit);
2214 return Ok;
2217 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
2218 REAL *height)
2220 TRACE("%p %p %p\n", image, width, height);
2222 if(!image || !height || !width)
2223 return InvalidParameter;
2225 if(image->type == ImageTypeMetafile){
2226 *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2227 *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2229 else if(image->type == ImageTypeBitmap){
2230 *height = ((GpBitmap*)image)->height;
2231 *width = ((GpBitmap*)image)->width;
2233 else{
2234 *height = ipicture_pixel_height(image->picture);
2235 *width = ipicture_pixel_width(image->picture);
2238 TRACE("returning (%f, %f)\n", *height, *width);
2239 return Ok;
2242 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
2243 GpGraphics **graphics)
2245 HDC hdc;
2246 GpStatus stat;
2248 TRACE("%p %p\n", image, graphics);
2250 if(!image || !graphics)
2251 return InvalidParameter;
2253 if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
2255 hdc = ((GpBitmap*)image)->hdc;
2257 if(!hdc){
2258 hdc = CreateCompatibleDC(0);
2259 SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
2260 ((GpBitmap*)image)->hdc = hdc;
2263 stat = GdipCreateFromHDC(hdc, graphics);
2265 if (stat == Ok)
2267 (*graphics)->image = image;
2268 (*graphics)->xres = image->xres;
2269 (*graphics)->yres = image->yres;
2272 else if (image->type == ImageTypeMetafile)
2273 stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics);
2274 else
2275 stat = graphics_from_image(image, graphics);
2277 return stat;
2280 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
2282 TRACE("%p %p\n", image, height);
2284 if(!image || !height)
2285 return InvalidParameter;
2287 if(image->type == ImageTypeMetafile)
2288 *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2289 else if(image->type == ImageTypeBitmap)
2290 *height = ((GpBitmap*)image)->height;
2291 else
2292 *height = ipicture_pixel_height(image->picture);
2294 TRACE("returning %d\n", *height);
2296 return Ok;
2299 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
2301 if(!image || !res)
2302 return InvalidParameter;
2304 *res = image->xres;
2306 TRACE("(%p) <-- %0.2f\n", image, *res);
2308 return Ok;
2311 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
2313 TRACE("%p %p\n", image, size);
2315 if(!image || !size)
2316 return InvalidParameter;
2318 if (!image->palette || image->palette->Count == 0)
2319 *size = sizeof(ColorPalette);
2320 else
2321 *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette->Count;
2323 TRACE("<-- %u\n", *size);
2325 return Ok;
2328 /* FIXME: test this function for non-bitmap types */
2329 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
2331 TRACE("%p %p\n", image, format);
2333 if(!image || !format)
2334 return InvalidParameter;
2336 if(image->type != ImageTypeBitmap)
2337 *format = PixelFormat24bppRGB;
2338 else
2339 *format = ((GpBitmap*) image)->format;
2341 return Ok;
2344 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
2346 TRACE("(%p, %p)\n", image, format);
2348 if(!image || !format)
2349 return InvalidParameter;
2351 memcpy(format, &image->format, sizeof(GUID));
2353 return Ok;
2356 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
2358 TRACE("%p %p\n", image, type);
2360 if(!image || !type)
2361 return InvalidParameter;
2363 *type = image->type;
2365 return Ok;
2368 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
2370 if(!image || !res)
2371 return InvalidParameter;
2373 *res = image->yres;
2375 TRACE("(%p) <-- %0.2f\n", image, *res);
2377 return Ok;
2380 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
2382 TRACE("%p %p\n", image, width);
2384 if(!image || !width)
2385 return InvalidParameter;
2387 if(image->type == ImageTypeMetafile)
2388 *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2389 else if(image->type == ImageTypeBitmap)
2390 *width = ((GpBitmap*)image)->width;
2391 else
2392 *width = ipicture_pixel_width(image->picture);
2394 TRACE("returning %d\n", *width);
2396 return Ok;
2399 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num)
2401 TRACE("(%p, %p)\n", image, num);
2403 if (!image || !num) return InvalidParameter;
2405 *num = 0;
2407 if (image->type == ImageTypeBitmap)
2409 if (((GpBitmap *)image)->prop_item)
2411 *num = ((GpBitmap *)image)->prop_count;
2412 return Ok;
2415 if (((GpBitmap *)image)->metadata_reader)
2416 IWICMetadataReader_GetCount(((GpBitmap *)image)->metadata_reader, num);
2419 return Ok;
2422 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID *list)
2424 HRESULT hr;
2425 IWICMetadataReader *reader;
2426 IWICEnumMetadataItem *enumerator;
2427 UINT prop_count, i, items_returned;
2429 TRACE("(%p, %u, %p)\n", image, num, list);
2431 if (!image || !list) return InvalidParameter;
2433 if (image->type != ImageTypeBitmap)
2435 FIXME("Not implemented for type %d\n", image->type);
2436 return NotImplemented;
2439 if (((GpBitmap *)image)->prop_item)
2441 if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter;
2443 for (i = 0; i < num; i++)
2445 list[i] = ((GpBitmap *)image)->prop_item[i].id;
2448 return Ok;
2451 reader = ((GpBitmap *)image)->metadata_reader;
2452 if (!reader)
2454 if (num != 0) return InvalidParameter;
2455 return Ok;
2458 hr = IWICMetadataReader_GetCount(reader, &prop_count);
2459 if (FAILED(hr)) return hresult_to_status(hr);
2461 if (num != prop_count) return InvalidParameter;
2463 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2464 if (FAILED(hr)) return hresult_to_status(hr);
2466 IWICEnumMetadataItem_Reset(enumerator);
2468 for (i = 0; i < num; i++)
2470 PROPVARIANT id;
2472 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, NULL, &items_returned);
2473 if (hr != S_OK) break;
2475 if (id.vt != VT_UI2)
2477 FIXME("not supported propvariant type for id: %u\n", id.vt);
2478 list[i] = 0;
2479 continue;
2481 list[i] = id.u.uiVal;
2484 IWICEnumMetadataItem_Release(enumerator);
2486 return hr == S_OK ? Ok : hresult_to_status(hr);
2489 static UINT propvariant_size(PROPVARIANT *value)
2491 switch (value->vt & ~VT_VECTOR)
2493 case VT_EMPTY:
2494 return 0;
2495 case VT_I1:
2496 case VT_UI1:
2497 if (!(value->vt & VT_VECTOR)) return 1;
2498 return value->u.caub.cElems;
2499 case VT_I2:
2500 case VT_UI2:
2501 if (!(value->vt & VT_VECTOR)) return 2;
2502 return value->u.caui.cElems * 2;
2503 case VT_I4:
2504 case VT_UI4:
2505 case VT_R4:
2506 if (!(value->vt & VT_VECTOR)) return 4;
2507 return value->u.caul.cElems * 4;
2508 case VT_I8:
2509 case VT_UI8:
2510 case VT_R8:
2511 if (!(value->vt & VT_VECTOR)) return 8;
2512 return value->u.cauh.cElems * 8;
2513 case VT_LPSTR:
2514 return value->u.pszVal ? strlen(value->u.pszVal) + 1 : 0;
2515 case VT_BLOB:
2516 return value->u.blob.cbSize;
2517 default:
2518 FIXME("not supported variant type %d\n", value->vt);
2519 return 0;
2523 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID propid, UINT *size)
2525 HRESULT hr;
2526 IWICMetadataReader *reader;
2527 PROPVARIANT id, value;
2529 TRACE("(%p,%#x,%p)\n", image, propid, size);
2531 if (!size || !image) return InvalidParameter;
2533 if (image->type != ImageTypeBitmap)
2535 FIXME("Not implemented for type %d\n", image->type);
2536 return NotImplemented;
2539 if (((GpBitmap *)image)->prop_item)
2541 UINT i;
2543 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2545 if (propid == ((GpBitmap *)image)->prop_item[i].id)
2547 *size = sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2548 return Ok;
2552 return PropertyNotFound;
2555 reader = ((GpBitmap *)image)->metadata_reader;
2556 if (!reader) return PropertyNotFound;
2558 id.vt = VT_UI2;
2559 id.u.uiVal = propid;
2560 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2561 if (FAILED(hr)) return PropertyNotFound;
2563 *size = propvariant_size(&value);
2564 if (*size) *size += sizeof(PropertyItem);
2565 PropVariantClear(&value);
2567 return Ok;
2570 #ifndef PropertyTagTypeSByte
2571 #define PropertyTagTypeSByte 6
2572 #define PropertyTagTypeSShort 8
2573 #define PropertyTagTypeFloat 11
2574 #define PropertyTagTypeDouble 12
2575 #endif
2577 static UINT vt_to_itemtype(UINT vt)
2579 static const struct
2581 UINT vt, type;
2582 } vt2type[] =
2584 { VT_I1, PropertyTagTypeSByte },
2585 { VT_UI1, PropertyTagTypeByte },
2586 { VT_I2, PropertyTagTypeSShort },
2587 { VT_UI2, PropertyTagTypeShort },
2588 { VT_I4, PropertyTagTypeSLONG },
2589 { VT_UI4, PropertyTagTypeLong },
2590 { VT_I8, PropertyTagTypeSRational },
2591 { VT_UI8, PropertyTagTypeRational },
2592 { VT_R4, PropertyTagTypeFloat },
2593 { VT_R8, PropertyTagTypeDouble },
2594 { VT_LPSTR, PropertyTagTypeASCII },
2595 { VT_BLOB, PropertyTagTypeUndefined }
2597 UINT i;
2598 for (i = 0; i < sizeof(vt2type)/sizeof(vt2type[0]); i++)
2600 if (vt2type[i].vt == vt) return vt2type[i].type;
2602 FIXME("not supported variant type %u\n", vt);
2603 return 0;
2606 static GpStatus propvariant_to_item(PROPVARIANT *value, PropertyItem *item,
2607 UINT size, PROPID id)
2609 UINT item_size, item_type;
2611 item_size = propvariant_size(value);
2612 if (size != item_size + sizeof(PropertyItem)) return InvalidParameter;
2614 item_type = vt_to_itemtype(value->vt & ~VT_VECTOR);
2615 if (!item_type) return InvalidParameter;
2617 item->value = item + 1;
2619 switch (value->vt & ~VT_VECTOR)
2621 case VT_I1:
2622 case VT_UI1:
2623 if (!(value->vt & VT_VECTOR))
2624 *(BYTE *)item->value = value->u.bVal;
2625 else
2626 memcpy(item->value, value->u.caub.pElems, item_size);
2627 break;
2628 case VT_I2:
2629 case VT_UI2:
2630 if (!(value->vt & VT_VECTOR))
2631 *(USHORT *)item->value = value->u.uiVal;
2632 else
2633 memcpy(item->value, value->u.caui.pElems, item_size);
2634 break;
2635 case VT_I4:
2636 case VT_UI4:
2637 case VT_R4:
2638 if (!(value->vt & VT_VECTOR))
2639 *(ULONG *)item->value = value->u.ulVal;
2640 else
2641 memcpy(item->value, value->u.caul.pElems, item_size);
2642 break;
2643 case VT_I8:
2644 case VT_UI8:
2645 case VT_R8:
2646 if (!(value->vt & VT_VECTOR))
2647 *(ULONGLONG *)item->value = value->u.uhVal.QuadPart;
2648 else
2649 memcpy(item->value, value->u.cauh.pElems, item_size);
2650 break;
2651 case VT_LPSTR:
2652 memcpy(item->value, value->u.pszVal, item_size);
2653 break;
2654 case VT_BLOB:
2655 memcpy(item->value, value->u.blob.pBlobData, item_size);
2656 break;
2657 default:
2658 FIXME("not supported variant type %d\n", value->vt);
2659 return InvalidParameter;
2662 item->length = item_size;
2663 item->type = item_type;
2664 item->id = id;
2666 return Ok;
2669 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID propid, UINT size,
2670 PropertyItem *buffer)
2672 GpStatus stat;
2673 HRESULT hr;
2674 IWICMetadataReader *reader;
2675 PROPVARIANT id, value;
2677 TRACE("(%p,%#x,%u,%p)\n", image, propid, size, buffer);
2679 if (!image || !buffer) return InvalidParameter;
2681 if (image->type != ImageTypeBitmap)
2683 FIXME("Not implemented for type %d\n", image->type);
2684 return NotImplemented;
2687 if (((GpBitmap *)image)->prop_item)
2689 UINT i;
2691 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2693 if (propid == ((GpBitmap *)image)->prop_item[i].id)
2695 if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length)
2696 return InvalidParameter;
2698 *buffer = ((GpBitmap *)image)->prop_item[i];
2699 buffer->value = buffer + 1;
2700 memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length);
2701 return Ok;
2705 return PropertyNotFound;
2708 reader = ((GpBitmap *)image)->metadata_reader;
2709 if (!reader) return PropertyNotFound;
2711 id.vt = VT_UI2;
2712 id.u.uiVal = propid;
2713 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2714 if (FAILED(hr)) return PropertyNotFound;
2716 stat = propvariant_to_item(&value, buffer, size, propid);
2717 PropVariantClear(&value);
2719 return stat;
2722 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT *size, UINT *count)
2724 HRESULT hr;
2725 IWICMetadataReader *reader;
2726 IWICEnumMetadataItem *enumerator;
2727 UINT prop_count, prop_size, i;
2728 PROPVARIANT id, value;
2730 TRACE("(%p,%p,%p)\n", image, size, count);
2732 if (!image || !size || !count) return InvalidParameter;
2734 if (image->type != ImageTypeBitmap)
2736 FIXME("Not implemented for type %d\n", image->type);
2737 return NotImplemented;
2740 if (((GpBitmap *)image)->prop_item)
2742 *count = ((GpBitmap *)image)->prop_count;
2743 *size = 0;
2745 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2747 *size += sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2750 return Ok;
2753 reader = ((GpBitmap *)image)->metadata_reader;
2754 if (!reader) return PropertyNotFound;
2756 hr = IWICMetadataReader_GetCount(reader, &prop_count);
2757 if (FAILED(hr)) return hresult_to_status(hr);
2759 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2760 if (FAILED(hr)) return hresult_to_status(hr);
2762 IWICEnumMetadataItem_Reset(enumerator);
2764 prop_size = 0;
2766 PropVariantInit(&id);
2767 PropVariantInit(&value);
2769 for (i = 0; i < prop_count; i++)
2771 UINT items_returned, item_size;
2773 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2774 if (hr != S_OK) break;
2776 item_size = propvariant_size(&value);
2777 if (item_size) prop_size += sizeof(PropertyItem) + item_size;
2779 PropVariantClear(&id);
2780 PropVariantClear(&value);
2783 IWICEnumMetadataItem_Release(enumerator);
2785 if (hr != S_OK) return PropertyNotFound;
2787 *count = prop_count;
2788 *size = prop_size;
2789 return Ok;
2792 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
2793 UINT count, PropertyItem *buf)
2795 GpStatus status;
2796 HRESULT hr;
2797 IWICMetadataReader *reader;
2798 IWICEnumMetadataItem *enumerator;
2799 UINT prop_count, prop_size, i;
2800 PROPVARIANT id, value;
2801 char *item_value;
2803 TRACE("(%p,%u,%u,%p)\n", image, size, count, buf);
2805 if (!image || !buf) return InvalidParameter;
2807 if (image->type != ImageTypeBitmap)
2809 FIXME("Not implemented for type %d\n", image->type);
2810 return NotImplemented;
2813 status = GdipGetPropertySize(image, &prop_size, &prop_count);
2814 if (status != Ok) return status;
2816 if (prop_count != count || prop_size != size) return InvalidParameter;
2818 if (((GpBitmap *)image)->prop_item)
2820 memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size);
2822 item_value = (char *)(buf + prop_count);
2824 for (i = 0; i < prop_count; i++)
2826 buf[i].value = item_value;
2827 item_value += buf[i].length;
2830 return Ok;
2833 reader = ((GpBitmap *)image)->metadata_reader;
2834 if (!reader) return PropertyNotFound;
2836 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2837 if (FAILED(hr)) return hresult_to_status(hr);
2839 IWICEnumMetadataItem_Reset(enumerator);
2841 item_value = (char *)(buf + prop_count);
2843 PropVariantInit(&id);
2844 PropVariantInit(&value);
2846 for (i = 0; i < prop_count; i++)
2848 PropertyItem *item;
2849 UINT items_returned, item_size;
2851 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2852 if (hr != S_OK) break;
2854 if (id.vt != VT_UI2)
2856 FIXME("not supported propvariant type for id: %u\n", id.vt);
2857 continue;
2860 item_size = propvariant_size(&value);
2861 if (item_size)
2863 item = HeapAlloc(GetProcessHeap(), 0, item_size + sizeof(*item));
2865 propvariant_to_item(&value, item, item_size + sizeof(*item), id.u.uiVal);
2866 buf[i].id = item->id;
2867 buf[i].type = item->type;
2868 buf[i].length = item_size;
2869 buf[i].value = item_value;
2870 memcpy(item_value, item->value, item_size);
2871 item_value += item_size;
2873 HeapFree(GetProcessHeap(), 0, item);
2876 PropVariantClear(&id);
2877 PropVariantClear(&value);
2880 IWICEnumMetadataItem_Release(enumerator);
2882 if (hr != S_OK) return PropertyNotFound;
2884 return Ok;
2887 struct image_format_dimension
2889 const GUID *format;
2890 const GUID *dimension;
2893 static const struct image_format_dimension image_format_dimensions[] =
2895 {&ImageFormatGIF, &FrameDimensionTime},
2896 {&ImageFormatIcon, &FrameDimensionResolution},
2897 {NULL}
2900 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
2901 GDIPCONST GUID* dimensionID, UINT* count)
2903 TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
2905 if(!image || !count)
2906 return InvalidParameter;
2908 if (!dimensionID ||
2909 IsEqualGUID(dimensionID, &image->format) ||
2910 IsEqualGUID(dimensionID, &FrameDimensionPage) ||
2911 IsEqualGUID(dimensionID, &FrameDimensionTime))
2913 *count = image->frame_count;
2914 return Ok;
2917 return InvalidParameter;
2920 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
2921 UINT* count)
2923 TRACE("(%p, %p)\n", image, count);
2925 /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
2927 if(!image || !count)
2928 return InvalidParameter;
2930 *count = 1;
2932 return Ok;
2935 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
2936 GUID* dimensionIDs, UINT count)
2938 int i;
2939 const GUID *result=NULL;
2941 TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
2943 if(!image || !dimensionIDs || count != 1)
2944 return InvalidParameter;
2946 for (i=0; image_format_dimensions[i].format; i++)
2948 if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
2950 result = image_format_dimensions[i].dimension;
2951 break;
2955 if (!result)
2956 result = &FrameDimensionPage;
2958 memcpy(dimensionIDs, result, sizeof(GUID));
2960 return Ok;
2963 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
2964 GpImage **image)
2966 GpStatus stat;
2967 IStream *stream;
2969 TRACE("(%s) %p\n", debugstr_w(filename), image);
2971 if (!filename || !image)
2972 return InvalidParameter;
2974 *image = NULL;
2976 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
2978 if (stat != Ok)
2979 return stat;
2981 stat = GdipLoadImageFromStream(stream, image);
2983 IStream_Release(stream);
2985 return stat;
2988 /* FIXME: no icm handling */
2989 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
2991 TRACE("(%s) %p\n", debugstr_w(filename), image);
2993 return GdipLoadImageFromFile(filename, image);
2996 static void add_property(GpBitmap *bitmap, PropertyItem *item)
2998 UINT prop_size, prop_count;
2999 PropertyItem *prop_item;
3001 if (bitmap->prop_item == NULL)
3003 prop_size = prop_count = 0;
3004 prop_item = GdipAlloc(item->length + sizeof(PropertyItem));
3005 if (!prop_item) return;
3007 else
3009 UINT i;
3010 char *item_value;
3012 GdipGetPropertySize((GpImage *)bitmap, &prop_size, &prop_count);
3014 prop_item = GdipAlloc(prop_size + item->length + sizeof(PropertyItem));
3015 if (!prop_item) return;
3016 memcpy(prop_item, bitmap->prop_item, sizeof(PropertyItem) * bitmap->prop_count);
3017 prop_size -= sizeof(PropertyItem) * bitmap->prop_count;
3018 memcpy(prop_item + prop_count + 1, bitmap->prop_item + prop_count, prop_size);
3020 item_value = (char *)(prop_item + prop_count + 1);
3022 for (i = 0; i < prop_count; i++)
3024 prop_item[i].value = item_value;
3025 item_value += prop_item[i].length;
3029 prop_item[prop_count].id = item->id;
3030 prop_item[prop_count].type = item->type;
3031 prop_item[prop_count].length = item->length;
3032 prop_item[prop_count].value = (char *)(prop_item + prop_count + 1) + prop_size;
3033 memcpy(prop_item[prop_count].value, item->value, item->length);
3035 GdipFree(bitmap->prop_item);
3036 bitmap->prop_item = prop_item;
3037 bitmap->prop_count++;
3040 static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3042 HRESULT hr;
3043 GUID format;
3044 PROPVARIANT id, value;
3045 BOOL ret = FALSE;
3047 IWICMetadataReader_GetMetadataFormat(reader, &format);
3048 if (!IsEqualGUID(&format, guid)) return FALSE;
3050 PropVariantInit(&id);
3051 PropVariantInit(&value);
3053 id.vt = VT_LPWSTR;
3054 id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3055 if (!id.u.pwszVal) return FALSE;
3056 lstrcpyW(id.u.pwszVal, prop_name);
3057 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3058 if (hr == S_OK && value.vt == VT_BOOL)
3059 ret = value.u.boolVal;
3061 PropVariantClear(&id);
3062 PropVariantClear(&value);
3064 return ret;
3067 static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3069 HRESULT hr;
3070 GUID format;
3071 PROPVARIANT id, value;
3072 PropertyItem *item = NULL;
3074 IWICMetadataReader_GetMetadataFormat(reader, &format);
3075 if (!IsEqualGUID(&format, guid)) return NULL;
3077 PropVariantInit(&id);
3078 PropVariantInit(&value);
3080 id.vt = VT_LPWSTR;
3081 id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3082 if (!id.u.pwszVal) return NULL;
3083 lstrcpyW(id.u.pwszVal, prop_name);
3084 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3085 if (hr == S_OK)
3087 UINT item_size = propvariant_size(&value);
3088 if (item_size)
3090 item_size += sizeof(*item);
3091 item = GdipAlloc(item_size);
3092 if (propvariant_to_item(&value, item, item_size, 0) != Ok)
3094 GdipFree(item);
3095 item = NULL;
3100 PropVariantClear(&id);
3101 PropVariantClear(&value);
3103 return item;
3106 static PropertyItem *get_gif_comment(IWICMetadataReader *reader)
3108 static const WCHAR textentryW[] = { 'T','e','x','t','E','n','t','r','y',0 };
3109 PropertyItem *comment;
3111 comment = get_property(reader, &GUID_MetadataFormatGifComment, textentryW);
3112 if (comment)
3113 comment->id = PropertyTagExifUserComment;
3115 return comment;
3118 static PropertyItem *get_gif_loopcount(IWICMetadataReader *reader)
3120 static const WCHAR applicationW[] = { 'A','p','p','l','i','c','a','t','i','o','n',0 };
3121 static const WCHAR dataW[] = { 'D','a','t','a',0 };
3122 PropertyItem *appext = NULL, *appdata = NULL, *loop = NULL;
3124 appext = get_property(reader, &GUID_MetadataFormatAPE, applicationW);
3125 if (appext)
3127 if (appext->type == PropertyTagTypeByte && appext->length == 11 &&
3128 (!memcmp(appext->value, "NETSCAPE2.0", 11) || !memcmp(appext->value, "ANIMEXTS1.0", 11)))
3130 appdata = get_property(reader, &GUID_MetadataFormatAPE, dataW);
3131 if (appdata)
3133 if (appdata->type == PropertyTagTypeByte && appdata->length == 4)
3135 BYTE *data = appdata->value;
3136 if (data[0] == 3 && data[1] == 1)
3138 loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
3139 if (loop)
3141 loop->type = PropertyTagTypeShort;
3142 loop->id = PropertyTagLoopCount;
3143 loop->length = sizeof(SHORT);
3144 loop->value = loop + 1;
3145 *(SHORT *)loop->value = data[2] | (data[3] << 8);
3153 GdipFree(appext);
3154 GdipFree(appdata);
3156 return loop;
3159 static PropertyItem *get_gif_background(IWICMetadataReader *reader)
3161 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 };
3162 PropertyItem *background;
3164 background = get_property(reader, &GUID_MetadataFormatLSD, backgroundW);
3165 if (background)
3166 background->id = PropertyTagIndexBackground;
3168 return background;
3171 static PropertyItem *get_gif_palette(IWICBitmapDecoder *decoder, IWICMetadataReader *reader)
3173 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 };
3174 HRESULT hr;
3175 IWICImagingFactory *factory;
3176 IWICPalette *palette;
3177 UINT count = 0;
3178 WICColor colors[256];
3180 if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW))
3181 return NULL;
3183 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
3184 if (hr != S_OK) return NULL;
3186 hr = IWICImagingFactory_CreatePalette(factory, &palette);
3187 if (hr == S_OK)
3189 hr = IWICBitmapDecoder_CopyPalette(decoder, palette);
3190 if (hr == S_OK)
3191 IWICPalette_GetColors(palette, 256, colors, &count);
3193 IWICPalette_Release(palette);
3196 IWICImagingFactory_Release(factory);
3198 if (count)
3200 PropertyItem *pal;
3201 UINT i;
3202 BYTE *rgb;
3204 pal = GdipAlloc(sizeof(*pal) + count * 3);
3205 if (!pal) return NULL;
3206 pal->type = PropertyTagTypeByte;
3207 pal->id = PropertyTagGlobalPalette;
3208 pal->value = pal + 1;
3209 pal->length = count * 3;
3211 rgb = pal->value;
3213 for (i = 0; i < count; i++)
3215 rgb[i*3] = (colors[i] >> 16) & 0xff;
3216 rgb[i*3 + 1] = (colors[i] >> 8) & 0xff;
3217 rgb[i*3 + 2] = colors[i] & 0xff;
3220 return pal;
3223 return NULL;
3226 static PropertyItem *get_gif_transparent_idx(IWICMetadataReader *reader)
3228 static const WCHAR transparency_flagW[] = { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 };
3229 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 };
3230 PropertyItem *index = NULL;
3232 if (get_bool_property(reader, &GUID_MetadataFormatGCE, transparency_flagW))
3234 index = get_property(reader, &GUID_MetadataFormatGCE, colorW);
3235 if (index)
3236 index->id = PropertyTagIndexTransparent;
3238 return index;
3241 static LONG get_gif_frame_delay(IWICBitmapFrameDecode *frame)
3243 static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
3244 HRESULT hr;
3245 IWICMetadataBlockReader *block_reader;
3246 IWICMetadataReader *reader;
3247 UINT block_count, i;
3248 PropertyItem *delay;
3249 LONG value = 0;
3251 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3252 if (hr == S_OK)
3254 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3255 if (hr == S_OK)
3257 for (i = 0; i < block_count; i++)
3259 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3260 if (hr == S_OK)
3262 delay = get_property(reader, &GUID_MetadataFormatGCE, delayW);
3263 if (delay)
3265 if (delay->type == PropertyTagTypeShort && delay->length == 2)
3266 value = *(SHORT *)delay->value;
3268 GdipFree(delay);
3270 IWICMetadataReader_Release(reader);
3274 IWICMetadataBlockReader_Release(block_reader);
3277 return value;
3280 static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
3282 HRESULT hr;
3283 IWICBitmapFrameDecode *frame;
3284 IWICMetadataBlockReader *block_reader;
3285 IWICMetadataReader *reader;
3286 UINT frame_count, block_count, i;
3287 PropertyItem *delay = NULL, *comment = NULL, *background = NULL;
3288 PropertyItem *transparent_idx = NULL, *loop = NULL, *palette = NULL;
3290 IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3291 if (frame_count > 1)
3293 delay = GdipAlloc(sizeof(*delay) + frame_count * sizeof(LONG));
3294 if (delay)
3296 LONG *value;
3298 delay->type = PropertyTagTypeLong;
3299 delay->id = PropertyTagFrameDelay;
3300 delay->length = frame_count * sizeof(LONG);
3301 delay->value = delay + 1;
3303 value = delay->value;
3305 for (i = 0; i < frame_count; i++)
3307 hr = IWICBitmapDecoder_GetFrame(decoder, i, &frame);
3308 if (hr == S_OK)
3310 value[i] = get_gif_frame_delay(frame);
3311 IWICBitmapFrameDecode_Release(frame);
3313 else value[i] = 0;
3318 hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3319 if (hr == S_OK)
3321 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3322 if (hr == S_OK)
3324 for (i = 0; i < block_count; i++)
3326 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3327 if (hr == S_OK)
3329 if (!comment)
3330 comment = get_gif_comment(reader);
3332 if (frame_count > 1 && !loop)
3333 loop = get_gif_loopcount(reader);
3335 if (!background)
3336 background = get_gif_background(reader);
3338 if (!palette)
3339 palette = get_gif_palette(decoder, reader);
3341 IWICMetadataReader_Release(reader);
3345 IWICMetadataBlockReader_Release(block_reader);
3348 if (frame_count > 1 && !loop)
3350 loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
3351 if (loop)
3353 loop->type = PropertyTagTypeShort;
3354 loop->id = PropertyTagLoopCount;
3355 loop->length = sizeof(SHORT);
3356 loop->value = loop + 1;
3357 *(SHORT *)loop->value = 1;
3361 if (delay) add_property(bitmap, delay);
3362 if (comment) add_property(bitmap, comment);
3363 if (loop) add_property(bitmap, loop);
3364 if (palette) add_property(bitmap, palette);
3365 if (background) add_property(bitmap, background);
3367 GdipFree(delay);
3368 GdipFree(comment);
3369 GdipFree(loop);
3370 GdipFree(palette);
3371 GdipFree(background);
3373 /* Win7 gdiplus always returns transparent color index from frame 0 */
3374 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
3375 if (hr != S_OK) return;
3377 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3378 if (hr == S_OK)
3380 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3381 if (hr == S_OK)
3383 for (i = 0; i < block_count; i++)
3385 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3386 if (hr == S_OK)
3388 if (!transparent_idx)
3389 transparent_idx = get_gif_transparent_idx(reader);
3391 IWICMetadataReader_Release(reader);
3395 IWICMetadataBlockReader_Release(block_reader);
3398 if (transparent_idx) add_property(bitmap, transparent_idx);
3399 GdipFree(transparent_idx);
3401 IWICBitmapFrameDecode_Release(frame);
3404 typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame);
3406 static GpStatus decode_image_wic(IStream *stream, REFGUID container,
3407 UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
3409 GpStatus status=Ok;
3410 GpBitmap *bitmap;
3411 HRESULT hr;
3412 IWICImagingFactory *factory;
3413 IWICBitmapDecoder *decoder;
3414 IWICBitmapFrameDecode *frame;
3415 IWICBitmapSource *source=NULL;
3416 IWICMetadataBlockReader *block_reader;
3417 WICPixelFormatGUID wic_format;
3418 PixelFormat gdip_format=0;
3419 ColorPalette *palette = NULL;
3420 WICBitmapPaletteType palette_type = WICBitmapPaletteTypeFixedHalftone256;
3421 int i;
3422 UINT width, height, frame_count;
3423 BitmapData lockeddata;
3424 WICRect wrc;
3426 TRACE("%p,%s,%u,%p\n", stream, wine_dbgstr_guid(container), active_frame, image);
3428 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
3429 if (FAILED(hr)) goto end;
3430 hr = IWICImagingFactory_CreateDecoder(factory, container, NULL, &decoder);
3431 IWICImagingFactory_Release(factory);
3432 if (FAILED(hr)) goto end;
3434 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
3435 if (SUCCEEDED(hr))
3437 IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3438 hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
3441 if (SUCCEEDED(hr)) /* got frame */
3443 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
3445 if (SUCCEEDED(hr))
3447 IWICBitmapSource *bmp_source;
3448 IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICBitmapSource, (void **)&bmp_source);
3450 for (i=0; pixel_formats[i].wic_format; i++)
3452 if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format))
3454 source = bmp_source;
3455 gdip_format = pixel_formats[i].gdip_format;
3456 palette_type = pixel_formats[i].palette_type;
3457 break;
3460 if (!source)
3462 /* unknown format; fall back on 32bppARGB */
3463 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bmp_source, &source);
3464 gdip_format = PixelFormat32bppARGB;
3465 IWICBitmapSource_Release(bmp_source);
3467 TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format);
3470 if (SUCCEEDED(hr)) /* got source */
3472 hr = IWICBitmapSource_GetSize(source, &width, &height);
3474 if (SUCCEEDED(hr))
3475 status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
3476 NULL, &bitmap);
3478 if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
3480 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
3481 gdip_format, &lockeddata);
3482 if (status == Ok) /* locked bitmap */
3484 wrc.X = 0;
3485 wrc.Width = width;
3486 wrc.Height = 1;
3487 for (i=0; i<height; i++)
3489 wrc.Y = i;
3490 hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
3491 abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
3492 if (FAILED(hr)) break;
3495 GdipBitmapUnlockBits(bitmap, &lockeddata);
3498 if (SUCCEEDED(hr) && status == Ok)
3499 *image = (GpImage*)bitmap;
3500 else
3502 *image = NULL;
3503 GdipDisposeImage((GpImage*)bitmap);
3506 if (SUCCEEDED(hr) && status == Ok)
3508 double dpix, dpiy;
3509 hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy);
3510 if (SUCCEEDED(hr))
3512 bitmap->image.xres = dpix;
3513 bitmap->image.yres = dpiy;
3515 hr = S_OK;
3519 IWICBitmapSource_Release(source);
3522 if (SUCCEEDED(hr)) {
3523 bitmap->metadata_reader = NULL;
3525 if (metadata_reader)
3526 metadata_reader(bitmap, decoder, active_frame);
3527 else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK)
3529 UINT block_count = 0;
3530 if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count)
3531 IWICMetadataBlockReader_GetReaderByIndex(block_reader, 0, &bitmap->metadata_reader);
3532 IWICMetadataBlockReader_Release(block_reader);
3535 palette = get_palette(frame, palette_type);
3536 IWICBitmapFrameDecode_Release(frame);
3540 IWICBitmapDecoder_Release(decoder);
3542 end:
3543 if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
3545 if (status == Ok)
3547 /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
3548 bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB;
3549 bitmap->image.frame_count = frame_count;
3550 bitmap->image.current_frame = active_frame;
3551 bitmap->image.stream = stream;
3552 if (palette)
3554 GdipFree(bitmap->image.palette);
3555 bitmap->image.palette = palette;
3557 else
3559 if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite))
3560 bitmap->image.palette->Flags = 0;
3562 /* Pin the source stream */
3563 IStream_AddRef(stream);
3564 TRACE("=> %p\n", *image);
3567 return status;
3570 static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3572 return decode_image_wic(stream, &GUID_ContainerFormatIco, active_frame, NULL, image);
3575 static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3577 GpStatus status;
3578 GpBitmap* bitmap;
3580 status = decode_image_wic(stream, &GUID_ContainerFormatBmp, active_frame, NULL, image);
3582 bitmap = (GpBitmap*)*image;
3584 if (status == Ok && bitmap->format == PixelFormat32bppARGB)
3586 /* WIC supports bmp files with alpha, but gdiplus does not */
3587 bitmap->format = PixelFormat32bppRGB;
3590 return status;
3593 static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3595 return decode_image_wic(stream, &GUID_ContainerFormatJpeg, active_frame, NULL, image);
3598 static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3600 return decode_image_wic(stream, &GUID_ContainerFormatPng, active_frame, NULL, image);
3603 static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3605 return decode_image_wic(stream, &GUID_ContainerFormatGif, active_frame, gif_metadata_reader, image);
3608 static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3610 return decode_image_wic(stream, &GUID_ContainerFormatTiff, active_frame, NULL, image);
3613 static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
3615 IPicture *pic;
3617 TRACE("%p %p\n", stream, image);
3619 if(!stream || !image)
3620 return InvalidParameter;
3622 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
3623 (LPVOID*) &pic) != S_OK){
3624 TRACE("Could not load picture\n");
3625 return GenericError;
3628 /* FIXME: missing initialization code */
3629 *image = GdipAlloc(sizeof(GpMetafile));
3630 if(!*image) return OutOfMemory;
3631 (*image)->type = ImageTypeMetafile;
3632 (*image)->stream = NULL;
3633 (*image)->picture = pic;
3634 (*image)->flags = ImageFlagsNone;
3635 (*image)->frame_count = 1;
3636 (*image)->current_frame = 0;
3637 (*image)->palette = NULL;
3639 TRACE("<-- %p\n", *image);
3641 return Ok;
3644 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
3645 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
3647 typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, UINT active_frame, GpImage **image);
3649 typedef struct image_codec {
3650 ImageCodecInfo info;
3651 encode_image_func encode_func;
3652 decode_image_func decode_func;
3653 } image_codec;
3655 typedef enum {
3656 BMP,
3657 JPEG,
3658 GIF,
3659 TIFF,
3660 EMF,
3661 WMF,
3662 PNG,
3663 ICO,
3664 NUM_CODECS
3665 } ImageFormat;
3667 static const struct image_codec codecs[NUM_CODECS];
3669 static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
3671 BYTE signature[8];
3672 const BYTE *pattern, *mask;
3673 LARGE_INTEGER seek;
3674 HRESULT hr;
3675 UINT bytesread;
3676 int i;
3677 DWORD j, sig;
3679 /* seek to the start of the stream */
3680 seek.QuadPart = 0;
3681 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
3682 if (FAILED(hr)) return hresult_to_status(hr);
3684 /* read the first 8 bytes */
3685 /* FIXME: This assumes all codecs have signatures <= 8 bytes in length */
3686 hr = IStream_Read(stream, signature, 8, &bytesread);
3687 if (FAILED(hr)) return hresult_to_status(hr);
3688 if (hr == S_FALSE || bytesread == 0) return GenericError;
3690 for (i = 0; i < NUM_CODECS; i++) {
3691 if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
3692 bytesread >= codecs[i].info.SigSize)
3694 for (sig=0; sig<codecs[i].info.SigCount; sig++)
3696 pattern = &codecs[i].info.SigPattern[codecs[i].info.SigSize*sig];
3697 mask = &codecs[i].info.SigMask[codecs[i].info.SigSize*sig];
3698 for (j=0; j<codecs[i].info.SigSize; j++)
3699 if ((signature[j] & mask[j]) != pattern[j])
3700 break;
3701 if (j == codecs[i].info.SigSize)
3703 *result = &codecs[i];
3704 return Ok;
3710 TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
3711 signature[0],signature[1],signature[2],signature[3],
3712 signature[4],signature[5],signature[6],signature[7]);
3714 return GenericError;
3717 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *dimensionID,
3718 UINT frame)
3720 GpStatus stat;
3721 LARGE_INTEGER seek;
3722 HRESULT hr;
3723 const struct image_codec *codec = NULL;
3724 GpImage *new_image;
3726 TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
3728 if (!image || !dimensionID)
3729 return InvalidParameter;
3731 if (frame >= image->frame_count)
3733 WARN("requested frame %u, but image has only %u\n", frame, image->frame_count);
3734 return InvalidParameter;
3737 if (image->type != ImageTypeBitmap && image->type != ImageTypeMetafile)
3739 WARN("invalid image type %d\n", image->type);
3740 return InvalidParameter;
3743 if (image->current_frame == frame)
3744 return Ok;
3746 if (!image->stream)
3748 TRACE("image doesn't have an associated stream\n");
3749 return Ok;
3752 /* choose an appropriate image decoder */
3753 stat = get_decoder_info(image->stream, &codec);
3754 if (stat != Ok)
3756 WARN("can't find decoder info\n");
3757 return stat;
3760 /* seek to the start of the stream */
3761 seek.QuadPart = 0;
3762 hr = IStream_Seek(image->stream, seek, STREAM_SEEK_SET, NULL);
3763 if (FAILED(hr))
3764 return hresult_to_status(hr);
3766 /* call on the image decoder to do the real work */
3767 stat = codec->decode_func(image->stream, &codec->info.Clsid, frame, &new_image);
3769 if (stat == Ok)
3771 memcpy(&new_image->format, &codec->info.FormatID, sizeof(GUID));
3772 free_image_data(image);
3773 if (image->type == ImageTypeBitmap)
3774 *(GpBitmap *)image = *(GpBitmap *)new_image;
3775 else if (image->type == ImageTypeMetafile)
3776 *(GpMetafile *)image = *(GpMetafile *)new_image;
3777 new_image->type = ~0;
3778 GdipFree(new_image);
3779 return Ok;
3782 return stat;
3785 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
3787 GpStatus stat;
3788 LARGE_INTEGER seek;
3789 HRESULT hr;
3790 const struct image_codec *codec=NULL;
3792 /* choose an appropriate image decoder */
3793 stat = get_decoder_info(stream, &codec);
3794 if (stat != Ok) return stat;
3796 /* seek to the start of the stream */
3797 seek.QuadPart = 0;
3798 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
3799 if (FAILED(hr)) return hresult_to_status(hr);
3801 /* call on the image decoder to do the real work */
3802 stat = codec->decode_func(stream, &codec->info.Clsid, 0, image);
3804 /* take note of the original data format */
3805 if (stat == Ok)
3807 memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
3808 return Ok;
3811 return stat;
3814 /* FIXME: no ICM */
3815 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
3817 TRACE("%p %p\n", stream, image);
3819 return GdipLoadImageFromStream(stream, image);
3822 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
3824 static int calls;
3826 TRACE("(%p,%u)\n", image, propId);
3828 if(!image)
3829 return InvalidParameter;
3831 if(!(calls++))
3832 FIXME("not implemented\n");
3834 return NotImplemented;
3837 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
3839 static int calls;
3841 if (!image || !item) return InvalidParameter;
3843 TRACE("(%p,%p:%#x,%u,%u,%p)\n", image, item, item->id, item->type, item->length, item->value);
3845 if(!(calls++))
3846 FIXME("not implemented\n");
3848 return Ok;
3851 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
3852 GDIPCONST CLSID *clsidEncoder,
3853 GDIPCONST EncoderParameters *encoderParams)
3855 GpStatus stat;
3856 IStream *stream;
3858 TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
3860 if (!image || !filename|| !clsidEncoder)
3861 return InvalidParameter;
3863 stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
3864 if (stat != Ok)
3865 return GenericError;
3867 stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
3869 IStream_Release(stream);
3870 return stat;
3873 /*************************************************************************
3874 * Encoding functions -
3875 * These functions encode an image in different image file formats.
3878 static GpStatus encode_image_wic(GpImage *image, IStream* stream,
3879 REFGUID container, GDIPCONST EncoderParameters* params)
3881 GpStatus stat;
3882 GpBitmap *bitmap;
3883 IWICImagingFactory *factory;
3884 IWICBitmapEncoder *encoder;
3885 IWICBitmapFrameEncode *frameencode;
3886 IPropertyBag2 *encoderoptions;
3887 HRESULT hr;
3888 UINT width, height;
3889 PixelFormat gdipformat=0;
3890 const WICPixelFormatGUID *desired_wicformat;
3891 WICPixelFormatGUID wicformat;
3892 GpRect rc;
3893 BitmapData lockeddata;
3894 UINT i;
3896 if (image->type != ImageTypeBitmap)
3897 return GenericError;
3899 bitmap = (GpBitmap*)image;
3901 GdipGetImageWidth(image, &width);
3902 GdipGetImageHeight(image, &height);
3904 rc.X = 0;
3905 rc.Y = 0;
3906 rc.Width = width;
3907 rc.Height = height;
3909 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
3910 if (FAILED(hr))
3911 return hresult_to_status(hr);
3912 hr = IWICImagingFactory_CreateEncoder(factory, container, NULL, &encoder);
3913 IWICImagingFactory_Release(factory);
3914 if (FAILED(hr))
3915 return hresult_to_status(hr);
3917 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
3919 if (SUCCEEDED(hr))
3921 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
3924 if (SUCCEEDED(hr)) /* created frame */
3926 hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
3928 if (SUCCEEDED(hr))
3929 hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
3931 if (SUCCEEDED(hr))
3932 hr = IWICBitmapFrameEncode_SetResolution(frameencode, image->xres, image->yres);
3934 if (SUCCEEDED(hr))
3936 for (i=0; pixel_formats[i].wic_format; i++)
3938 if (pixel_formats[i].gdip_format == bitmap->format)
3940 desired_wicformat = pixel_formats[i].wic_format;
3941 gdipformat = bitmap->format;
3942 break;
3945 if (!gdipformat)
3947 desired_wicformat = &GUID_WICPixelFormat32bppBGRA;
3948 gdipformat = PixelFormat32bppARGB;
3951 memcpy(&wicformat, desired_wicformat, sizeof(GUID));
3952 hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
3955 if (SUCCEEDED(hr) && !IsEqualGUID(desired_wicformat, &wicformat))
3957 /* Encoder doesn't support this bitmap's format. */
3958 gdipformat = 0;
3959 for (i=0; pixel_formats[i].wic_format; i++)
3961 if (IsEqualGUID(&wicformat, pixel_formats[i].wic_format))
3963 gdipformat = pixel_formats[i].gdip_format;
3964 break;
3967 if (!gdipformat)
3969 ERR("Cannot support encoder format %s\n", debugstr_guid(&wicformat));
3970 hr = E_FAIL;
3974 if (SUCCEEDED(hr))
3976 stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
3977 &lockeddata);
3979 if (stat == Ok)
3981 UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
3982 BYTE *row;
3984 /* write one row at a time in case stride is negative */
3985 row = lockeddata.Scan0;
3986 for (i=0; i<lockeddata.Height; i++)
3988 hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
3989 if (FAILED(hr)) break;
3990 row += lockeddata.Stride;
3993 GdipBitmapUnlockBits(bitmap, &lockeddata);
3995 else
3996 hr = E_FAIL;
3999 if (SUCCEEDED(hr))
4000 hr = IWICBitmapFrameEncode_Commit(frameencode);
4002 IWICBitmapFrameEncode_Release(frameencode);
4003 IPropertyBag2_Release(encoderoptions);
4006 if (SUCCEEDED(hr))
4007 hr = IWICBitmapEncoder_Commit(encoder);
4009 IWICBitmapEncoder_Release(encoder);
4010 return hresult_to_status(hr);
4013 static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
4014 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4016 return encode_image_wic(image, stream, &GUID_ContainerFormatBmp, params);
4019 static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
4020 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4022 return encode_image_wic(image, stream, &GUID_ContainerFormatTiff, params);
4025 static GpStatus encode_image_png(GpImage *image, IStream* stream,
4026 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4028 return encode_image_wic(image, stream, &GUID_ContainerFormatPng, params);
4031 static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
4032 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4034 return encode_image_wic(image, stream, &GUID_ContainerFormatJpeg, params);
4037 /*****************************************************************************
4038 * GdipSaveImageToStream [GDIPLUS.@]
4040 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
4041 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
4043 GpStatus stat;
4044 encode_image_func encode_image;
4045 int i;
4047 TRACE("%p %p %p %p\n", image, stream, clsid, params);
4049 if(!image || !stream)
4050 return InvalidParameter;
4052 /* select correct encoder */
4053 encode_image = NULL;
4054 for (i = 0; i < NUM_CODECS; i++) {
4055 if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
4056 IsEqualCLSID(clsid, &codecs[i].info.Clsid))
4057 encode_image = codecs[i].encode_func;
4059 if (encode_image == NULL)
4060 return UnknownImageFormat;
4062 stat = encode_image(image, stream, clsid, params);
4064 return stat;
4067 /*****************************************************************************
4068 * GdipSaveAdd [GDIPLUS.@]
4070 GpStatus WINGDIPAPI GdipSaveAdd(GpImage *image, GDIPCONST EncoderParameters *params)
4072 FIXME("(%p,%p): stub\n", image, params);
4073 return Ok;
4076 /*****************************************************************************
4077 * GdipGetImagePalette [GDIPLUS.@]
4079 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
4081 INT count;
4083 TRACE("(%p,%p,%i)\n", image, palette, size);
4085 if (!image || !palette)
4086 return InvalidParameter;
4088 count = image->palette ? image->palette->Count : 0;
4090 if (size < (sizeof(UINT)*2+sizeof(ARGB)*count))
4092 TRACE("<-- InsufficientBuffer\n");
4093 return InsufficientBuffer;
4096 if (image->palette)
4098 palette->Flags = image->palette->Flags;
4099 palette->Count = image->palette->Count;
4100 memcpy(palette->Entries, image->palette->Entries, sizeof(ARGB)*image->palette->Count);
4102 else
4104 palette->Flags = 0;
4105 palette->Count = 0;
4107 return Ok;
4110 /*****************************************************************************
4111 * GdipSetImagePalette [GDIPLUS.@]
4113 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
4114 GDIPCONST ColorPalette *palette)
4116 ColorPalette *new_palette;
4118 TRACE("(%p,%p)\n", image, palette);
4120 if(!image || !palette || palette->Count > 256)
4121 return InvalidParameter;
4123 new_palette = GdipAlloc(2 * sizeof(UINT) + palette->Count * sizeof(ARGB));
4124 if (!new_palette) return OutOfMemory;
4126 GdipFree(image->palette);
4127 image->palette = new_palette;
4128 image->palette->Flags = palette->Flags;
4129 image->palette->Count = palette->Count;
4130 memcpy(image->palette->Entries, palette->Entries, sizeof(ARGB)*palette->Count);
4132 return Ok;
4135 /*************************************************************************
4136 * Encoders -
4137 * Structures that represent which formats we support for encoding.
4140 /* ImageCodecInfo creation routines taken from libgdiplus */
4141 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */
4142 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
4143 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
4144 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
4145 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
4146 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
4148 static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
4149 static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
4150 static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
4151 static const WCHAR jpeg_format[] = {'J','P','E','G',0};
4152 static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
4153 static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
4155 static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
4156 static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
4157 static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
4158 static const WCHAR gif_format[] = {'G','I','F',0};
4159 static const BYTE gif_sig_pattern[12] = "GIF87aGIF89a";
4160 static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4162 static const WCHAR tiff_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'T','I','F','F', 0};
4163 static const WCHAR tiff_extension[] = {'*','.','T','I','F','F',';','*','.','T','I','F',0};
4164 static const WCHAR tiff_mimetype[] = {'i','m','a','g','e','/','t','i','f','f', 0};
4165 static const WCHAR tiff_format[] = {'T','I','F','F',0};
4166 static const BYTE tiff_sig_pattern[] = {0x49,0x49,42,0,0x4d,0x4d,0,42};
4167 static const BYTE tiff_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4169 static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
4170 static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
4171 static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
4172 static const WCHAR emf_format[] = {'E','M','F',0};
4173 static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
4174 static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
4176 static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
4177 static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
4178 static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
4179 static const WCHAR wmf_format[] = {'W','M','F',0};
4180 static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
4181 static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
4183 static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
4184 static const WCHAR png_extension[] = {'*','.','P','N','G',0};
4185 static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
4186 static const WCHAR png_format[] = {'P','N','G',0};
4187 static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
4188 static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
4190 static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
4191 static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
4192 static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
4193 static const WCHAR ico_format[] = {'I','C','O',0};
4194 static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
4195 static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
4197 static const struct image_codec codecs[NUM_CODECS] = {
4199 { /* BMP */
4200 /* Clsid */ { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4201 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4202 /* CodecName */ bmp_codecname,
4203 /* DllName */ NULL,
4204 /* FormatDescription */ bmp_format,
4205 /* FilenameExtension */ bmp_extension,
4206 /* MimeType */ bmp_mimetype,
4207 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4208 /* Version */ 1,
4209 /* SigCount */ 1,
4210 /* SigSize */ 2,
4211 /* SigPattern */ bmp_sig_pattern,
4212 /* SigMask */ bmp_sig_mask,
4214 encode_image_BMP,
4215 decode_image_bmp
4218 { /* JPEG */
4219 /* Clsid */ { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4220 /* FormatID */ { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4221 /* CodecName */ jpeg_codecname,
4222 /* DllName */ NULL,
4223 /* FormatDescription */ jpeg_format,
4224 /* FilenameExtension */ jpeg_extension,
4225 /* MimeType */ jpeg_mimetype,
4226 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4227 /* Version */ 1,
4228 /* SigCount */ 1,
4229 /* SigSize */ 2,
4230 /* SigPattern */ jpeg_sig_pattern,
4231 /* SigMask */ jpeg_sig_mask,
4233 encode_image_jpeg,
4234 decode_image_jpeg
4237 { /* GIF */
4238 /* Clsid */ { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4239 /* FormatID */ { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4240 /* CodecName */ gif_codecname,
4241 /* DllName */ NULL,
4242 /* FormatDescription */ gif_format,
4243 /* FilenameExtension */ gif_extension,
4244 /* MimeType */ gif_mimetype,
4245 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4246 /* Version */ 1,
4247 /* SigCount */ 2,
4248 /* SigSize */ 6,
4249 /* SigPattern */ gif_sig_pattern,
4250 /* SigMask */ gif_sig_mask,
4252 NULL,
4253 decode_image_gif
4256 { /* TIFF */
4257 /* Clsid */ { 0x557cf405, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4258 /* FormatID */ { 0xb96b3cb1U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4259 /* CodecName */ tiff_codecname,
4260 /* DllName */ NULL,
4261 /* FormatDescription */ tiff_format,
4262 /* FilenameExtension */ tiff_extension,
4263 /* MimeType */ tiff_mimetype,
4264 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsEncoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4265 /* Version */ 1,
4266 /* SigCount */ 2,
4267 /* SigSize */ 4,
4268 /* SigPattern */ tiff_sig_pattern,
4269 /* SigMask */ tiff_sig_mask,
4271 encode_image_tiff,
4272 decode_image_tiff
4275 { /* EMF */
4276 /* Clsid */ { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4277 /* FormatID */ { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4278 /* CodecName */ emf_codecname,
4279 /* DllName */ NULL,
4280 /* FormatDescription */ emf_format,
4281 /* FilenameExtension */ emf_extension,
4282 /* MimeType */ emf_mimetype,
4283 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
4284 /* Version */ 1,
4285 /* SigCount */ 1,
4286 /* SigSize */ 4,
4287 /* SigPattern */ emf_sig_pattern,
4288 /* SigMask */ emf_sig_mask,
4290 NULL,
4291 decode_image_olepicture_metafile
4294 { /* WMF */
4295 /* Clsid */ { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4296 /* FormatID */ { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4297 /* CodecName */ wmf_codecname,
4298 /* DllName */ NULL,
4299 /* FormatDescription */ wmf_format,
4300 /* FilenameExtension */ wmf_extension,
4301 /* MimeType */ wmf_mimetype,
4302 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
4303 /* Version */ 1,
4304 /* SigCount */ 1,
4305 /* SigSize */ 2,
4306 /* SigPattern */ wmf_sig_pattern,
4307 /* SigMask */ wmf_sig_mask,
4309 NULL,
4310 decode_image_olepicture_metafile
4313 { /* PNG */
4314 /* Clsid */ { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4315 /* FormatID */ { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4316 /* CodecName */ png_codecname,
4317 /* DllName */ NULL,
4318 /* FormatDescription */ png_format,
4319 /* FilenameExtension */ png_extension,
4320 /* MimeType */ png_mimetype,
4321 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4322 /* Version */ 1,
4323 /* SigCount */ 1,
4324 /* SigSize */ 8,
4325 /* SigPattern */ png_sig_pattern,
4326 /* SigMask */ png_sig_mask,
4328 encode_image_png,
4329 decode_image_png
4332 { /* ICO */
4333 /* Clsid */ { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
4334 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
4335 /* CodecName */ ico_codecname,
4336 /* DllName */ NULL,
4337 /* FormatDescription */ ico_format,
4338 /* FilenameExtension */ ico_extension,
4339 /* MimeType */ ico_mimetype,
4340 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
4341 /* Version */ 1,
4342 /* SigCount */ 1,
4343 /* SigSize */ 4,
4344 /* SigPattern */ ico_sig_pattern,
4345 /* SigMask */ ico_sig_mask,
4347 NULL,
4348 decode_image_icon
4352 /*****************************************************************************
4353 * GdipGetImageDecodersSize [GDIPLUS.@]
4355 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
4357 int decoder_count=0;
4358 int i;
4359 TRACE("%p %p\n", numDecoders, size);
4361 if (!numDecoders || !size)
4362 return InvalidParameter;
4364 for (i=0; i<NUM_CODECS; i++)
4366 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
4367 decoder_count++;
4370 *numDecoders = decoder_count;
4371 *size = decoder_count * sizeof(ImageCodecInfo);
4373 return Ok;
4376 /*****************************************************************************
4377 * GdipGetImageDecoders [GDIPLUS.@]
4379 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
4381 int i, decoder_count=0;
4382 TRACE("%u %u %p\n", numDecoders, size, decoders);
4384 if (!decoders ||
4385 size != numDecoders * sizeof(ImageCodecInfo))
4386 return GenericError;
4388 for (i=0; i<NUM_CODECS; i++)
4390 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
4392 if (decoder_count == numDecoders) return GenericError;
4393 memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
4394 decoder_count++;
4398 if (decoder_count < numDecoders) return GenericError;
4400 return Ok;
4403 /*****************************************************************************
4404 * GdipGetImageEncodersSize [GDIPLUS.@]
4406 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
4408 int encoder_count=0;
4409 int i;
4410 TRACE("%p %p\n", numEncoders, size);
4412 if (!numEncoders || !size)
4413 return InvalidParameter;
4415 for (i=0; i<NUM_CODECS; i++)
4417 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
4418 encoder_count++;
4421 *numEncoders = encoder_count;
4422 *size = encoder_count * sizeof(ImageCodecInfo);
4424 return Ok;
4427 /*****************************************************************************
4428 * GdipGetImageEncoders [GDIPLUS.@]
4430 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
4432 int i, encoder_count=0;
4433 TRACE("%u %u %p\n", numEncoders, size, encoders);
4435 if (!encoders ||
4436 size != numEncoders * sizeof(ImageCodecInfo))
4437 return GenericError;
4439 for (i=0; i<NUM_CODECS; i++)
4441 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
4443 if (encoder_count == numEncoders) return GenericError;
4444 memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
4445 encoder_count++;
4449 if (encoder_count < numEncoders) return GenericError;
4451 return Ok;
4454 GpStatus WINGDIPAPI GdipGetEncoderParameterListSize(GpImage *image,
4455 GDIPCONST CLSID* clsidEncoder, UINT *size)
4457 static int calls;
4459 TRACE("(%p,%s,%p)\n", image, debugstr_guid(clsidEncoder), size);
4461 if(!(calls++))
4462 FIXME("not implemented\n");
4464 *size = 0;
4466 return NotImplemented;
4469 static PixelFormat get_16bpp_format(HBITMAP hbm)
4471 BITMAPV4HEADER bmh;
4472 HDC hdc;
4473 PixelFormat result;
4475 hdc = CreateCompatibleDC(NULL);
4477 memset(&bmh, 0, sizeof(bmh));
4478 bmh.bV4Size = sizeof(bmh);
4479 bmh.bV4Width = 1;
4480 bmh.bV4Height = 1;
4481 bmh.bV4V4Compression = BI_BITFIELDS;
4482 bmh.bV4BitCount = 16;
4484 GetDIBits(hdc, hbm, 0, 0, NULL, (BITMAPINFO*)&bmh, DIB_RGB_COLORS);
4486 if (bmh.bV4RedMask == 0x7c00 &&
4487 bmh.bV4GreenMask == 0x3e0 &&
4488 bmh.bV4BlueMask == 0x1f)
4490 result = PixelFormat16bppRGB555;
4492 else if (bmh.bV4RedMask == 0xf800 &&
4493 bmh.bV4GreenMask == 0x7e0 &&
4494 bmh.bV4BlueMask == 0x1f)
4496 result = PixelFormat16bppRGB565;
4498 else
4500 FIXME("unrecognized bitfields %x,%x,%x\n", bmh.bV4RedMask,
4501 bmh.bV4GreenMask, bmh.bV4BlueMask);
4502 result = PixelFormatUndefined;
4505 DeleteDC(hdc);
4507 return result;
4510 /*****************************************************************************
4511 * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
4513 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
4515 BITMAP bm;
4516 GpStatus retval;
4517 PixelFormat format;
4518 BitmapData lockeddata;
4520 TRACE("%p %p %p\n", hbm, hpal, bitmap);
4522 if(!hbm || !bitmap)
4523 return InvalidParameter;
4525 if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm))
4526 return InvalidParameter;
4528 /* TODO: Figure out the correct format for 16, 32, 64 bpp */
4529 switch(bm.bmBitsPixel) {
4530 case 1:
4531 format = PixelFormat1bppIndexed;
4532 break;
4533 case 4:
4534 format = PixelFormat4bppIndexed;
4535 break;
4536 case 8:
4537 format = PixelFormat8bppIndexed;
4538 break;
4539 case 16:
4540 format = get_16bpp_format(hbm);
4541 if (format == PixelFormatUndefined)
4542 return InvalidParameter;
4543 break;
4544 case 24:
4545 format = PixelFormat24bppRGB;
4546 break;
4547 case 32:
4548 format = PixelFormat32bppRGB;
4549 break;
4550 case 48:
4551 format = PixelFormat48bppRGB;
4552 break;
4553 default:
4554 FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel);
4555 return InvalidParameter;
4558 retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, 0,
4559 format, NULL, bitmap);
4561 if (retval == Ok)
4563 retval = GdipBitmapLockBits(*bitmap, NULL, ImageLockModeWrite,
4564 format, &lockeddata);
4565 if (retval == Ok)
4567 HDC hdc;
4568 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
4569 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
4570 INT src_height;
4572 hdc = CreateCompatibleDC(NULL);
4574 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
4575 pbmi->bmiHeader.biBitCount = 0;
4577 GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
4579 src_height = abs(pbmi->bmiHeader.biHeight);
4580 pbmi->bmiHeader.biHeight = -src_height;
4582 GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
4584 DeleteDC(hdc);
4586 GdipBitmapUnlockBits(*bitmap, &lockeddata);
4589 if (retval == Ok && hpal)
4591 PALETTEENTRY entry[256];
4592 ColorPalette *palette=NULL;
4593 int i, num_palette_entries;
4595 num_palette_entries = GetPaletteEntries(hpal, 0, 256, entry);
4596 if (!num_palette_entries)
4597 retval = GenericError;
4599 palette = GdipAlloc(sizeof(ColorPalette) + sizeof(ARGB) * (num_palette_entries-1));
4600 if (!palette)
4601 retval = OutOfMemory;
4603 if (retval == Ok)
4605 palette->Flags = 0;
4606 palette->Count = num_palette_entries;
4608 for (i=0; i<num_palette_entries; i++)
4610 palette->Entries[i] = 0xff000000 | entry[i].peRed << 16 |
4611 entry[i].peGreen << 8 | entry[i].peBlue;
4614 retval = GdipSetImagePalette((GpImage*)*bitmap, palette);
4617 GdipFree(palette);
4620 if (retval != Ok)
4622 GdipDisposeImage((GpImage*)*bitmap);
4623 *bitmap = NULL;
4627 return retval;
4630 GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect)
4632 FIXME("(%p): stub\n", effect);
4633 /* note: According to Jose Roca's GDI+ Docs, this is not implemented
4634 * in Windows's gdiplus */
4635 return NotImplemented;
4638 /*****************************************************************************
4639 * GdipSetEffectParameters [GDIPLUS.@]
4641 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
4642 const VOID *params, const UINT size)
4644 static int calls;
4646 TRACE("(%p,%p,%u)\n", effect, params, size);
4648 if(!(calls++))
4649 FIXME("not implemented\n");
4651 return NotImplemented;
4654 /*****************************************************************************
4655 * GdipGetImageFlags [GDIPLUS.@]
4657 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
4659 TRACE("%p %p\n", image, flags);
4661 if(!image || !flags)
4662 return InvalidParameter;
4664 *flags = image->flags;
4666 return Ok;
4669 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
4671 TRACE("(%d, %p)\n", control, param);
4673 switch(control){
4674 case TestControlForceBilinear:
4675 if(param)
4676 FIXME("TestControlForceBilinear not handled\n");
4677 break;
4678 case TestControlNoICM:
4679 if(param)
4680 FIXME("TestControlNoICM not handled\n");
4681 break;
4682 case TestControlGetBuildNumber:
4683 *((DWORD*)param) = 3102;
4684 break;
4687 return Ok;
4690 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
4692 TRACE("%p\n", image);
4694 return Ok;
4697 /*****************************************************************************
4698 * GdipGetImageThumbnail [GDIPLUS.@]
4700 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
4701 GpImage **ret_image, GetThumbnailImageAbort cb,
4702 VOID * cb_data)
4704 GpStatus stat;
4705 GpGraphics *graphics;
4706 UINT srcwidth, srcheight;
4708 TRACE("(%p %u %u %p %p %p)\n",
4709 image, width, height, ret_image, cb, cb_data);
4711 if (!image || !ret_image)
4712 return InvalidParameter;
4714 if (!width) width = 120;
4715 if (!height) height = 120;
4717 GdipGetImageWidth(image, &srcwidth);
4718 GdipGetImageHeight(image, &srcheight);
4720 stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
4721 NULL, (GpBitmap**)ret_image);
4723 if (stat == Ok)
4725 stat = GdipGetImageGraphicsContext(*ret_image, &graphics);
4727 if (stat == Ok)
4729 stat = GdipDrawImageRectRectI(graphics, image,
4730 0, 0, width, height, 0, 0, srcwidth, srcheight, UnitPixel,
4731 NULL, NULL, NULL);
4733 GdipDeleteGraphics(graphics);
4736 if (stat != Ok)
4738 GdipDisposeImage(*ret_image);
4739 *ret_image = NULL;
4743 return stat;
4746 /*****************************************************************************
4747 * GdipImageRotateFlip [GDIPLUS.@]
4749 GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
4751 GpBitmap *new_bitmap;
4752 GpBitmap *bitmap;
4753 int bpp, bytesperpixel;
4754 BOOL rotate_90, flip_x, flip_y;
4755 int src_x_offset, src_y_offset;
4756 LPBYTE src_origin;
4757 UINT x, y, width, height;
4758 BitmapData src_lock, dst_lock;
4759 GpStatus stat;
4761 TRACE("(%p, %u)\n", image, type);
4763 if (!image)
4764 return InvalidParameter;
4766 rotate_90 = type&1;
4767 flip_x = (type&6) == 2 || (type&6) == 4;
4768 flip_y = (type&3) == 1 || (type&3) == 2;
4770 if (image->type != ImageTypeBitmap)
4772 FIXME("Not implemented for type %i\n", image->type);
4773 return NotImplemented;
4776 bitmap = (GpBitmap*)image;
4777 bpp = PIXELFORMATBPP(bitmap->format);
4779 if (bpp < 8)
4781 FIXME("Not implemented for %i bit images\n", bpp);
4782 return NotImplemented;
4785 if (rotate_90)
4787 width = bitmap->height;
4788 height = bitmap->width;
4790 else
4792 width = bitmap->width;
4793 height = bitmap->height;
4796 bytesperpixel = bpp/8;
4798 stat = GdipCreateBitmapFromScan0(width, height, 0, bitmap->format, NULL, &new_bitmap);
4800 if (stat != Ok)
4801 return stat;
4803 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format, &src_lock);
4805 if (stat == Ok)
4807 stat = GdipBitmapLockBits(new_bitmap, NULL, ImageLockModeWrite, bitmap->format, &dst_lock);
4809 if (stat == Ok)
4811 LPBYTE src_row, src_pixel;
4812 LPBYTE dst_row, dst_pixel;
4814 src_origin = src_lock.Scan0;
4815 if (flip_x) src_origin += bytesperpixel * (bitmap->width - 1);
4816 if (flip_y) src_origin += src_lock.Stride * (bitmap->height - 1);
4818 if (rotate_90)
4820 if (flip_y) src_x_offset = -src_lock.Stride;
4821 else src_x_offset = src_lock.Stride;
4822 if (flip_x) src_y_offset = -bytesperpixel;
4823 else src_y_offset = bytesperpixel;
4825 else
4827 if (flip_x) src_x_offset = -bytesperpixel;
4828 else src_x_offset = bytesperpixel;
4829 if (flip_y) src_y_offset = -src_lock.Stride;
4830 else src_y_offset = src_lock.Stride;
4833 src_row = src_origin;
4834 dst_row = dst_lock.Scan0;
4835 for (y=0; y<height; y++)
4837 src_pixel = src_row;
4838 dst_pixel = dst_row;
4839 for (x=0; x<width; x++)
4841 /* FIXME: This could probably be faster without memcpy. */
4842 memcpy(dst_pixel, src_pixel, bytesperpixel);
4843 dst_pixel += bytesperpixel;
4844 src_pixel += src_x_offset;
4846 src_row += src_y_offset;
4847 dst_row += dst_lock.Stride;
4850 GdipBitmapUnlockBits(new_bitmap, &dst_lock);
4853 GdipBitmapUnlockBits(bitmap, &src_lock);
4856 if (stat == Ok)
4857 move_bitmap(bitmap, new_bitmap, FALSE);
4858 else
4859 GdipDisposeImage((GpImage*)new_bitmap);
4861 return stat;