ReactOS  r76032
image.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  * Copyright (C) 2012,2016 Dmitry Timoshkov
4  *
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.
9  *
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.
14  *
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
18  */
19 
20 #include "gdiplus_private.h"
21 
22 #include <assert.h>
23 #include <ole2.h>
24 #include <olectl.h>
25 
27 
28 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
29 #define WMF_PLACEABLE_KEY 0x9ac6cdd7
30 
31 static const struct
32 {
35  /* predefined palette type to use for pixel format conversions */
37 } pixel_formats[] =
38 {
39  { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
40  { &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
41  { &GUID_WICPixelFormat4bppIndexed, PixelFormat4bppIndexed, WICBitmapPaletteTypeFixedHalftone8 },
42  { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 },
43  { &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedHalftone256 },
44  { &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555, WICBitmapPaletteTypeFixedHalftone256 },
45  { &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
46  { &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
47  { &GUID_WICPixelFormat48bppRGB, PixelFormat48bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
48  { &GUID_WICPixelFormat32bppBGRA, PixelFormat32bppARGB, WICBitmapPaletteTypeFixedHalftone256 },
49  { &GUID_WICPixelFormat32bppPBGRA, PixelFormat32bppPARGB, WICBitmapPaletteTypeFixedHalftone256 },
50  { &GUID_WICPixelFormat32bppCMYK, PixelFormat32bppCMYK, WICBitmapPaletteTypeFixedHalftone256 },
51  { &GUID_WICPixelFormat32bppGrayFloat, PixelFormat32bppARGB, WICBitmapPaletteTypeFixedGray256 },
52  { &GUID_WICPixelFormat64bppCMYK, PixelFormat48bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
53  { &GUID_WICPixelFormat64bppRGBA, PixelFormat48bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
54  { NULL }
55 };
56 
58 {
59  HRESULT hr;
61  IWICPalette *wic_palette;
63 
64  hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
65  if (hr != S_OK) return NULL;
66 
67  hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
68  if (hr == S_OK)
69  {
71  if (frame)
72  hr = IWICBitmapFrameDecode_CopyPalette(frame, wic_palette);
73  if (hr != S_OK)
74  {
75  TRACE("using predefined palette %#x\n", palette_type);
76  hr = IWICPalette_InitializePredefined(wic_palette, palette_type, FALSE);
77  }
78  if (hr == S_OK)
79  {
81  BOOL alpha;
82  UINT count;
83 
84  IWICPalette_GetColorCount(wic_palette, &count);
85  palette = heap_alloc(2 * sizeof(UINT) + count * sizeof(ARGB));
86  IWICPalette_GetColors(wic_palette, count, palette->Entries, &palette->Count);
87 
88  IWICPalette_GetType(wic_palette, &type);
89  switch(type) {
93  palette->Flags = PaletteFlagsGrayScale;
94  break;
102  palette->Flags = PaletteFlagsHalftone;
103  break;
104  default:
105  palette->Flags = 0;
106  }
107  IWICPalette_HasAlpha(wic_palette, &alpha);
108  if(alpha)
109  palette->Flags |= PaletteFlagsHasAlpha;
110  }
111  IWICPalette_Release(wic_palette);
112  }
113  IWICImagingFactory_Release(factory);
114  return palette;
115 }
116 
118  RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
119 {
120  FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
121  /*
122  * Note: According to Jose Roca's GDI+ docs, this function is not
123  * implemented in Windows's GDI+.
124  */
125  return NotImplemented;
126 }
127 
129  INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
130  GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
131 {
132  FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
133  /*
134  * Note: According to Jose Roca's GDI+ docs, this function is not
135  * implemented in Windows's GDI+.
136  */
137  return NotImplemented;
138 }
139 
140 static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
141 {
142  *index = (row[x/8]>>(7-x%8)) & 1;
143 }
144 
145 static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x)
146 {
147  if (x & 1)
148  *index = row[x/2]&0xf;
149  else
150  *index = row[x/2]>>4;
151 }
152 
153 static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
154 {
155  *index = row[x];
156 }
157 
158 static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
159  const BYTE *row, UINT x)
160 {
161  *r = *g = *b = row[x*2+1];
162  *a = 255;
163 }
164 
165 static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
166  const BYTE *row, UINT x)
167 {
168  WORD pixel = *((const WORD*)(row)+x);
169  *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
170  *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
171  *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
172  *a = 255;
173 }
174 
175 static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
176  const BYTE *row, UINT x)
177 {
178  WORD pixel = *((const WORD*)(row)+x);
179  *r = (pixel>>8&0xf8)|(pixel>>13&0x7);
180  *g = (pixel>>3&0xfc)|(pixel>>9&0x3);
181  *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
182  *a = 255;
183 }
184 
185 static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
186  const BYTE *row, UINT x)
187 {
188  WORD pixel = *((const WORD*)(row)+x);
189  *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
190  *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
191  *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
192  if ((pixel&0x8000) == 0x8000)
193  *a = 255;
194  else
195  *a = 0;
196 }
197 
198 static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
199  const BYTE *row, UINT x)
200 {
201  *r = row[x*3+2];
202  *g = row[x*3+1];
203  *b = row[x*3];
204  *a = 255;
205 }
206 
207 static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
208  const BYTE *row, UINT x)
209 {
210  *r = row[x*4+2];
211  *g = row[x*4+1];
212  *b = row[x*4];
213  *a = 255;
214 }
215 
216 static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
217  const BYTE *row, UINT x)
218 {
219  *r = row[x*4+2];
220  *g = row[x*4+1];
221  *b = row[x*4];
222  *a = row[x*4+3];
223 }
224 
225 static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
226  const BYTE *row, UINT x)
227 {
228  *a = row[x*4+3];
229  if (*a == 0)
230  *r = *g = *b = 0;
231  else
232  {
233  *r = row[x*4+2] * 255 / *a;
234  *g = row[x*4+1] * 255 / *a;
235  *b = row[x*4] * 255 / *a;
236  }
237 }
238 
239 static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
240  const BYTE *row, UINT x)
241 {
242  *r = row[x*6+5];
243  *g = row[x*6+3];
244  *b = row[x*6+1];
245  *a = 255;
246 }
247 
248 static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
249  const BYTE *row, UINT x)
250 {
251  *r = row[x*8+5];
252  *g = row[x*8+3];
253  *b = row[x*8+1];
254  *a = row[x*8+7];
255 }
256 
257 static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
258  const BYTE *row, UINT x)
259 {
260  *a = row[x*8+7];
261  if (*a == 0)
262  *r = *g = *b = 0;
263  else
264  {
265  *r = row[x*8+5] * 255 / *a;
266  *g = row[x*8+3] * 255 / *a;
267  *b = row[x*8+1] * 255 / *a;
268  }
269 }
270 
272  ARGB *color)
273 {
274  BYTE r, g, b, a;
275  BYTE index;
276  BYTE *row;
277 
278  if(!bitmap || !color ||
279  x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
280  return InvalidParameter;
281 
282  row = bitmap->bits+bitmap->stride*y;
283 
284  switch (bitmap->format)
285  {
287  getpixel_1bppIndexed(&index,row,x);
288  break;
290  getpixel_4bppIndexed(&index,row,x);
291  break;
293  getpixel_8bppIndexed(&index,row,x);
294  break;
296  getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
297  break;
299  getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
300  break;
302  getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
303  break;
305  getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
306  break;
307  case PixelFormat24bppRGB:
308  getpixel_24bppRGB(&r,&g,&b,&a,row,x);
309  break;
310  case PixelFormat32bppRGB:
311  getpixel_32bppRGB(&r,&g,&b,&a,row,x);
312  break;
314  getpixel_32bppARGB(&r,&g,&b,&a,row,x);
315  break;
317  getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
318  break;
319  case PixelFormat48bppRGB:
320  getpixel_48bppRGB(&r,&g,&b,&a,row,x);
321  break;
323  getpixel_64bppARGB(&r,&g,&b,&a,row,x);
324  break;
326  getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
327  break;
328  default:
329  FIXME("not implemented for format 0x%x\n", bitmap->format);
330  return NotImplemented;
331  }
332 
333  if (bitmap->format & PixelFormatIndexed)
334  *color = bitmap->image.palette->Entries[index];
335  else
336  *color = a<<24|r<<16|g<<8|b;
337 
338  return Ok;
339 }
340 
342 {
343  BYTE index = 0;
344  int best_distance = 0x7fff;
345  int distance;
346  UINT i;
347 
348  if (!palette) return 0;
349  /* This algorithm scans entire palette,
350  computes difference from desired color (all color components have equal weight)
351  and returns the index of color with least difference.
352 
353  Note: Maybe it could be replaced with a better algorithm for better image quality
354  and performance, though better algorithm would probably need some pre-built lookup
355  tables and thus may actually be slower if this method is called only few times per
356  every image.
357  */
358  for(i=0;i<palette->Count;i++) {
359  ARGB color=palette->Entries[i];
360  distance=abs(b-(color & 0xff)) + abs(g-(color>>8 & 0xff)) + abs(r-(color>>16 & 0xff)) + abs(a-(color>>24 & 0xff));
361  if (distance<best_distance) {
362  best_distance=distance;
363  index=i;
364  }
365  }
366  return index;
367 }
368 
369 static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
371 {
372  BYTE index = get_palette_index(r,g,b,a,palette);
373  row[x]=index;
374 }
375 
376 static inline void setpixel_1bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
378 {
379  row[x/8] = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,palette)<<(7-x%8));
380 }
381 
382 static inline void setpixel_4bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
384 {
385  if (x & 1)
386  row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,palette);
387  else
388  row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,palette)<<4;
389 }
390 
391 static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
392  BYTE *row, UINT x)
393 {
394  *((WORD*)(row)+x) = (r+g+b)*85;
395 }
396 
397 static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
398  BYTE *row, UINT x)
399 {
400  *((WORD*)(row)+x) = (r<<7&0x7c00)|
401  (g<<2&0x03e0)|
402  (b>>3&0x001f);
403 }
404 
405 static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
406  BYTE *row, UINT x)
407 {
408  *((WORD*)(row)+x) = (r<<8&0xf800)|
409  (g<<3&0x07e0)|
410  (b>>3&0x001f);
411 }
412 
413 static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
414  BYTE *row, UINT x)
415 {
416  *((WORD*)(row)+x) = (a<<8&0x8000)|
417  (r<<7&0x7c00)|
418  (g<<2&0x03e0)|
419  (b>>3&0x001f);
420 }
421 
422 static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
423  BYTE *row, UINT x)
424 {
425  row[x*3+2] = r;
426  row[x*3+1] = g;
427  row[x*3] = b;
428 }
429 
430 static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
431  BYTE *row, UINT x)
432 {
433  *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
434 }
435 
436 static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
437  BYTE *row, UINT x)
438 {
439  *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
440 }
441 
442 static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
443  BYTE *row, UINT x)
444 {
445  r = r * a / 255;
446  g = g * a / 255;
447  b = b * a / 255;
448  *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
449 }
450 
451 static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
452  BYTE *row, UINT x)
453 {
454  row[x*6+5] = row[x*6+4] = r;
455  row[x*6+3] = row[x*6+2] = g;
456  row[x*6+1] = row[x*6] = b;
457 }
458 
459 static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
460  BYTE *row, UINT x)
461 {
462  UINT64 a64=a, r64=r, g64=g, b64=b;
463  *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
464 }
465 
466 static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
467  BYTE *row, UINT x)
468 {
469  UINT64 a64, r64, g64, b64;
470  a64 = a * 257;
471  r64 = r * a / 255;
472  g64 = g * a / 255;
473  b64 = b * a / 255;
474  *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
475 }
476 
478  ARGB color)
479 {
480  BYTE a, r, g, b;
481  BYTE *row;
482 
483  if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
484  return InvalidParameter;
485 
486  a = color>>24;
487  r = color>>16;
488  g = color>>8;
489  b = color;
490 
491  row = bitmap->bits + bitmap->stride * y;
492 
493  switch (bitmap->format)
494  {
496  setpixel_16bppGrayScale(r,g,b,a,row,x);
497  break;
499  setpixel_16bppRGB555(r,g,b,a,row,x);
500  break;
502  setpixel_16bppRGB565(r,g,b,a,row,x);
503  break;
505  setpixel_16bppARGB1555(r,g,b,a,row,x);
506  break;
507  case PixelFormat24bppRGB:
508  setpixel_24bppRGB(r,g,b,a,row,x);
509  break;
510  case PixelFormat32bppRGB:
511  setpixel_32bppRGB(r,g,b,a,row,x);
512  break;
514  setpixel_32bppARGB(r,g,b,a,row,x);
515  break;
517  setpixel_32bppPARGB(r,g,b,a,row,x);
518  break;
519  case PixelFormat48bppRGB:
520  setpixel_48bppRGB(r,g,b,a,row,x);
521  break;
523  setpixel_64bppARGB(r,g,b,a,row,x);
524  break;
526  setpixel_64bppPARGB(r,g,b,a,row,x);
527  break;
529  setpixel_8bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
530  break;
532  setpixel_4bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
533  break;
535  setpixel_1bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
536  break;
537  default:
538  FIXME("not implemented for format 0x%x\n", bitmap->format);
539  return NotImplemented;
540  }
541 
542  return Ok;
543 }
544 
546  INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
547  INT src_stride, const BYTE *src_bits, PixelFormat src_format,
549 {
550  INT x, y;
551 
552  if (src_format == dst_format ||
553  (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32))
554  {
555  UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8;
556  for (y=0; y<height; y++)
557  memcpy(dst_bits+dst_stride*y, src_bits+src_stride*y, widthbytes);
558  return Ok;
559  }
560 
561 #define convert_indexed_to_rgb(getpixel_function, setpixel_function) do { \
562  for (y=0; y<height; y++) \
563  for (x=0; x<width; x++) { \
564  BYTE index; \
565  ARGB argb; \
566  BYTE *color = (BYTE *)&argb; \
567  getpixel_function(&index, src_bits+src_stride*y, x); \
568  argb = (palette && index < palette->Count) ? palette->Entries[index] : 0; \
569  setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
570  } \
571  return Ok; \
572 } while (0);
573 
574 #define convert_rgb_to_rgb(getpixel_function, setpixel_function) do { \
575  for (y=0; y<height; y++) \
576  for (x=0; x<width; x++) { \
577  BYTE r, g, b, a; \
578  getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
579  setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x); \
580  } \
581  return Ok; \
582 } while (0);
583 
584 #define convert_rgb_to_indexed(getpixel_function, setpixel_function) do { \
585  for (y=0; y<height; y++) \
586  for (x=0; x<width; x++) { \
587  BYTE r, g, b, a; \
588  getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
589  setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x, palette); \
590  } \
591  return Ok; \
592 } while (0);
593 
594  switch (src_format)
595  {
597  switch (dst_format)
598  {
607  case PixelFormat24bppRGB:
609  case PixelFormat32bppRGB:
615  case PixelFormat48bppRGB:
619  default:
620  break;
621  }
622  break;
624  switch (dst_format)
625  {
634  case PixelFormat24bppRGB:
636  case PixelFormat32bppRGB:
642  case PixelFormat48bppRGB:
646  default:
647  break;
648  }
649  break;
651  switch (dst_format)
652  {
661  case PixelFormat24bppRGB:
663  case PixelFormat32bppRGB:
669  case PixelFormat48bppRGB:
673  default:
674  break;
675  }
676  break;
678  switch (dst_format)
679  {
690  case PixelFormat24bppRGB:
692  case PixelFormat32bppRGB:
698  case PixelFormat48bppRGB:
702  default:
703  break;
704  }
705  break;
707  switch (dst_format)
708  {
719  case PixelFormat24bppRGB:
721  case PixelFormat32bppRGB:
727  case PixelFormat48bppRGB:
731  default:
732  break;
733  }
734  break;
736  switch (dst_format)
737  {
748  case PixelFormat24bppRGB:
750  case PixelFormat32bppRGB:
756  case PixelFormat48bppRGB:
760  default:
761  break;
762  }
763  break;
765  switch (dst_format)
766  {
777  case PixelFormat24bppRGB:
779  case PixelFormat32bppRGB:
785  case PixelFormat48bppRGB:
789  default:
790  break;
791  }
792  break;
793  case PixelFormat24bppRGB:
794  switch (dst_format)
795  {
808  case PixelFormat32bppRGB:
814  case PixelFormat48bppRGB:
818  default:
819  break;
820  }
821  break;
822  case PixelFormat32bppRGB:
823  switch (dst_format)
824  {
837  case PixelFormat24bppRGB:
843  case PixelFormat48bppRGB:
847  default:
848  break;
849  }
850  break;
852  switch (dst_format)
853  {
866  case PixelFormat24bppRGB:
869  convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
870  return Ok;
871  case PixelFormat48bppRGB:
875  default:
876  break;
877  }
878  break;
880  switch (dst_format)
881  {
894  case PixelFormat24bppRGB:
896  case PixelFormat32bppRGB:
900  case PixelFormat48bppRGB:
904  default:
905  break;
906  }
907  break;
908  case PixelFormat48bppRGB:
909  switch (dst_format)
910  {
923  case PixelFormat24bppRGB:
925  case PixelFormat32bppRGB:
933  default:
934  break;
935  }
936  break;
938  switch (dst_format)
939  {
952  case PixelFormat24bppRGB:
954  case PixelFormat32bppRGB:
960  case PixelFormat48bppRGB:
962  default:
963  break;
964  }
965  break;
967  switch (dst_format)
968  {
981  case PixelFormat24bppRGB:
983  case PixelFormat32bppRGB:
989  case PixelFormat48bppRGB:
993  default:
994  break;
995  }
996  break;
997  default:
998  break;
999  }
1000 
1001 #undef convert_indexed_to_rgb
1002 #undef convert_rgb_to_rgb
1003 
1004  return NotImplemented;
1005 }
1006 
1007 /* This function returns a pointer to an array of pixels that represents the
1008  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
1009  * flags. It is correct behavior that a user who calls this function with write
1010  * privileges can write to the whole bitmap (not just the area in rect).
1011  *
1012  * FIXME: only used portion of format is bits per pixel. */
1014  UINT flags, PixelFormat format, BitmapData* lockeddata)
1015 {
1016  INT bitspp = PIXELFORMATBPP(format);
1017  GpRect act_rect; /* actual rect to be used */
1018  GpStatus stat;
1019  BOOL unlock;
1020 
1021  TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
1022 
1023  if(!lockeddata || !bitmap)
1024  return InvalidParameter;
1025  if(!image_lock(&bitmap->image, &unlock))
1026  return ObjectBusy;
1027 
1028  if(rect){
1029  if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
1030  (rect->Y + rect->Height > bitmap->height) || !flags)
1031  {
1032  image_unlock(&bitmap->image, unlock);
1033  return InvalidParameter;
1034  }
1035 
1036  act_rect = *rect;
1037  }
1038  else{
1039  act_rect.X = act_rect.Y = 0;
1040  act_rect.Width = bitmap->width;
1041  act_rect.Height = bitmap->height;
1042  }
1043 
1044  if(bitmap->lockmode)
1045  {
1046  WARN("bitmap is already locked and cannot be locked again\n");
1047  image_unlock(&bitmap->image, unlock);
1048  return WrongState;
1049  }
1050 
1051  if (bitmap->bits && bitmap->format == format && !(flags & ImageLockModeUserInputBuf))
1052  {
1053  /* no conversion is necessary; just use the bits directly */
1054  lockeddata->Width = act_rect.Width;
1055  lockeddata->Height = act_rect.Height;
1056  lockeddata->PixelFormat = format;
1057  lockeddata->Reserved = flags;
1058  lockeddata->Stride = bitmap->stride;
1059  lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
1060  bitmap->stride * act_rect.Y;
1061 
1062  bitmap->lockmode = flags | ImageLockModeRead;
1063 
1064  image_unlock(&bitmap->image, unlock);
1065  return Ok;
1066  }
1067 
1068  /* Make sure we can convert to the requested format. */
1069  if (flags & ImageLockModeRead)
1070  {
1071  stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL);
1072  if (stat == NotImplemented)
1073  {
1074  FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
1075  image_unlock(&bitmap->image, unlock);
1076  return NotImplemented;
1077  }
1078  }
1079 
1080  /* If we're opening for writing, make sure we'll be able to write back in
1081  * the original format. */
1082  if (flags & ImageLockModeWrite)
1083  {
1084  stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL);
1085  if (stat == NotImplemented)
1086  {
1087  FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
1088  image_unlock(&bitmap->image, unlock);
1089  return NotImplemented;
1090  }
1091  }
1092 
1093  lockeddata->Width = act_rect.Width;
1094  lockeddata->Height = act_rect.Height;
1095  lockeddata->PixelFormat = format;
1096  lockeddata->Reserved = flags;
1097 
1098  if(!(flags & ImageLockModeUserInputBuf))
1099  {
1100  lockeddata->Stride = (((act_rect.Width * bitspp + 7) / 8) + 3) & ~3;
1101 
1102  bitmap->bitmapbits = heap_alloc_zero(lockeddata->Stride * act_rect.Height);
1103 
1104  if (!bitmap->bitmapbits)
1105  {
1106  image_unlock(&bitmap->image, unlock);
1107  return OutOfMemory;
1108  }
1109 
1110  lockeddata->Scan0 = bitmap->bitmapbits;
1111  }
1112 
1113  if (flags & ImageLockModeRead)
1114  {
1115  static BOOL fixme = FALSE;
1116 
1117  if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
1118  {
1119  FIXME("Cannot copy rows that don't start at a whole byte.\n");
1120  fixme = TRUE;
1121  }
1122 
1123  stat = convert_pixels(act_rect.Width, act_rect.Height,
1124  lockeddata->Stride, lockeddata->Scan0, format,
1125  bitmap->stride,
1126  bitmap->bits + bitmap->stride * act_rect.Y + PIXELFORMATBPP(bitmap->format) * act_rect.X / 8,
1127  bitmap->format, bitmap->image.palette);
1128 
1129  if (stat != Ok)
1130  {
1131  heap_free(bitmap->bitmapbits);
1132  bitmap->bitmapbits = NULL;
1133  image_unlock(&bitmap->image, unlock);
1134  return stat;
1135  }
1136  }
1137 
1138  bitmap->lockmode = flags | ImageLockModeRead;
1139  bitmap->lockx = act_rect.X;
1140  bitmap->locky = act_rect.Y;
1141 
1142  image_unlock(&bitmap->image, unlock);
1143  return Ok;
1144 }
1145 
1147 {
1148  TRACE("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
1149 
1150  if (!bitmap || xdpi == 0.0 || ydpi == 0.0)
1151  return InvalidParameter;
1152 
1153  bitmap->image.xres = xdpi;
1154  bitmap->image.yres = ydpi;
1155 
1156  return Ok;
1157 }
1158 
1160  BitmapData* lockeddata)
1161 {
1162  GpStatus stat;
1163  static BOOL fixme = FALSE;
1164  BOOL unlock;
1165 
1166  TRACE("(%p,%p)\n", bitmap, lockeddata);
1167 
1168  if(!bitmap || !lockeddata)
1169  return InvalidParameter;
1170  if(!image_lock(&bitmap->image, &unlock))
1171  return ObjectBusy;
1172 
1173  if(!bitmap->lockmode)
1174  {
1175  image_unlock(&bitmap->image, unlock);
1176  return WrongState;
1177  }
1178 
1179  if(!(lockeddata->Reserved & ImageLockModeWrite)){
1180  bitmap->lockmode = 0;
1181  heap_free(bitmap->bitmapbits);
1182  bitmap->bitmapbits = NULL;
1183  image_unlock(&bitmap->image, unlock);
1184  return Ok;
1185  }
1186 
1187  if (!bitmap->bitmapbits && !(lockeddata->Reserved & ImageLockModeUserInputBuf))
1188  {
1189  /* we passed a direct reference; no need to do anything */
1190  bitmap->lockmode = 0;
1191  image_unlock(&bitmap->image, unlock);
1192  return Ok;
1193  }
1194 
1195  if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
1196  {
1197  FIXME("Cannot copy rows that don't start at a whole byte.\n");
1198  fixme = TRUE;
1199  }
1200 
1201  stat = convert_pixels(lockeddata->Width, lockeddata->Height,
1202  bitmap->stride,
1203  bitmap->bits + bitmap->stride * bitmap->locky + PIXELFORMATBPP(bitmap->format) * bitmap->lockx / 8,
1204  bitmap->format,
1205  lockeddata->Stride, lockeddata->Scan0, lockeddata->PixelFormat, NULL);
1206 
1207  if (stat != Ok)
1208  {
1209  ERR("failed to convert pixels; this should never happen\n");
1210  }
1211 
1212  heap_free(bitmap->bitmapbits);
1213  bitmap->bitmapbits = NULL;
1214  bitmap->lockmode = 0;
1215 
1216  image_unlock(&bitmap->image, unlock);
1217  return stat;
1218 }
1219 
1221  PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1222 {
1223  Rect area;
1224  GpStatus stat;
1225 
1226  TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1227 
1228  if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap ||
1229  x < 0 || y < 0 ||
1230  x + width > srcBitmap->width || y + height > srcBitmap->height)
1231  {
1232  TRACE("<-- InvalidParameter\n");
1233  return InvalidParameter;
1234  }
1235 
1236  if (format == PixelFormatDontCare)
1237  format = srcBitmap->format;
1238 
1239  area.X = gdip_round(x);
1240  area.Y = gdip_round(y);
1241  area.Width = gdip_round(width);
1242  area.Height = gdip_round(height);
1243 
1244  stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap);
1245  if (stat == Ok)
1246  {
1247  stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format,
1248  srcBitmap->stride,
1249  srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8,
1250  srcBitmap->format, srcBitmap->image.palette);
1251 
1252  if (stat == Ok && srcBitmap->image.palette)
1253  {
1254  ColorPalette *src_palette, *dst_palette;
1255 
1256  src_palette = srcBitmap->image.palette;
1257 
1258  dst_palette = heap_alloc_zero(sizeof(UINT) * 2 + sizeof(ARGB) * src_palette->Count);
1259 
1260  if (dst_palette)
1261  {
1262  dst_palette->Flags = src_palette->Flags;
1263  dst_palette->Count = src_palette->Count;
1264  memcpy(dst_palette->Entries, src_palette->Entries, sizeof(ARGB) * src_palette->Count);
1265 
1266  heap_free((*dstBitmap)->image.palette);
1267  (*dstBitmap)->image.palette = dst_palette;
1268  }
1269  else
1270  stat = OutOfMemory;
1271  }
1272 
1273  if (stat != Ok)
1274  GdipDisposeImage(&(*dstBitmap)->image);
1275  }
1276 
1277  if (stat != Ok)
1278  *dstBitmap = NULL;
1279 
1280  return stat;
1281 }
1282 
1284  PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1285 {
1286  TRACE("(%i,%i,%i,%i,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1287 
1288  return GdipCloneBitmapArea(x, y, width, height, format, srcBitmap, dstBitmap);
1289 }
1290 
1292 {
1293  TRACE("%p, %p\n", image, cloneImage);
1294 
1295  if (!image || !cloneImage)
1296  return InvalidParameter;
1297 
1298  if (image->type == ImageTypeBitmap)
1299  {
1300  GpBitmap *bitmap = (GpBitmap *)image;
1301 
1302  return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height,
1303  bitmap->format, bitmap, (GpBitmap **)cloneImage);
1304  }
1305  else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
1306  {
1308 
1309  metafile = (GpMetafile*)image;
1310 
1311  result = heap_alloc_zero(sizeof(*result));
1312  if (!result)
1313  return OutOfMemory;
1314 
1315  result->image.type = ImageTypeMetafile;
1316  result->image.format = image->format;
1317  result->image.flags = image->flags;
1318  result->image.frame_count = 1;
1319  result->image.xres = image->xres;
1320  result->image.yres = image->yres;
1321  result->bounds = metafile->bounds;
1322  result->unit = metafile->unit;
1323  result->metafile_type = metafile->metafile_type;
1324  result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
1325  list_init(&result->containers);
1326 
1327  if (!result->hemf)
1328  {
1329  heap_free(result);
1330  return OutOfMemory;
1331  }
1332 
1333  *cloneImage = &result->image;
1334  return Ok;
1335  }
1336  else
1337  {
1338  WARN("GpImage with no image data (metafile in wrong state?)\n");
1339  return InvalidParameter;
1340  }
1341 }
1342 
1344  GpBitmap **bitmap)
1345 {
1346  GpStatus stat;
1347  IStream *stream;
1348 
1349  TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1350 
1351  if(!filename || !bitmap)
1352  return InvalidParameter;
1353 
1354  *bitmap = NULL;
1355 
1356  stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
1357 
1358  if(stat != Ok)
1359  return stat;
1360 
1361  stat = GdipCreateBitmapFromStream(stream, bitmap);
1362 
1363  IStream_Release(stream);
1364 
1365  return stat;
1366 }
1367 
1369  VOID *bits, GpBitmap **bitmap)
1370 {
1371  DWORD height, stride;
1373 
1374  FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
1375 
1376  if (!info || !bits || !bitmap)
1377  return InvalidParameter;
1378 
1379  height = abs(info->bmiHeader.biHeight);
1380  stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
1381 
1382  if(info->bmiHeader.biHeight > 0) /* bottom-up */
1383  {
1384  bits = (BYTE*)bits + (height - 1) * stride;
1385  stride = -stride;
1386  }
1387 
1388  switch(info->bmiHeader.biBitCount) {
1389  case 1:
1390  format = PixelFormat1bppIndexed;
1391  break;
1392  case 4:
1393  format = PixelFormat4bppIndexed;
1394  break;
1395  case 8:
1396  format = PixelFormat8bppIndexed;
1397  break;
1398  case 16:
1399  format = PixelFormat16bppRGB555;
1400  break;
1401  case 24:
1402  format = PixelFormat24bppRGB;
1403  break;
1404  case 32:
1405  format = PixelFormat32bppRGB;
1406  break;
1407  default:
1408  FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
1409  *bitmap = NULL;
1410  return InvalidParameter;
1411  }
1412 
1413  return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
1414  bits, bitmap);
1415 
1416 }
1417 
1418 /* FIXME: no icm */
1420  GpBitmap **bitmap)
1421 {
1422  TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1423 
1424  return GdipCreateBitmapFromFile(filename, bitmap);
1425 }
1426 
1428  GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
1429 {
1430  HBITMAP hbm;
1432 
1433  TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
1434 
1435  if(!lpBitmapName || !bitmap)
1436  return InvalidParameter;
1437 
1438  /* load DIB */
1439  hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
1441 
1442  if(hbm){
1443  stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
1444  DeleteObject(hbm);
1445  }
1446 
1447  return stat;
1448 }
1449 
1451 {
1452  BYTE b = (BYTE)src;
1453  BYTE g = (BYTE)(src >> 8);
1454  BYTE r = (BYTE)(src >> 16);
1455  DWORD alpha = (BYTE)(src >> 24);
1456  return ((b + ((BYTE)bkgnd * (255 - alpha) + 127) / 255) |
1457  (g + ((BYTE)(bkgnd >> 8) * (255 - alpha) + 127) / 255) << 8 |
1458  (r + ((BYTE)(bkgnd >> 16) * (255 - alpha) + 127) / 255) << 16 |
1459  (alpha << 24));
1460 }
1461 
1463  HBITMAP* hbmReturn, ARGB background)
1464 {
1465  GpStatus stat;
1466  HBITMAP result;
1467  UINT width, height;
1468  BITMAPINFOHEADER bih;
1469  LPBYTE bits;
1470  BOOL unlock;
1471 
1472  TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
1473 
1474  if (!bitmap || !hbmReturn) return InvalidParameter;
1475  if (!image_lock(&bitmap->image, &unlock)) return ObjectBusy;
1476 
1477  GdipGetImageWidth(&bitmap->image, &width);
1478  GdipGetImageHeight(&bitmap->image, &height);
1479 
1480  bih.biSize = sizeof(bih);
1481  bih.biWidth = width;
1482  bih.biHeight = height;
1483  bih.biPlanes = 1;
1484  bih.biBitCount = 32;
1485  bih.biCompression = BI_RGB;
1486  bih.biSizeImage = 0;
1487  bih.biXPelsPerMeter = 0;
1488  bih.biYPelsPerMeter = 0;
1489  bih.biClrUsed = 0;
1490  bih.biClrImportant = 0;
1491 
1492  result = CreateDIBSection(0, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1493  if (!result)
1494  {
1495  image_unlock(&bitmap->image, unlock);
1496  return GenericError;
1497  }
1498 
1499  stat = convert_pixels(width, height, -width*4,
1500  bits + (width * 4 * (height - 1)), PixelFormat32bppPARGB,
1501  bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette);
1502  if (stat != Ok)
1503  {
1504  DeleteObject(result);
1505  image_unlock(&bitmap->image, unlock);
1506  return stat;
1507  }
1508 
1509  if (background & 0xffffff)
1510  {
1511  DWORD *ptr;
1512  UINT i;
1513  for (ptr = (DWORD*)bits, i = 0; i < width * height; ptr++, i++)
1514  {
1515  if ((*ptr & 0xff000000) == 0xff000000) continue;
1516  *ptr = blend_argb_no_bkgnd_alpha(*ptr, background);
1517  }
1518  }
1519 
1520  *hbmReturn = result;
1521  image_unlock(&bitmap->image, unlock);
1522  return Ok;
1523 }
1524 
1527 {
1528  GpStatus ret;
1529 
1530  TRACE("(%d, %d, %p, %p)\n", width, height, target, bitmap);
1531 
1532  if(!target || !bitmap)
1533  return InvalidParameter;
1534 
1535  ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
1536  NULL, bitmap);
1537 
1538  if (ret == Ok)
1539  {
1540  GdipGetDpiX(target, &(*bitmap)->image.xres);
1541  GdipGetDpiY(target, &(*bitmap)->image.yres);
1542  }
1543 
1544  return ret;
1545 }
1546 
1548 {
1549  GpStatus stat;
1550  ICONINFO iinfo;
1551  BITMAP bm;
1552  int ret;
1553  UINT width, height, stride;
1554  GpRect rect;
1555  BitmapData lockeddata;
1556  HDC screendc;
1557  BOOL has_alpha;
1558  int x, y;
1559  BITMAPINFOHEADER bih;
1560  DWORD *src;
1561  BYTE *dst_row;
1562  DWORD *dst;
1563 
1564  TRACE("%p, %p\n", hicon, bitmap);
1565 
1566  if(!bitmap || !GetIconInfo(hicon, &iinfo))
1567  return InvalidParameter;
1568 
1569  /* get the size of the icon */
1570  ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
1571  if (ret == 0) {
1572  DeleteObject(iinfo.hbmColor);
1573  DeleteObject(iinfo.hbmMask);
1574  return GenericError;
1575  }
1576 
1577  width = bm.bmWidth;
1578  height = iinfo.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2;
1579  stride = width * 4;
1580 
1581  stat = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat32bppARGB, NULL, bitmap);
1582  if (stat != Ok) {
1583  DeleteObject(iinfo.hbmColor);
1584  DeleteObject(iinfo.hbmMask);
1585  return stat;
1586  }
1587 
1588  rect.X = 0;
1589  rect.Y = 0;
1590  rect.Width = width;
1591  rect.Height = height;
1592 
1593  stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
1594  if (stat != Ok) {
1595  DeleteObject(iinfo.hbmColor);
1596  DeleteObject(iinfo.hbmMask);
1597  GdipDisposeImage(&(*bitmap)->image);
1598  return stat;
1599  }
1600 
1601  bih.biSize = sizeof(bih);
1602  bih.biWidth = width;
1603  bih.biHeight = iinfo.hbmColor ? -height: -height * 2;
1604  bih.biPlanes = 1;
1605  bih.biBitCount = 32;
1606  bih.biCompression = BI_RGB;
1607  bih.biSizeImage = 0;
1608  bih.biXPelsPerMeter = 0;
1609  bih.biYPelsPerMeter = 0;
1610  bih.biClrUsed = 0;
1611  bih.biClrImportant = 0;
1612 
1613  screendc = CreateCompatibleDC(0);
1614  if (iinfo.hbmColor)
1615  {
1616  GetDIBits(screendc, iinfo.hbmColor, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1617 
1618  if (bm.bmBitsPixel == 32)
1619  {
1620  has_alpha = FALSE;
1621 
1622  /* If any pixel has a non-zero alpha, ignore hbmMask */
1623  src = (DWORD*)lockeddata.Scan0;
1624  for (x=0; x<width && !has_alpha; x++)
1625  for (y=0; y<height && !has_alpha; y++)
1626  if ((*src++ & 0xff000000) != 0)
1627  has_alpha = TRUE;
1628  }
1629  else has_alpha = FALSE;
1630  }
1631  else
1632  {
1633  GetDIBits(screendc, iinfo.hbmMask, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1634  has_alpha = FALSE;
1635  }
1636 
1637  if (!has_alpha)
1638  {
1639  if (iinfo.hbmMask)
1640  {
1641  BYTE *bits = heap_alloc(height * stride);
1642 
1643  /* read alpha data from the mask */
1644  if (iinfo.hbmColor)
1645  GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1646  else
1647  GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1648 
1649  src = (DWORD*)bits;
1650  dst_row = lockeddata.Scan0;
1651  for (y=0; y<height; y++)
1652  {
1653  dst = (DWORD*)dst_row;
1654  for (x=0; x<height; x++)
1655  {
1656  DWORD src_value = *src++;
1657  if (src_value)
1658  *dst++ = 0;
1659  else
1660  *dst++ |= 0xff000000;
1661  }
1662  dst_row += lockeddata.Stride;
1663  }
1664 
1665  heap_free(bits);
1666  }
1667  else
1668  {
1669  /* set constant alpha of 255 */
1670  dst_row = lockeddata.Scan0;
1671  for (y=0; y<height; y++)
1672  {
1673  dst = (DWORD*)dst_row;
1674  for (x=0; x<height; x++)
1675  *dst++ |= 0xff000000;
1676  dst_row += lockeddata.Stride;
1677  }
1678  }
1679  }
1680 
1681  DeleteDC(screendc);
1682 
1683  DeleteObject(iinfo.hbmColor);
1684  DeleteObject(iinfo.hbmMask);
1685 
1686  GdipBitmapUnlockBits(*bitmap, &lockeddata);
1687 
1688  return Ok;
1689 }
1690 
1692 {
1693  static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
1694  UINT i;
1695 
1696  for (i=0; i<8 && i<count; i++)
1697  {
1698  entries[i] = 0xff000000;
1699  if (i&1) entries[i] |= 0x800000;
1700  if (i&2) entries[i] |= 0x8000;
1701  if (i&4) entries[i] |= 0x80;
1702  }
1703 
1704  if (8 < count)
1705  entries[i] = 0xffc0c0c0;
1706 
1707  for (i=9; i<16 && i<count; i++)
1708  {
1709  entries[i] = 0xff000000;
1710  if (i&1) entries[i] |= 0xff0000;
1711  if (i&2) entries[i] |= 0xff00;
1712  if (i&4) entries[i] |= 0xff;
1713  }
1714 
1715  for (i=16; i<40 && i<count; i++)
1716  {
1717  entries[i] = 0;
1718  }
1719 
1720  for (i=40; i<256 && i<count; i++)
1721  {
1722  entries[i] = 0xff000000;
1723  entries[i] |= halftone_values[(i-40)%6];
1724  entries[i] |= halftone_values[((i-40)/6)%6] << 8;
1725  entries[i] |= halftone_values[((i-40)/36)%6] << 16;
1726  }
1727 }
1728 
1730 {
1731  HDC screendc = CreateCompatibleDC(0);
1732 
1733  if (!screendc) return GenericError;
1734 
1735  *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
1736  *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
1737 
1738  DeleteDC(screendc);
1739 
1740  return Ok;
1741 }
1742 
1744  PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
1745 {
1747  INT row_size, dib_stride;
1748  BYTE *bits=NULL, *own_bits=NULL;
1749  REAL xres, yres;
1750  GpStatus stat;
1751 
1752  TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
1753 
1754  if (!bitmap) return InvalidParameter;
1755 
1756  if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
1757  *bitmap = NULL;
1758  return InvalidParameter;
1759  }
1760 
1761  if(scan0 && !stride)
1762  return InvalidParameter;
1763 
1764  stat = get_screen_resolution(&xres, &yres);
1765  if (stat != Ok) return stat;
1766 
1767  row_size = (width * PIXELFORMATBPP(format)+7) / 8;
1768  dib_stride = (row_size + 3) & ~3;
1769 
1770  if(stride == 0)
1771  stride = dib_stride;
1772 
1773  if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
1774  {
1775  char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
1776  BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
1777 
1778  pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1779  pbmi->bmiHeader.biWidth = width;
1780  pbmi->bmiHeader.biHeight = -height;
1781  pbmi->bmiHeader.biPlanes = 1;
1782  /* FIXME: use the rest of the data from format */
1783  pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
1784  pbmi->bmiHeader.biCompression = BI_RGB;
1785  pbmi->bmiHeader.biSizeImage = 0;
1786  pbmi->bmiHeader.biXPelsPerMeter = 0;
1787  pbmi->bmiHeader.biYPelsPerMeter = 0;
1788  pbmi->bmiHeader.biClrUsed = 0;
1789  pbmi->bmiHeader.biClrImportant = 0;
1790 
1791  hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1792 
1793  if (!hbitmap) return GenericError;
1794 
1795  stride = dib_stride;
1796  }
1797  else
1798  {
1799  /* Not a GDI format; don't try to make an HBITMAP. */
1800  if (scan0)
1801  bits = scan0;
1802  else
1803  {
1804  INT size = abs(stride) * height;
1805 
1806  own_bits = bits = heap_alloc_zero(size);
1807  if (!own_bits) return OutOfMemory;
1808 
1809  if (stride < 0)
1810  bits += stride * (1 - height);
1811  }
1812  }
1813 
1814  *bitmap = heap_alloc_zero(sizeof(GpBitmap));
1815  if(!*bitmap)
1816  {
1817  DeleteObject(hbitmap);
1818  heap_free(own_bits);
1819  return OutOfMemory;
1820  }
1821 
1822  (*bitmap)->image.type = ImageTypeBitmap;
1823  memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
1824  (*bitmap)->image.flags = ImageFlagsNone;
1825  (*bitmap)->image.frame_count = 1;
1826  (*bitmap)->image.current_frame = 0;
1827  (*bitmap)->image.palette = NULL;
1828  (*bitmap)->image.xres = xres;
1829  (*bitmap)->image.yres = yres;
1830  (*bitmap)->width = width;
1831  (*bitmap)->height = height;
1832  (*bitmap)->format = format;
1833  (*bitmap)->image.decoder = NULL;
1834  (*bitmap)->hbitmap = hbitmap;
1835  (*bitmap)->hdc = NULL;
1836  (*bitmap)->bits = bits;
1837  (*bitmap)->stride = stride;
1838  (*bitmap)->own_bits = own_bits;
1839  (*bitmap)->metadata_reader = NULL;
1840  (*bitmap)->prop_count = 0;
1841  (*bitmap)->prop_item = NULL;
1842 
1843  /* set format-related flags */
1845  (*bitmap)->image.flags |= ImageFlagsHasAlpha;
1846 
1847  if (format == PixelFormat1bppIndexed ||
1848  format == PixelFormat4bppIndexed ||
1849  format == PixelFormat8bppIndexed)
1850  {
1851  (*bitmap)->image.palette = heap_alloc_zero(sizeof(UINT) * 2 + sizeof(ARGB) * (1 << PIXELFORMATBPP(format)));
1852 
1853  if (!(*bitmap)->image.palette)
1854  {
1855  GdipDisposeImage(&(*bitmap)->image);
1856  *bitmap = NULL;
1857  return OutOfMemory;
1858  }
1859 
1860  (*bitmap)->image.palette->Count = 1 << PIXELFORMATBPP(format);
1861 
1862  if (format == PixelFormat1bppIndexed)
1863  {
1864  (*bitmap)->image.palette->Flags = PaletteFlagsGrayScale;
1865  (*bitmap)->image.palette->Entries[0] = 0xff000000;
1866  (*bitmap)->image.palette->Entries[1] = 0xffffffff;
1867  }
1868  else
1869  {
1870  if (format == PixelFormat8bppIndexed)
1871  (*bitmap)->image.palette->Flags = PaletteFlagsHalftone;
1872 
1873  generate_halftone_palette((*bitmap)->image.palette->Entries,
1874  (*bitmap)->image.palette->Count);
1875  }
1876  }
1877 
1878  TRACE("<-- %p\n", *bitmap);
1879 
1880  return Ok;
1881 }
1882 
1884  GpBitmap **bitmap)
1885 {
1886  GpStatus stat;
1887 
1888  TRACE("%p %p\n", stream, bitmap);
1889 
1890  stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
1891 
1892  if(stat != Ok)
1893  return stat;
1894 
1895  if((*bitmap)->image.type != ImageTypeBitmap){
1896  GdipDisposeImage(&(*bitmap)->image);
1897  *bitmap = NULL;
1898  return GenericError; /* FIXME: what error to return? */
1899  }
1900 
1901  return Ok;
1902 }
1903 
1904 /* FIXME: no icm */
1906  GpBitmap **bitmap)
1907 {
1908  TRACE("%p %p\n", stream, bitmap);
1909 
1910  return GdipCreateBitmapFromStream(stream, bitmap);
1911 }
1912 
1914  GpCachedBitmap **cachedbmp)
1915 {
1916  GpStatus stat;
1917 
1918  TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
1919 
1920  if(!bitmap || !graphics || !cachedbmp)
1921  return InvalidParameter;
1922 
1923  *cachedbmp = heap_alloc_zero(sizeof(GpCachedBitmap));
1924  if(!*cachedbmp)
1925  return OutOfMemory;
1926 
1927  stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
1928  if(stat != Ok){
1929  heap_free(*cachedbmp);
1930  return stat;
1931  }
1932 
1933  return Ok;
1934 }
1935 
1937 {
1938  GpStatus stat;
1939  BitmapData lockeddata;
1940  ULONG andstride, xorstride, bitssize;
1941  LPBYTE andbits, xorbits, androw, xorrow, srcrow;
1942  UINT x, y;
1943 
1944  TRACE("(%p, %p)\n", bitmap, hicon);
1945 
1946  if (!bitmap || !hicon)
1947  return InvalidParameter;
1948 
1949  stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead,
1950  PixelFormat32bppPARGB, &lockeddata);
1951  if (stat == Ok)
1952  {
1953  andstride = ((lockeddata.Width+31)/32)*4;
1954  xorstride = lockeddata.Width*4;
1955  bitssize = (andstride + xorstride) * lockeddata.Height;
1956 
1957  andbits = heap_alloc_zero(bitssize);
1958 
1959  if (andbits)
1960  {
1961  xorbits = andbits + andstride * lockeddata.Height;
1962 
1963  for (y=0; y<lockeddata.Height; y++)
1964  {
1965  srcrow = ((LPBYTE)lockeddata.Scan0) + lockeddata.Stride * y;
1966 
1967  androw = andbits + andstride * y;
1968  for (x=0; x<lockeddata.Width; x++)
1969  if (srcrow[3+4*x] >= 128)
1970  androw[x/8] |= 1 << (7-x%8);
1971 
1972  xorrow = xorbits + xorstride * y;
1973  memcpy(xorrow, srcrow, xorstride);
1974  }
1975 
1976  *hicon = CreateIcon(NULL, lockeddata.Width, lockeddata.Height, 1, 32,
1977  andbits, xorbits);
1978 
1979  heap_free(andbits);
1980  }
1981  else
1982  stat = OutOfMemory;
1983 
1984  GdipBitmapUnlockBits(bitmap, &lockeddata);
1985  }
1986 
1987  return stat;
1988 }
1989 
1991 {
1992  TRACE("%p\n", cachedbmp);
1993 
1994  if(!cachedbmp)
1995  return InvalidParameter;
1996 
1997  GdipDisposeImage(cachedbmp->image);
1998  heap_free(cachedbmp);
1999 
2000  return Ok;
2001 }
2002 
2004  GpCachedBitmap *cachedbmp, INT x, INT y)
2005 {
2006  TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
2007 
2008  if(!graphics || !cachedbmp)
2009  return InvalidParameter;
2010 
2011  return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
2012 }
2013 
2014 /* Internal utility function: Replace the image data of dst with that of src,
2015  * and free src. */
2016 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
2017 {
2018  assert(src->image.type == ImageTypeBitmap);
2019  assert(dst->image.type == ImageTypeBitmap);
2020 
2021  heap_free(dst->bitmapbits);
2022  heap_free(dst->own_bits);
2023  DeleteDC(dst->hdc);
2024  DeleteObject(dst->hbitmap);
2025 
2026  if (clobber_palette)
2027  {
2028  heap_free(dst->image.palette);
2029  dst->image.palette = src->image.palette;
2030  }
2031  else
2032  heap_free(src->image.palette);
2033 
2034  dst->image.xres = src->image.xres;
2035  dst->image.yres = src->image.yres;
2036  dst->width = src->width;
2037  dst->height = src->height;
2038  dst->format = src->format;
2039  dst->hbitmap = src->hbitmap;
2040  dst->hdc = src->hdc;
2041  dst->bits = src->bits;
2042  dst->stride = src->stride;
2043  dst->own_bits = src->own_bits;
2044  if (dst->metadata_reader)
2045  IWICMetadataReader_Release(dst->metadata_reader);
2046  dst->metadata_reader = src->metadata_reader;
2047  heap_free(dst->prop_item);
2048  dst->prop_item = src->prop_item;
2049  dst->prop_count = src->prop_count;
2050  if (dst->image.decoder)
2051  IWICBitmapDecoder_Release(dst->image.decoder);
2052  dst->image.decoder = src->image.decoder;
2053  dst->image.frame_count = src->image.frame_count;
2054  dst->image.current_frame = src->image.current_frame;
2055  dst->image.format = src->image.format;
2056 
2057  src->image.type = ~0;
2058  heap_free(src);
2059 }
2060 
2062 {
2063  if(!image)
2064  return InvalidParameter;
2065 
2066  if (image->type == ImageTypeBitmap)
2067  {
2068  heap_free(((GpBitmap*)image)->bitmapbits);
2069  heap_free(((GpBitmap*)image)->own_bits);
2070  DeleteDC(((GpBitmap*)image)->hdc);
2071  DeleteObject(((GpBitmap*)image)->hbitmap);
2072  if (((GpBitmap*)image)->metadata_reader)
2073  IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader);
2074  heap_free(((GpBitmap*)image)->prop_item);
2075  }
2076  else if (image->type == ImageTypeMetafile)
2077  {
2078  GpMetafile *metafile = (GpMetafile*)image;
2079  heap_free(metafile->comment_data);
2081  if (!metafile->preserve_hemf)
2082  DeleteEnhMetaFile(metafile->hemf);
2083  if (metafile->record_graphics)
2084  {
2085  WARN("metafile closed while recording\n");
2086  /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
2087  metafile->record_graphics->image = NULL;
2088  metafile->record_graphics->busy = TRUE;
2089  }
2090  if (metafile->record_stream)
2091  {
2092  IStream_Release(metafile->record_stream);
2093  }
2094  }
2095  else
2096  {
2097  WARN("invalid image: %p\n", image);
2098  return ObjectBusy;
2099  }
2100  if (image->decoder)
2101  IWICBitmapDecoder_Release(image->decoder);
2102  heap_free(image->palette);
2103 
2104  return Ok;
2105 }
2106 
2108 {
2109  GpStatus status;
2110 
2111  TRACE("%p\n", image);
2112 
2113  status = free_image_data(image);
2114  if (status != Ok) return status;
2115  image->type = ~0;
2116  heap_free(image);
2117 
2118  return Ok;
2119 }
2120 
2122 {
2123  static int calls;
2124 
2125  TRACE("(%p,%p)\n", image, item);
2126 
2127  if(!image || !item)
2128  return InvalidParameter;
2129 
2130  if (!(calls++))
2131  FIXME("not implemented\n");
2132 
2133  return NotImplemented;
2134 }
2135 
2137 {
2138  static int calls;
2139 
2140  TRACE("(%p,%p)\n", image, item);
2141 
2142  if (!(calls++))
2143  FIXME("not implemented\n");
2144 
2145  return NotImplemented;
2146 }
2147 
2149  GpUnit *srcUnit)
2150 {
2151  TRACE("%p %p %p\n", image, srcRect, srcUnit);
2152 
2153  if(!image || !srcRect || !srcUnit)
2154  return InvalidParameter;
2155  if(image->type == ImageTypeMetafile){
2156  *srcRect = ((GpMetafile*)image)->bounds;
2157  *srcUnit = ((GpMetafile*)image)->unit;
2158  }
2159  else if(image->type == ImageTypeBitmap){
2160  srcRect->X = srcRect->Y = 0.0;
2161  srcRect->Width = (REAL) ((GpBitmap*)image)->width;
2162  srcRect->Height = (REAL) ((GpBitmap*)image)->height;
2163  *srcUnit = UnitPixel;
2164  }
2165  else{
2166  WARN("GpImage with no image data\n");
2167  return InvalidParameter;
2168  }
2169 
2170  TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
2171  srcRect->Width, srcRect->Height, *srcUnit);
2172 
2173  return Ok;
2174 }
2175 
2177  REAL *height)
2178 {
2179  TRACE("%p %p %p\n", image, width, height);
2180 
2181  if(!image || !height || !width)
2182  return InvalidParameter;
2183 
2184  if(image->type == ImageTypeMetafile){
2185  *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2186  *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2187  }
2188  else if(image->type == ImageTypeBitmap){
2189  *height = ((GpBitmap*)image)->height;
2190  *width = ((GpBitmap*)image)->width;
2191  }
2192  else{
2193  WARN("GpImage with no image data\n");
2194  return InvalidParameter;
2195  }
2196 
2197  TRACE("returning (%f, %f)\n", *height, *width);
2198  return Ok;
2199 }
2200 
2202  GpGraphics **graphics)
2203 {
2204  HDC hdc;
2205  GpStatus stat;
2206 
2207  TRACE("%p %p\n", image, graphics);
2208 
2209  if(!image || !graphics)
2210  return InvalidParameter;
2211 
2212  if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
2213  {
2214  hdc = ((GpBitmap*)image)->hdc;
2215 
2216  if(!hdc){
2217  hdc = CreateCompatibleDC(0);
2218  SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
2219  ((GpBitmap*)image)->hdc = hdc;
2220  }
2221 
2222  stat = GdipCreateFromHDC(hdc, graphics);
2223 
2224  if (stat == Ok)
2225  {
2226  (*graphics)->image = image;
2227  (*graphics)->xres = image->xres;
2228  (*graphics)->yres = image->yres;
2229  }
2230  }
2231  else if (image->type == ImageTypeMetafile)
2232  stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics);
2233  else
2234  stat = graphics_from_image(image, graphics);
2235 
2236  return stat;
2237 }
2238 
2240 {
2241  TRACE("%p %p\n", image, height);
2242 
2243  if(!image || !height)
2244  return InvalidParameter;
2245 
2246  if(image->type == ImageTypeMetafile)
2247  *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2248  else if(image->type == ImageTypeBitmap)
2249  *height = ((GpBitmap*)image)->height;
2250  else
2251  {
2252  WARN("GpImage with no image data\n");
2253  return InvalidParameter;
2254  }
2255 
2256  TRACE("returning %d\n", *height);
2257 
2258  return Ok;
2259 }
2260 
2262 {
2263  if(!image || !res)
2264  return InvalidParameter;
2265 
2266  *res = image->xres;
2267 
2268  TRACE("(%p) <-- %0.2f\n", image, *res);
2269 
2270  return Ok;
2271 }
2272 
2274 {
2275  TRACE("%p %p\n", image, size);
2276 
2277  if(!image || !size)
2278  return InvalidParameter;
2279 
2280  if (!image->palette || image->palette->Count == 0)
2281  *size = sizeof(ColorPalette);
2282  else
2283  *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette->Count;
2284 
2285  TRACE("<-- %u\n", *size);
2286 
2287  return Ok;
2288 }
2289 
2290 /* FIXME: test this function for non-bitmap types */
2292 {
2293  TRACE("%p %p\n", image, format);
2294 
2295  if(!image || !format)
2296  return InvalidParameter;
2297 
2298  if(image->type != ImageTypeBitmap)
2299  *format = PixelFormat24bppRGB;
2300  else
2301  *format = ((GpBitmap*) image)->format;
2302 
2303  return Ok;
2304 }
2305 
2307 {
2308  TRACE("(%p, %p)\n", image, format);
2309 
2310  if(!image || !format)
2311  return InvalidParameter;
2312 
2313  memcpy(format, &image->format, sizeof(GUID));
2314 
2315  return Ok;
2316 }
2317 
2319 {
2320  TRACE("%p %p\n", image, type);
2321 
2322  if(!image || !type)
2323  return InvalidParameter;
2324 
2325  *type = image->type;
2326 
2327  return Ok;
2328 }
2329 
2331 {
2332  if(!image || !res)
2333  return InvalidParameter;
2334 
2335  *res = image->yres;
2336 
2337  TRACE("(%p) <-- %0.2f\n", image, *res);
2338 
2339  return Ok;
2340 }
2341 
2343 {
2344  TRACE("%p %p\n", image, width);
2345 
2346  if(!image || !width)
2347  return InvalidParameter;
2348 
2349  if(image->type == ImageTypeMetafile)
2350  *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2351  else if(image->type == ImageTypeBitmap)
2352  *width = ((GpBitmap*)image)->width;
2353  else
2354  {
2355  WARN("GpImage with no image data\n");
2356  return InvalidParameter;
2357  }
2358 
2359  TRACE("returning %d\n", *width);
2360 
2361  return Ok;
2362 }
2363 
2365 {
2366  TRACE("(%p, %p)\n", image, num);
2367 
2368  if (!image || !num) return InvalidParameter;
2369 
2370  *num = 0;
2371 
2372  if (image->type == ImageTypeBitmap)
2373  {
2374  if (((GpBitmap *)image)->prop_item)
2375  {
2376  *num = ((GpBitmap *)image)->prop_count;
2377  return Ok;
2378  }
2379 
2380  if (((GpBitmap *)image)->metadata_reader)
2381  IWICMetadataReader_GetCount(((GpBitmap *)image)->metadata_reader, num);
2382  }
2383 
2384  return Ok;
2385 }
2386 
2388 {
2389  HRESULT hr;
2391  IWICEnumMetadataItem *enumerator;
2392  UINT prop_count, i, items_returned;
2393 
2394  TRACE("(%p, %u, %p)\n", image, num, list);
2395 
2396  if (!image || !list) return InvalidParameter;
2397 
2398  if (image->type != ImageTypeBitmap)
2399  {
2400  FIXME("Not implemented for type %d\n", image->type);
2401  return NotImplemented;
2402  }
2403 
2404  if (((GpBitmap *)image)->prop_item)
2405  {
2406  if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter;
2407 
2408  for (i = 0; i < num; i++)
2409  {
2410  list[i] = ((GpBitmap *)image)->prop_item[i].id;
2411  }
2412 
2413  return Ok;
2414  }
2415 
2416  reader = ((GpBitmap *)image)->metadata_reader;
2417  if (!reader)
2418  {
2419  if (num != 0) return InvalidParameter;
2420  return Ok;
2421  }
2422 
2423  hr = IWICMetadataReader_GetCount(reader, &prop_count);
2424  if (FAILED(hr)) return hresult_to_status(hr);
2425 
2426  if (num != prop_count) return InvalidParameter;
2427 
2428  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2429  if (FAILED(hr)) return hresult_to_status(hr);
2430 
2431  IWICEnumMetadataItem_Reset(enumerator);
2432 
2433  for (i = 0; i < num; i++)
2434  {
2435  PROPVARIANT id;
2436 
2437  hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, NULL, &items_returned);
2438  if (hr != S_OK) break;
2439 
2440  if (id.vt != VT_UI2)
2441  {
2442  FIXME("not supported propvariant type for id: %u\n", id.vt);
2443  list[i] = 0;
2444  continue;
2445  }
2446  list[i] = id.u.uiVal;
2447  }
2448 
2449  IWICEnumMetadataItem_Release(enumerator);
2450 
2451  return hr == S_OK ? Ok : hresult_to_status(hr);
2452 }
2453 
2454 static UINT propvariant_size(PROPVARIANT *value)
2455 {
2456  switch (value->vt & ~VT_VECTOR)
2457  {
2458  case VT_EMPTY:
2459  return 0;
2460  case VT_I1:
2461  case VT_UI1:
2462  if (!(value->vt & VT_VECTOR)) return 1;
2463  return value->u.caub.cElems;
2464  case VT_I2:
2465  case VT_UI2:
2466  if (!(value->vt & VT_VECTOR)) return 2;
2467  return value->u.caui.cElems * 2;
2468  case VT_I4:
2469  case VT_UI4:
2470  case VT_R4:
2471  if (!(value->vt & VT_VECTOR)) return 4;
2472  return value->u.caul.cElems * 4;
2473  case VT_I8:
2474  case VT_UI8:
2475  case VT_R8:
2476  if (!(value->vt & VT_VECTOR)) return 8;
2477  return value->u.cauh.cElems * 8;
2478  case VT_LPSTR:
2479  return value->u.pszVal ? strlen(value->u.pszVal) + 1 : 0;
2480  case VT_BLOB:
2481  return value->u.blob.cbSize;
2482  default:
2483  FIXME("not supported variant type %d\n", value->vt);
2484  return 0;
2485  }
2486 }
2487 
2489 {
2490  HRESULT hr;
2492  PROPVARIANT id, value;
2493 
2494  TRACE("(%p,%#x,%p)\n", image, propid, size);
2495 
2496  if (!size || !image) return InvalidParameter;
2497 
2498  if (image->type != ImageTypeBitmap)
2499  {
2500  FIXME("Not implemented for type %d\n", image->type);
2501  return NotImplemented;
2502  }
2503 
2504  if (((GpBitmap *)image)->prop_item)
2505  {
2506  UINT i;
2507 
2508  for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2509  {
2510  if (propid == ((GpBitmap *)image)->prop_item[i].id)
2511  {
2512  *size = sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2513  return Ok;
2514  }
2515  }
2516 
2517  return PropertyNotFound;
2518  }
2519 
2520  reader = ((GpBitmap *)image)->metadata_reader;
2521  if (!reader) return PropertyNotFound;
2522 
2523  id.vt = VT_UI2;
2524  id.u.uiVal = propid;
2525  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2526  if (FAILED(hr)) return PropertyNotFound;
2527 
2528  *size = propvariant_size(&value);
2529  if (*size) *size += sizeof(PropertyItem);
2530  PropVariantClear(&value);
2531 
2532  return Ok;
2533 }
2534 
2535 #ifndef PropertyTagTypeSByte
2536 #define PropertyTagTypeSByte 6
2537 #define PropertyTagTypeSShort 8
2538 #define PropertyTagTypeFloat 11
2539 #define PropertyTagTypeDouble 12
2540 #endif
2541 
2543 {
2544  static const struct
2545  {
2546  UINT vt, type;
2547  } vt2type[] =
2548  {
2561  };
2562  UINT i;
2563  for (i = 0; i < sizeof(vt2type)/sizeof(vt2type[0]); i++)
2564  {
2565  if (vt2type[i].vt == vt) return vt2type[i].type;
2566  }
2567  FIXME("not supported variant type %u\n", vt);
2568  return 0;
2569 }
2570 
2572  UINT size, PROPID id)
2573 {
2574  UINT item_size, item_type;
2575 
2576  item_size = propvariant_size(value);
2577  if (size != item_size + sizeof(PropertyItem)) return InvalidParameter;
2578 
2579  item_type = vt_to_itemtype(value->vt & ~VT_VECTOR);
2580  if (!item_type) return InvalidParameter;
2581 
2582  item->value = item + 1;
2583 
2584  switch (value->vt & ~VT_VECTOR)
2585  {
2586  case VT_I1:
2587  case VT_UI1:
2588  if (!(value->vt & VT_VECTOR))
2589  *(BYTE *)item->value = value->u.bVal;
2590  else
2591  memcpy(item->value, value->u.caub.pElems, item_size);
2592  break;
2593  case VT_I2:
2594  case VT_UI2:
2595  if (!(value->vt & VT_VECTOR))
2596  *(USHORT *)item->value = value->u.uiVal;
2597  else
2598  memcpy(item->value, value->u.caui.pElems, item_size);
2599  break;
2600  case VT_I4:
2601  case VT_UI4:
2602  case VT_R4:
2603  if (!(value->vt & VT_VECTOR))
2604  *(ULONG *)item->value = value->u.ulVal;
2605  else
2606  memcpy(item->value, value->u.caul.pElems, item_size);
2607  break;
2608  case VT_I8:
2609  case VT_UI8:
2610  case VT_R8:
2611  if (!(value->vt & VT_VECTOR))
2612  *(ULONGLONG *)item->value = value->u.uhVal.QuadPart;
2613  else
2614  memcpy(item->value, value->u.cauh.pElems, item_size);
2615  break;
2616  case VT_LPSTR:
2617  memcpy(item->value, value->u.pszVal, item_size);
2618  break;
2619  case VT_BLOB:
2620  memcpy(item->value, value->u.blob.pBlobData, item_size);
2621  break;
2622  default:
2623  FIXME("not supported variant type %d\n", value->vt);
2624  return InvalidParameter;
2625  }
2626 
2627  item->length = item_size;
2628  item->type = item_type;
2629  item->id = id;
2630 
2631  return Ok;
2632 }
2633 
2636 {
2637  GpStatus stat;
2638  HRESULT hr;
2640  PROPVARIANT id, value;
2641 
2642  TRACE("(%p,%#x,%u,%p)\n", image, propid, size, buffer);
2643 
2644  if (!image || !buffer) return InvalidParameter;
2645 
2646  if (image->type != ImageTypeBitmap)
2647  {
2648  FIXME("Not implemented for type %d\n", image->type);
2649  return NotImplemented;
2650  }
2651 
2652  if (((GpBitmap *)image)->prop_item)
2653  {
2654  UINT i;
2655 
2656  for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2657  {
2658  if (propid == ((GpBitmap *)image)->prop_item[i].id)
2659  {
2660  if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length)
2661  return InvalidParameter;
2662 
2663  *buffer = ((GpBitmap *)image)->prop_item[i];
2664  buffer->value = buffer + 1;
2665  memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length);
2666  return Ok;
2667  }
2668  }
2669 
2670  return PropertyNotFound;
2671  }
2672 
2673  reader = ((GpBitmap *)image)->metadata_reader;
2674  if (!reader) return PropertyNotFound;
2675 
2676  id.vt = VT_UI2;
2677  id.u.uiVal = propid;
2678  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2679  if (FAILED(hr)) return PropertyNotFound;
2680 
2681  stat = propvariant_to_item(&value, buffer, size, propid);
2682  PropVariantClear(&value);
2683 
2684  return stat;
2685 }
2686 
2688 {
2689  HRESULT hr;
2691  IWICEnumMetadataItem *enumerator;
2692  UINT prop_count, prop_size, i;
2693  PROPVARIANT id, value;
2694 
2695  TRACE("(%p,%p,%p)\n", image, size, count);
2696 
2697  if (!image || !size || !count) return InvalidParameter;
2698 
2699  if (image->type != ImageTypeBitmap)
2700  {
2701  FIXME("Not implemented for type %d\n", image->type);
2702  return NotImplemented;
2703  }
2704 
2705  if (((GpBitmap *)image)->prop_item)
2706  {
2707  *count = ((GpBitmap *)image)->prop_count;
2708  *size = 0;
2709 
2710  for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2711  {
2712  *size += sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2713  }
2714 
2715  return Ok;
2716  }
2717 
2718  reader = ((GpBitmap *)image)->metadata_reader;
2719  if (!reader) return PropertyNotFound;
2720 
2721  hr = IWICMetadataReader_GetCount(reader, &prop_count);
2722  if (FAILED(hr)) return hresult_to_status(hr);
2723 
2724  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2725  if (FAILED(hr)) return hresult_to_status(hr);
2726 
2727  IWICEnumMetadataItem_Reset(enumerator);
2728 
2729  prop_size = 0;
2730 
2731  PropVariantInit(&id);
2732  PropVariantInit(&value);
2733 
2734  for (i = 0; i < prop_count; i++)
2735  {
2736  UINT items_returned, item_size;
2737 
2738  hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2739  if (hr != S_OK) break;
2740 
2741  item_size = propvariant_size(&value);
2742  if (item_size) prop_size += sizeof(PropertyItem) + item_size;
2743 
2744  PropVariantClear(&id);
2745  PropVariantClear(&value);
2746  }
2747 
2748  IWICEnumMetadataItem_Release(enumerator);
2749 
2750  if (hr != S_OK) return PropertyNotFound;
2751 
2752  *count = prop_count;
2753  *size = prop_size;
2754  return Ok;
2755 }
2756 
2759 {
2760  GpStatus status;
2761  HRESULT hr;
2763  IWICEnumMetadataItem *enumerator;
2764  UINT prop_count, prop_size, i;
2765  PROPVARIANT id, value;
2766  char *item_value;
2767 
2768  TRACE("(%p,%u,%u,%p)\n", image, size, count, buf);
2769 
2770  if (!image || !buf) return InvalidParameter;
2771 
2772  if (image->type != ImageTypeBitmap)
2773  {
2774  FIXME("Not implemented for type %d\n", image->type);
2775  return NotImplemented;
2776  }
2777 
2778  status = GdipGetPropertySize(image, &prop_size, &prop_count);
2779  if (status != Ok) return status;
2780 
2781  if (prop_count != count || prop_size != size) return InvalidParameter;
2782 
2783  if (((GpBitmap *)image)->prop_item)
2784  {
2785  memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size);
2786 
2787  item_value = (char *)(buf + prop_count);
2788 
2789  for (i = 0; i < prop_count; i++)
2790  {
2791  buf[i].value = item_value;
2792  item_value += buf[i].length;
2793  }
2794 
2795  return Ok;
2796  }
2797 
2798  reader = ((GpBitmap *)image)->metadata_reader;
2799  if (!reader) return PropertyNotFound;
2800 
2801  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2802  if (FAILED(hr)) return hresult_to_status(hr);
2803 
2804  IWICEnumMetadataItem_Reset(enumerator);
2805 
2806  item_value = (char *)(buf + prop_count);
2807 
2808  PropVariantInit(&id);
2809  PropVariantInit(&value);
2810 
2811  for (i = 0; i < prop_count; i++)
2812  {
2813  PropertyItem *item;
2814  UINT items_returned, item_size;
2815 
2816  hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2817  if (hr != S_OK) break;
2818 
2819  if (id.vt != VT_UI2)
2820  {
2821  FIXME("not supported propvariant type for id: %u\n", id.vt);
2822  continue;
2823  }
2824 
2825  item_size = propvariant_size(&value);
2826  if (item_size)
2827  {
2828  item = heap_alloc(item_size + sizeof(*item));
2829 
2830  propvariant_to_item(&value, item, item_size + sizeof(*item), id.u.uiVal);
2831  buf[i].id = item->id;
2832  buf[i].type = item->type;
2833  buf[i].length = item_size;
2834  buf[i].value = item_value;
2835  memcpy(item_value, item->value, item_size);
2836  item_value += item_size;
2837 
2838  heap_free(item);
2839  }
2840 
2841  PropVariantClear(&id);
2842  PropVariantClear(&value);
2843  }
2844 
2845  IWICEnumMetadataItem_Release(enumerator);
2846 
2847  if (hr != S_OK) return PropertyNotFound;
2848 
2849  return Ok;
2850 }
2851 
2853 {
2854  const GUID *format;
2855  const GUID *dimension;
2856 };
2857 
2859 {
2860  {&ImageFormatGIF, &FrameDimensionTime},
2861  {&ImageFormatIcon, &FrameDimensionResolution},
2862  {NULL}
2863 };
2864 
2866  GDIPCONST GUID* dimensionID, UINT* count)
2867 {
2868  TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
2869 
2870  if(!image || !count)
2871  return InvalidParameter;
2872 
2873  if (!dimensionID ||
2874  IsEqualGUID(dimensionID, &image->format) ||
2875  IsEqualGUID(dimensionID, &FrameDimensionPage) ||
2876  IsEqualGUID(dimensionID, &FrameDimensionTime))
2877  {
2878  *count = image->frame_count;
2879  return Ok;
2880  }
2881 
2882  return InvalidParameter;
2883 }
2884 
2886  UINT* count)
2887 {
2888  TRACE("(%p, %p)\n", image, count);
2889 
2890  /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
2891 
2892  if(!image || !count)
2893  return InvalidParameter;
2894 
2895  *count = 1;
2896 
2897  return Ok;
2898 }
2899 
2901  GUID* dimensionIDs, UINT count)
2902 {
2903  int i;
2904  const GUID *result=NULL;
2905 
2906  TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
2907 
2908  if(!image || !dimensionIDs || count != 1)
2909  return InvalidParameter;
2910 
2911  for (i=0; image_format_dimensions[i].format; i++)
2912  {
2913  if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
2914  {
2915  result = image_format_dimensions[i].dimension;
2916  break;
2917  }
2918  }
2919 
2920  if (!result)
2921  result = &FrameDimensionPage;
2922 
2923  memcpy(dimensionIDs, result, sizeof(GUID));
2924 
2925  return Ok;
2926 }
2927 
2929  GpImage **image)
2930 {
2931  GpStatus stat;
2932  IStream *stream;
2933 
2934  TRACE("(%s) %p\n", debugstr_w(filename), image);
2935 
2936  if (!filename || !image)
2937  return InvalidParameter;
2938 
2939  *image = NULL;
2940 
2941  stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
2942 
2943  if (stat != Ok)
2944  return stat;
2945 
2946  stat = GdipLoadImageFromStream(stream, image);
2947 
2948  IStream_Release(stream);
2949 
2950  return stat;
2951 }
2952 
2953 /* FIXME: no icm handling */
2955 {
2956  TRACE("(%s) %p\n", debugstr_w(filename), image);
2957 
2958  return GdipLoadImageFromFile(filename, image);
2959 }
2960 
2962 {
2963  UINT prop_size, prop_count;
2964  PropertyItem *prop_item;
2965 
2966  if (bitmap->prop_item == NULL)
2967  {
2968  prop_size = prop_count = 0;
2969  prop_item = heap_alloc_zero(item->length + sizeof(PropertyItem));
2970  if (!prop_item) return;
2971  }
2972  else
2973  {
2974  UINT i;
2975  char *item_value;
2976 
2977  GdipGetPropertySize(&bitmap->image, &prop_size, &prop_count);
2978 
2979  prop_item = heap_alloc_zero(prop_size + item->length + sizeof(PropertyItem));
2980  if (!prop_item) return;
2981  memcpy(prop_item, bitmap->prop_item, sizeof(PropertyItem) * bitmap->prop_count);
2982  prop_size -= sizeof(PropertyItem) * bitmap->prop_count;
2983  memcpy(prop_item + prop_count + 1, bitmap->prop_item + prop_count, prop_size);
2984 
2985  item_value = (char *)(prop_item + prop_count + 1);
2986 
2987  for (i = 0; i < prop_count; i++)
2988  {
2989  prop_item[i].value = item_value;
2990  item_value += prop_item[i].length;
2991  }
2992  }
2993 
2994  prop_item[prop_count].id = item->id;
2995  prop_item[prop_count].type = item->type;
2996  prop_item[prop_count].length = item->length;
2997  prop_item[prop_count].value = (char *)(prop_item + prop_count + 1) + prop_size;
2998  memcpy(prop_item[prop_count].value, item->value, item->length);
2999 
3000  heap_free(bitmap->prop_item);
3001  bitmap->prop_item = prop_item;
3002  bitmap->prop_count++;
3003 }
3004 
3005 static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3006 {
3007  HRESULT hr;
3008  GUID format;
3009  PROPVARIANT id, value;
3010  BOOL ret = FALSE;
3011 
3012  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
3013  if (FAILED(hr) || !IsEqualGUID(&format, guid)) return FALSE;
3014 
3015  PropVariantInit(&id);
3016  PropVariantInit(&value);
3017 
3018  id.vt = VT_LPWSTR;
3019  id.u.pwszVal = CoTaskMemAlloc((lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3020  if (!id.u.pwszVal) return FALSE;
3021  lstrcpyW(id.u.pwszVal, prop_name);
3022  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3023  if (hr == S_OK && value.vt == VT_BOOL)
3024  ret = value.u.boolVal;
3025 
3026  PropVariantClear(&id);
3027  PropVariantClear(&value);
3028 
3029  return ret;
3030 }
3031 
3032 static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3033 {
3034  HRESULT hr;
3035  GUID format;
3036  PROPVARIANT id, value;
3037  PropertyItem *item = NULL;
3038 
3039  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
3040  if (FAILED(hr) || !IsEqualGUID(&format, guid)) return NULL;
3041 
3042  PropVariantInit(&id);
3043  PropVariantInit(&value);
3044 
3045  id.vt = VT_LPWSTR;
3046  id.u.pwszVal = CoTaskMemAlloc((lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3047  if (!id.u.pwszVal) return NULL;
3048  lstrcpyW(id.u.pwszVal, prop_name);
3049  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3050  if (hr == S_OK)
3051  {
3052  UINT item_size = propvariant_size(&value);
3053  if (item_size)
3054  {
3055  item_size += sizeof(*item);
3056  item = heap_alloc_zero(item_size);
3057  if (propvariant_to_item(&value, item, item_size, 0) != Ok)
3058  {
3059  heap_free(item);
3060  item = NULL;
3061  }
3062  }
3063  }
3064 
3065  PropVariantClear(&id);
3066  PropVariantClear(&value);
3067 
3068  return item;
3069 }
3070 
3072 {
3073  static const WCHAR textentryW[] = { 'T','e','x','t','E','n','t','r','y',0 };
3075 
3076  comment = get_property(reader, &GUID_MetadataFormatGifComment, textentryW);
3077  if (comment)
3078  comment->id = PropertyTagExifUserComment;
3079 
3080  return comment;
3081 }
3082 
3084 {
3085  static const WCHAR applicationW[] = { 'A','p','p','l','i','c','a','t','i','o','n',0 };
3086  static const WCHAR dataW[] = { 'D','a','t','a',0 };
3087  PropertyItem *appext = NULL, *appdata = NULL, *loop = NULL;
3088 
3089  appext = get_property(reader, &GUID_MetadataFormatAPE, applicationW);
3090  if (appext)
3091  {
3092  if (appext->type == PropertyTagTypeByte && appext->length == 11 &&
3093  (!memcmp(appext->value, "NETSCAPE2.0", 11) || !memcmp(appext->value, "ANIMEXTS1.0", 11)))
3094  {
3095  appdata = get_property(reader, &GUID_MetadataFormatAPE, dataW);
3096  if (appdata)
3097  {
3098  if (appdata->type == PropertyTagTypeByte && appdata->length == 4)
3099  {
3100  BYTE *data = appdata->value;
3101  if (data[0] == 3 && data[1] == 1)
3102  {
3103  loop = heap_alloc_zero(sizeof(*loop) + sizeof(SHORT));
3104  if (loop)
3105  {
3106  loop->type = PropertyTagTypeShort;
3107  loop->id = PropertyTagLoopCount;
3108  loop->length = sizeof(SHORT);
3109  loop->value = loop + 1;
3110  *(SHORT *)loop->value = data[2] | (data[3] << 8);
3111  }
3112  }
3113  }
3114  }
3115  }
3116  }
3117 
3118  heap_free(appext);
3119  heap_free(appdata);
3120 
3121  return loop;
3122 }
3123 
3125 {
3126  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 };
3127  PropertyItem *background;
3128 
3129  background = get_property(reader, &GUID_MetadataFormatLSD, backgroundW);
3130  if (background)
3131  background->id = PropertyTagIndexBackground;
3132 
3133  return background;
3134 }
3135 
3137 {
3138  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 };
3139  HRESULT hr;
3142  UINT count = 0;
3143  WICColor colors[256];
3144 
3145  if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW))
3146  return NULL;
3147 
3148  hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
3149  if (hr != S_OK) return NULL;
3150 
3151  hr = IWICImagingFactory_CreatePalette(factory, &palette);
3152  if (hr == S_OK)
3153  {
3154  hr = IWICBitmapDecoder_CopyPalette(decoder, palette);
3155  if (hr == S_OK)
3156  IWICPalette_GetColors(palette, 256, colors, &count);
3157 
3158  IWICPalette_Release(palette);
3159  }
3160 
3161  IWICImagingFactory_Release(factory);
3162 
3163  if (count)
3164  {
3165  PropertyItem *pal;
3166  UINT i;
3167  BYTE *rgb;
3168 
3169  pal = heap_alloc_zero(sizeof(*pal) + count * 3);
3170  if (!pal) return NULL;
3171  pal->type = PropertyTagTypeByte;
3173  pal->value = pal + 1;
3174  pal->length = count * 3;
3175 
3176  rgb = pal->value;
3177 
3178  for (i = 0; i < count; i++)
3179  {
3180  rgb[i*3] = (colors[i] >> 16) & 0xff;
3181  rgb[i*3 + 1] = (colors[i] >> 8) & 0xff;
3182  rgb[i*3 + 2] = colors[i] & 0xff;
3183  }
3184 
3185  return pal;
3186  }
3187 
3188  return NULL;
3189 }
3190 
3192 {
3193  static const WCHAR transparency_flagW[] = { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 };
3194  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 };
3195  PropertyItem *index = NULL;
3196 
3197  if (get_bool_property(reader, &GUID_MetadataFormatGCE, transparency_flagW))
3198  {
3199  index = get_property(reader, &GUID_MetadataFormatGCE, colorW);
3200  if (index)
3202  }
3203  return index;
3204 }
3205 
3207 {
3208  HRESULT hr;
3209  IWICMetadataBlockReader *block_reader;
3211  UINT block_count, i;
3212  PropertyItem *prop;
3213  LONG value = 0;
3214 
3215  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3216  if (hr == S_OK)
3217  {
3218  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3219  if (hr == S_OK)
3220  {
3221  for (i = 0; i < block_count; i++)
3222  {
3223  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3224  if (hr == S_OK)
3225  {
3226  prop = get_property(reader, format, property);
3227  if (prop)
3228  {
3229  if (prop->type == PropertyTagTypeByte && prop->length == 1)
3230  value = *(BYTE *)prop->value;
3231  else if (prop->type == PropertyTagTypeShort && prop->length == 2)
3232  value = *(SHORT *)prop->value;
3233 
3234  heap_free(prop);
3235  }
3236  IWICMetadataReader_Release(reader);
3237  }
3238  }
3239  }
3240  IWICMetadataBlockReader_Release(block_reader);
3241  }
3242 
3243  return value;
3244 }
3245 
3246 static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
3247 {
3248  static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
3249  HRESULT hr;
3250  IWICBitmapFrameDecode *frame;
3251  IWICMetadataBlockReader *block_reader;
3253  UINT frame_count, block_count, i;
3254  PropertyItem *delay = NULL, *comment = NULL, *background = NULL;
3255  PropertyItem *transparent_idx = NULL, *loop = NULL, *palette = NULL;
3256 
3257  IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3258  if (frame_count > 1)
3259  {
3260  delay = heap_alloc_zero(sizeof(*delay) + frame_count * sizeof(LONG));
3261  if (delay)
3262  {
3263  LONG *value;
3264 
3265  delay->type = PropertyTagTypeLong;
3266  delay->id = PropertyTagFrameDelay;
3267  delay->length = frame_count * sizeof(LONG);
3268  delay->value = delay + 1;
3269 
3270  value = delay->value;
3271 
3272  for (i = 0; i < frame_count; i++)
3273  {
3274  hr = IWICBitmapDecoder_GetFrame(decoder, i, &frame);
3275  if (hr == S_OK)
3276  {
3277  value[i] = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, delayW);
3278  IWICBitmapFrameDecode_Release(frame);
3279  }
3280  else value[i] = 0;
3281  }
3282  }
3283  }
3284 
3285  hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3286  if (hr == S_OK)
3287  {
3288  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3289  if (hr == S_OK)
3290  {
3291  for (i = 0; i < block_count; i++)
3292  {
3293  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3294  if (hr == S_OK)
3295  {
3296  if (!comment)
3297  comment = get_gif_comment(reader);
3298 
3299  if (frame_count > 1 && !loop)
3300  loop = get_gif_loopcount(reader);
3301 
3302  if (!background)
3303  background = get_gif_background(reader);
3304 
3305  if (!palette)
3306  palette = get_gif_palette(decoder, reader);
3307 
3308  IWICMetadataReader_Release(reader);
3309  }
3310  }
3311  }
3312  IWICMetadataBlockReader_Release(block_reader);
3313  }
3314 
3315  if (frame_count > 1 && !loop)
3316  {
3317  loop = heap_alloc_zero(sizeof(*loop) + sizeof(SHORT));
3318  if (loop)
3319  {
3320  loop->type = PropertyTagTypeShort;
3321  loop->id = PropertyTagLoopCount;
3322  loop->length = sizeof(SHORT);
3323  loop->value = loop + 1;
3324  *(SHORT *)loop->value = 1;
3325  }
3326  }
3327 
3328  if (delay) add_property(bitmap, delay);
3329  if (comment) add_property(bitmap, comment);
3330  if (loop) add_property(bitmap, loop);
3331  if (palette) add_property(bitmap, palette);
3332  if (background) add_property(bitmap, background);
3333 
3334  heap_free(delay);
3335  heap_free(comment);
3336  heap_free(loop);
3337  heap_free(palette);
3338  heap_free(background);
3339 
3340  /* Win7 gdiplus always returns transparent color index from frame 0 */
3341  hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
3342  if (hr != S_OK) return;
3343 
3344  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3345  if (hr == S_OK)
3346  {
3347  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3348  if (hr == S_OK)
3349  {
3350  for (i = 0; i < block_count; i++)
3351  {
3352  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3353  if (hr == S_OK)
3354  {
3355  if (!transparent_idx)
3356  transparent_idx = get_gif_transparent_idx(reader);
3357 
3358  IWICMetadataReader_Release(reader);
3359  }
3360  }
3361  }
3362  IWICMetadataBlockReader_Release(block_reader);
3363  }
3364 
3365  if (transparent_idx) add_property(bitmap, transparent_idx);
3366  heap_free(transparent_idx);
3367 
3368  IWICBitmapFrameDecode_Release(frame);
3369 }
3370 
3371 static PropertyItem* create_prop(PROPID propid, PROPVARIANT* value)
3372 {
3373  PropertyItem *item = NULL;
3374  UINT item_size = propvariant_size(value);
3375 
3376  if (item_size)
3377  {
3378  item_size += sizeof(*item);
3379  item = heap_alloc_zero(item_size);
3380  if (propvariant_to_item(value, item, item_size, propid) != Ok)
3381  {
3382  heap_free(item);
3383  item = NULL;
3384  }
3385  }
3386 
3387  return item;
3388 }
3389 
3391 {
3392  PROPVARIANT value;
3393  HRESULT hr;
3394  ULONG result=0;
3395 
3396  hr = IWICMetadataReader_GetValueByIndex(reader, index, NULL, NULL, &value);
3397  if (SUCCEEDED(hr))
3398  {
3399  switch (value.vt)
3400  {
3401  case VT_UI4:
3402  result = value.u.ulVal;
3403  break;
3404  default:
3405  ERR("unhandled case %u\n", value.vt);
3406  break;
3407  }
3408  PropVariantClear(&value);
3409  }
3410  return result;
3411 }
3412 
3413 static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
3414 {
3415  HRESULT hr;
3416  IWICBitmapFrameDecode *frame;
3417  IWICMetadataBlockReader *block_reader;
3419  UINT block_count, i, j;
3420  struct keyword_info {
3421  const char* name;
3422  PROPID propid;
3423  BOOL seen;
3424  } keywords[] = {
3425  { "Title", PropertyTagImageTitle },
3426  { "Author", PropertyTagArtist },
3427  { "Description", PropertyTagImageDescription },
3428  { "Copyright", PropertyTagCopyright },
3429  { "Software", PropertyTagSoftwareUsed },
3430  { "Source", PropertyTagEquipModel },
3431  { "Comment", PropertyTagExifUserComment },
3432  };
3433  BOOL seen_gamma=FALSE, seen_whitepoint=FALSE, seen_chrm=FALSE;
3434 
3435  hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
3436  if (hr != S_OK) return;
3437 
3438  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3439  if (hr == S_OK)
3440  {
3441  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3442  if (hr == S_OK)
3443  {
3444  for (i = 0; i < block_count; i++)
3445  {
3446  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3447  if (hr == S_OK)
3448  {
3449  GUID format;
3450 
3451  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
3452  if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunktEXt, &format))
3453  {
3454  PROPVARIANT name, value;
3455  PropertyItem* item;
3456 
3457  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &name, &value);
3458 
3459  if (SUCCEEDED(hr))
3460  {
3461  if (name.vt == VT_LPSTR)
3462  {
3463  for (j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++)
3464  if (!strcmp(keywords[j].name, name.u.pszVal))
3465  break;
3466  if (j < sizeof(keywords)/sizeof(keywords[0]) && !keywords[j].seen)
3467  {
3468  keywords[j].seen = TRUE;
3469  item = create_prop(keywords[j].propid, &value);
3470  if (item)
3471  add_property(bitmap, item);
3472  heap_free(item);
3473  }
3474  }
3475 
3476  PropVariantClear(&name);
3477  PropVariantClear(&value);
3478  }
3479  }
3480  else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkgAMA, &format))
3481  {
3482  PropertyItem* item;
3483 
3484  if (!seen_gamma)
3485  {
3486  item = heap_alloc_zero(sizeof(PropertyItem) + sizeof(ULONG) * 2);
3487  if (item)
3488  {
3489  ULONG *rational;
3490  item->length = sizeof(ULONG) * 2;
3491  item->type = PropertyTagTypeRational;
3492  item->id = PropertyTagGamma;
3493  rational = item->value = item + 1;
3494  rational[0] = 100000;
3495  rational[1] = get_ulong_by_index(reader, 0);
3496  add_property(bitmap, item);
3497  seen_gamma = TRUE;
3498  heap_free(item);
3499  }
3500  }
3501  }
3502  else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkcHRM, &format))
3503  {
3504  PropertyItem* item;
3505 
3506  if (!seen_whitepoint)
3507  {
3508  item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 4);
3509  if (item)
3510  {
3511  ULONG *rational;
3512  item->length = sizeof(ULONG) * 4;
3513  item->type = PropertyTagTypeRational;
3514  item->id = PropertyTagWhitePoint;
3515  rational = item->value = item + 1;
3516  rational[0] = get_ulong_by_index(reader, 0);
3517  rational[1] = 100000;
3518  rational[2] = get_ulong_by_index(reader, 1);
3519  rational[3] = 100000;
3520  add_property(bitmap, item);
3521  seen_whitepoint = TRUE;
3522  GdipFree(item);
3523  }
3524  }
3525  if (!seen_chrm)
3526  {
3527  item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 12);
3528  if (item)
3529  {
3530  ULONG *rational;
3531  item->length = sizeof(ULONG) * 12;
3532  item->type = PropertyTagTypeRational;
3534  rational = item->value = item + 1;
3535  rational[0] = get_ulong_by_index(reader, 2);
3536  rational[1] = 100000;
3537  rational[2] = get_ulong_by_index(reader, 3);
3538  rational[3] = 100000;
3539  rational[4] = get_ulong_by_index(reader, 4);
3540  rational[5] = 100000;
3541  rational[6] = get_ulong_by_index(reader, 5);
3542  rational[7] = 100000;
3543  rational[8] = get_ulong_by_index(reader, 6);
3544  rational[9] = 100000;
3545  rational[10] = get_ulong_by_index(reader, 7);
3546  rational[11] = 100000;
3547  add_property(bitmap, item);
3548  seen_chrm = TRUE;
3549  GdipFree(item);
3550  }
3551  }
3552  }
3553 
3554  IWICMetadataReader_Release(reader);
3555  }
3556  }
3557  }
3558  IWICMetadataBlockReader_Release(block_reader);
3559  }
3560 
3561  IWICBitmapFrameDecode_Release(frame);
3562 }
3563 
3565 {
3567  HRESULT hr;
3568 
3569  TRACE("%p,%s\n", stream, wine_dbgstr_guid(container));
3570 
3571  hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
3572  if (FAILED(hr)) return hresult_to_status(hr);
3573  hr = IWICImagingFactory_CreateDecoder(factory, container, NULL, decoder);
3574  IWICImagingFactory_Release(factory);
3575  if (FAILED(hr)) return hresult_to_status(hr);
3576 
3577  hr = IWICBitmapDecoder_Initialize(*decoder, stream, WICDecodeMetadataCacheOnLoad);
3578  if (FAILED(hr)) return hresult_to_status(hr);
3579  return Ok;
3580 }
3581 
3583 
3584 static GpStatus decode_frame_wic(IWICBitmapDecoder *decoder, BOOL force_conversion,
3585  UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
3586 {
3587  GpStatus status=Ok;
3588  GpBitmap *bitmap;
3589  HRESULT hr;
3590  IWICBitmapFrameDecode *frame;
3592  IWICMetadataBlockReader *block_reader;
3597  int i;
3598  UINT width, height, frame_count;
3599  BitmapData lockeddata;
3600  WICRect wrc;
3601 
3602  TRACE("%p,%u,%p\n", decoder, active_frame, image);
3603 
3604  IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3605  hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
3606  if (SUCCEEDED(hr)) /* got frame */
3607  {
3608  hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
3609 
3610  if (SUCCEEDED(hr))
3611  {
3612  if (!force_conversion)
3613  {
3614  for (i=0; pixel_formats[i].wic_format; i++)
3615  {
3616  if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format))
3617  {
3618  source = (IWICBitmapSource*)frame;
3619  IWICBitmapSource_AddRef(source);
3620  gdip_format = pixel_formats[i].gdip_format;
3621  palette_type = pixel_formats[i].palette_type;
3622  break;
3623  }
3624  }
3625  }
3626  if (!source)
3627  {
3628  /* unknown format; fall back on 32bppARGB */
3629  hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
3630  gdip_format = PixelFormat32bppARGB;
3631  }
3632  TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format);
3633  }
3634 
3635  if (SUCCEEDED(hr)) /* got source */
3636  {
3637  hr = IWICBitmapSource_GetSize(source, &width, &height);
3638 
3639  if (SUCCEEDED(hr))
3640  status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
3641  NULL, &bitmap);
3642 
3643  if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
3644  {
3645  status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
3646  gdip_format, &lockeddata);
3647  if (status == Ok) /* locked bitmap */
3648  {
3649  wrc.X = 0;
3650  wrc.Width = width;
3651  wrc.Height = 1;
3652  for (i=0; i<height; i++)
3653  {
3654  wrc.Y = i;
3655  hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
3656  abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
3657  if (FAILED(hr)) break;
3658  }
3659 
3660  GdipBitmapUnlockBits(bitmap, &lockeddata);
3661  }
3662 
3663  if (SUCCEEDED(hr) && status == Ok)
3664  *image = &bitmap->image;
3665  else
3666  {
3667  *image = NULL;
3668  GdipDisposeImage(&bitmap->image);
3669  }
3670 
3671  if (SUCCEEDED(hr) && status == Ok)
3672  {
3673  double dpix, dpiy;
3674  hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy);
3675  if (SUCCEEDED(hr))
3676  {
3677  bitmap->image.xres = dpix;
3678  bitmap->image.yres = dpiy;
3679  }
3680  hr = S_OK;
3681  }
3682  }
3683 
3684  IWICBitmapSource_Release(source);
3685  }
3686 
3687  if (SUCCEEDED(hr)) {
3688  bitmap->metadata_reader = NULL;
3689 
3690  if (metadata_reader)
3691  metadata_reader(bitmap, decoder, active_frame);
3692  else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK)
3693  {
3694  UINT block_count = 0;
3695  if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count)
3696  IWICMetadataBlockReader_GetReaderByIndex(block_reader, 0, &bitmap->metadata_reader);
3697  IWICMetadataBlockReader_Release(block_reader);
3698  }
3699 
3700  palette = get_palette(frame, palette_type);
3701  IWICBitmapFrameDecode_Release(frame);
3702  }
3703  }
3704 
3705  if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
3706 
3707  if (status == Ok)
3708  {
3709  /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
3711  if (IsEqualGUID(&wic_format, &GUID_WICPixelFormat2bppGray) ||
3712  IsEqualGUID(&wic_format, &GUID_WICPixelFormat4bppGray) ||
3713  IsEqualGUID(&wic_format, &GUID_WICPixelFormat8bppGray) ||
3714  IsEqualGUID(&wic_format, &GUID_WICPixelFormat16bppGray))
3716  else
3717  bitmap->image.flags |= ImageFlagsColorSpaceRGB;
3718  bitmap->image.frame_count = frame_count;
3719  bitmap->image.current_frame = active_frame;
3720  bitmap->image.decoder = decoder;
3721  IWICBitmapDecoder_AddRef(decoder);
3722  if (palette)
3723  {
3724  heap_free(bitmap->image.palette);
3725  bitmap->image.palette = palette;
3726  }
3727  else
3728  {
3729  if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite))
3730  bitmap->image.palette->Flags = 0;
3731  }
3732  TRACE("=> %p\n", *image);
3733  }
3734 
3735  return status;
3736 }
3737 
3739  metadata_reader_func metadata_reader, GpImage **image)
3740 {
3741  IWICBitmapDecoder *decoder;
3742  GpStatus status;
3743 
3744  status = initialize_decoder_wic(stream, container, &decoder);
3745  if(status != Ok)
3746  return status;
3747 
3748  status = decode_frame_wic(decoder, FALSE, 0, metadata_reader, image);
3749  IWICBitmapDecoder_Release(decoder);
3750  return status;
3751 }
3752 
3754 {
3755  GpImage *new_image;
3756  GpStatus status;
3757 
3758  status = decode_frame_wic(image->decoder, FALSE, active_frame, NULL, &new_image);
3759  if(status != Ok)
3760  return status;
3761 
3762  new_image->busy = image->busy;
3763  memcpy(&new_image->format, &image->format, sizeof(GUID));
3764  free_image_data(image);
3765  if (image->type == ImageTypeBitmap)
3766  *(GpBitmap *)image = *(GpBitmap *)new_image;
3767  else if (image->type == ImageTypeMetafile)
3768  *(GpMetafile *)image = *(GpMetafile *)new_image;
3769  new_image->type = ~0;
3770  heap_free(new_image);
3771  return Ok;
3772 }
3773 
3775  UINT *left, UINT *top, UINT *width, UINT *height)
3776 {
3777  static const WCHAR leftW[] = {'L','e','f','t',0};
3778  static const WCHAR topW[] = {'T','o','p',0};
3779 
3780  *left = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, leftW);
3781  *top = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, topW);
3782 
3783  return IWICBitmapFrameDecode_GetSize(frame, width, height);
3784 }
3785 
3787 {
3788  UINT i, j, left, top, width, height;
3790  BYTE *new_bits;
3791  HRESULT hr;
3792 
3793  hr = get_gif_frame_rect(frame, &left, &top, &width, &height);
3794  if(FAILED(hr))
3795  return hr;
3796 
3797  hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
3798  if(FAILED(hr))
3799  return hr;
3800 
3801  new_bits = heap_alloc_zero(width*height*4);
3802  if(!new_bits)
3803  return E_OUTOFMEMORY;
3804 
3805  hr = IWICBitmapSource_CopyPixels(source, NULL, width*4, width*height*4, new_bits);
3806  IWICBitmapSource_Release(source);
3807  if(FAILED(hr)) {
3808  heap_free(new_bits);
3809  return hr;
3810  }
3811 
3812  for(i=0; i<height && i+top<bitmap->height; i++) {
3813  for(j=0; j<width && j+left<bitmap->width; j++) {
3814  DWORD *src = (DWORD*)(new_bits+i*width*4+j*4);
3815  DWORD *dst = (DWORD*)(bitmap->bits+(i+top)*bitmap->stride+(j+left)*4);
3816 
3817  if(first_frame || *src>>24 != 0)
3818  *dst = *src;
3819  }
3820  }
3821  heap_free(new_bits);
3822  return hr;
3823 }
3824 
3826 {
3827  BYTE bgcolor_idx = 0;
3828  UINT i;
3829 
3830  for(i=0; i<bitmap->prop_count; i++) {
3831  if(bitmap->prop_item[i].id == PropertyTagIndexBackground) {
3832  bgcolor_idx = *(BYTE*)bitmap->prop_item[i].value;
3833  break;
3834  }
3835  }
3836 
3837  for(i=0; i<bitmap->prop_count; i++) {
3838  if(bitmap->prop_item[i].id == PropertyTagIndexTransparent) {
3839  BYTE transparent_idx;
3840  transparent_idx = *(BYTE*)bitmap->prop_item[i].value;
3841 
3842  if(transparent_idx == bgcolor_idx)
3843  return 0;
3844  }
3845  }
3846 
3847  for(i=0; i<bitmap->prop_count; i++) {
3848  if(bitmap->prop_item[i].id == PropertyTagGlobalPalette) {
3849  if(bitmap->prop_item[i].length/3 > bgcolor_idx) {
3850  BYTE *color = ((BYTE*)bitmap->prop_item[i].value)+bgcolor_idx*3;
3851  return color[2] + (color[1]<<8) + (color[0]<<16) + (0xffu<<24);
3852  }
3853  break;
3854  }
3855  }
3856 
3857  FIXME("can't get gif background color\n");
3858  return 0xffffffff;
3859 }
3860 
3862 {
3863  static const WCHAR disposalW[] = {'D','i','s','p','o','s','a','l',0};
3864 
3865  GpBitmap *bitmap = (GpBitmap*)image;
3866  IWICBitmapFrameDecode *frame;
3867  int cur_frame=0, disposal;
3868  BOOL bgcolor_set = FALSE;
3869  DWORD bgcolor = 0;
3870  HRESULT hr;
3871 
3872  if(active_frame > image->current_frame) {
3873  hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, image->current_frame, &frame);
3874  if(FAILED(hr))
3875  return hresult_to_status(hr);
3876  disposal = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, disposalW);
3877  IWICBitmapFrameDecode_Release(frame);
3878 
3879  if(disposal == GIF_DISPOSE_RESTORE_TO_BKGND)
3880  cur_frame = image->current_frame;
3881  else if(disposal != GIF_DISPOSE_RESTORE_TO_PREV)
3882  cur_frame = image->current_frame+1;
3883  }
3884 
3885  while(cur_frame != active_frame) {
3886  hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, cur_frame, &frame);
3887  if(FAILED(hr))
3888  return hresult_to_status(hr);
3889  disposal = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, disposalW);
3890 
3891  if(disposal==GIF_DISPOSE_UNSPECIFIED || disposal==GIF_DISPOSE_DO_NOT_DISPOSE) {
3892  hr = blit_gif_frame(bitmap, frame, cur_frame==0);
3893  if(FAILED(hr))
3894  return hresult_to_status(hr);
3895  }else if(disposal == GIF_DISPOSE_RESTORE_TO_BKGND) {
3896  UINT left, top, width, height, i, j;
3897 
3898  if(!bgcolor_set) {
3899  bgcolor = get_gif_background_color(bitmap);
3900  bgcolor_set = TRUE;
3901  }
3902 
3903  hr = get_gif_frame_rect(frame, &left, &top, &width, &height);
3904  if(FAILED(hr))
3905  return hresult_to_status(hr);
3906  for(i=top; i<top+height && i<bitmap->height; i++) {
3907  DWORD *bits = (DWORD*)(bitmap->bits+i*bitmap->stride);
3908  for(j=left; j<left+width && j<bitmap->width; j++)
3909  bits[j] = bgcolor;
3910  }
3911  }
3912 
3913  IWICBitmapFrameDecode_Release(frame);
3914  cur_frame++;
3915  }
3916 
3917  hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, active_frame, &frame);
3918  if(FAILED(hr))
3919  return hresult_to_status(hr);
3920 
3921  hr = blit_gif_frame(bitmap, frame, cur_frame==0);
3922  IWICBitmapFrameDecode_Release(frame);
3923  if(FAILED(hr))
3924  return hresult_to_status(hr);
3925 
3926  image->current_frame = active_frame;
3927  return Ok;
3928 }
3929 
3931 {
3932  return decode_image_wic(stream, &GUID_ContainerFormatIco, NULL, image);
3933 }
3934 
3936 {
3937  GpStatus status;
3938  GpBitmap* bitmap;
3939 
3940  status = decode_image_wic(stream, &GUID_ContainerFormatBmp, NULL, image);
3941 
3942  bitmap = (GpBitmap*)*image;
3943 
3944  if (status == Ok && bitmap->format == PixelFormat32bppARGB)
3945  {
3946  /* WIC supports bmp files with alpha, but gdiplus does not */
3947  bitmap->format = PixelFormat32bppRGB;
3948  }
3949 
3950  return status;
3951 }
3952 
3954 {
3955  return decode_image_wic(stream, &GUID_ContainerFormatJpeg, NULL, image);
3956 }
3957 
3959 {
3960  IWICBitmapDecoder *decoder;
3961  IWICBitmapFrameDecode *frame;
3962  GpStatus status;
3963  HRESULT hr;
3964  GUID format;
3965  BOOL force_conversion = FALSE;
3966 
3967  status = initialize_decoder_wic(stream, &GUID_ContainerFormatPng, &decoder);
3968  if (status != Ok)
3969  return status;
3970 
3971  hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
3972  if (hr == S_OK)
3973  {
3974  hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &format);
3975  if (hr == S_OK)
3976  {
3977  if (IsEqualGUID(&format, &GUID_WICPixelFormat8bppGray))
3978  force_conversion = TRUE;
3979  status = decode_frame_wic(decoder, force_conversion, 0, png_metadata_reader, image);
3980  }
3981  else
3982  status = hresult_to_status(hr);
3983 
3984  IWICBitmapFrameDecode_Release(frame);
3985  }
3986  else
3987  status = hresult_to_status(hr);
3988 
3989  IWICBitmapDecoder_Release(decoder);
3990  return status;
3991 }
3992 
3994 {
3995  IWICBitmapDecoder *decoder;
3996  UINT frame_count;
3997  GpStatus status;
3998  HRESULT hr;
3999 
4000  status = initialize_decoder_wic(stream, &GUID_ContainerFormatGif, &decoder);
4001  if(status != Ok)
4002  return status;
4003 
4004  hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
4005  if(FAILED(hr))
4006  return hresult_to_status(hr);
4007 
4008  status = decode_frame_wic(decoder, frame_count > 1, 0, gif_metadata_reader, image);
4009  IWICBitmapDecoder_Release(decoder);
4010  if(status != Ok)
4011  return status;
4012 
4013  if(frame_count > 1) {
4014  heap_free((*image)->palette);
4015  (*image)->palette = NULL;
4016  }
4017  return Ok;
4018 }
4019 
4021 {
4022  return decode_image_wic(stream, &GUID_ContainerFormatTiff, NULL, image);
4023 }
4024 
4026 {
4028  BOOL is_placeable = FALSE;
4030  GpStatus status;
4031  METAHEADER mh;
4032  HMETAFILE hmf;
4033  HRESULT hr;
4034  UINT size;
4035  void *buf;
4036 
4037  hr = IStream_Read(stream, &mh, sizeof(mh), &size);
4038  if (hr != S_OK || size != sizeof(mh))
4039  return GenericError;
4040 
4041  if (((WmfPlaceableFileHeader *)&mh)->Key == WMF_PLACEABLE_KEY)
4042  {
4043  seek.QuadPart = 0;
4044  hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
4045  if (FAILED(hr)) return hresult_to_status(hr);
4046 
4047  hr = IStream_Read(stream, &pfh, sizeof(pfh), &size);
4048  if (hr != S_OK || size != sizeof(pfh))
4049  return GenericError;
4050 
4051  hr = IStream_Read(stream, &mh, sizeof(mh), &size);
4052  if (hr != S_OK || size != sizeof(mh))
4053  return GenericError;
4054 
4055  is_placeable = TRUE;
4056  }
4057 
4058  seek.QuadPart = is_placeable ? sizeof(pfh) : 0;
4059  hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
4060  if (FAILED(hr)) return hresult_to_status(hr);
4061 
4062  buf = heap_alloc(mh.mtSize * 2);
4063  if (!buf) return OutOfMemory;
4064 
4065  hr = IStream_Read(stream, buf, mh.mtSize * 2, &size);
4066  if (hr != S_OK || size != mh.mtSize * 2)
4067  {
4068  heap_free(buf);
4069  return GenericError;
4070  }
4071 
4072  hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf);
4073  heap_free(buf);
4074  if (!hmf)
4075  return GenericError;
4076 
4077  status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile);
4078  if (status != Ok)
4079  DeleteMetaFile(hmf);
4080  return status;
4081 }
4082 
4084 {
4086  GpStatus status;
4087 
4088  TRACE("%p %p\n", stream, image);
4089 
4090  if (!stream || !image)
4091  return InvalidParameter;
4092 
4093  status = load_wmf(stream, &metafile);
4094  if (status != Ok)
4095  {
4096  TRACE("Could not load metafile\n");
4097  return status;
4098  }
4099 
4100  *image = (GpImage *)metafile;
4101  TRACE("<-- %p\n", *image);
4102 
4103  return Ok;
4104 }
4105 
4107 {
4109  ENHMETAHEADER emh;
4110  HENHMETAFILE hemf;
4111  GpStatus status;
4112  HRESULT hr;
4113  UINT size;
4114  void *buf;
4115 
4116  hr = IStream_Read(stream, &emh, sizeof(emh), &size);
4117  if (hr != S_OK || size != sizeof(emh) || emh.dSignature != ENHMETA_SIGNATURE)
4118  return GenericError;
4119 
4120  seek.QuadPart = 0;
4121  hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
4122  if (FAILED(hr)) return hresult_to_status(hr);
4123 
4124  buf = heap_alloc(emh.nBytes);
4125  if (!buf) return OutOfMemory;
4126 
4127  hr = IStream_Read(stream, buf, emh.nBytes, &size);
4128  if (hr != S_OK || size != emh.nBytes)
4129  {
4130  heap_free(buf);
4131  return GenericError;
4132  }
4133 
4134  hemf = SetEnhMetaFileBits(emh.nBytes, buf);
4135  heap_free(buf);
4136  if (!hemf)
4137  return GenericError;
4138 
4139  status = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
4140  if (status != Ok)
4141  DeleteEnhMetaFile(hemf);
4142  return status;
4143 }
4144 
4146 {
4148  GpStatus status;
4149 
4150  TRACE("%p %p\n", stream, image);
4151 
4152  if (!stream || !image)
4153  return InvalidParameter;
4154 
4155  status = load_emf(stream, &metafile);
4156  if (status != Ok)
4157  {
4158  TRACE("Could not load metafile\n");
4159  return status;
4160  }
4161 
4162  *image = (GpImage *)metafile;
4163  TRACE("<-- %p\n", *image);
4164 
4165  return Ok;
4166 }
4167 
4170 
4172 
4173 typedef GpStatus (*select_image_func)(GpImage *image, UINT active_frame);
4174 
4175 typedef struct image_codec {
4180 } image_codec;
4181 
4182 typedef enum {
4192 } ImageFormat;
4193 
4194 static const struct image_codec codecs[NUM_CODECS];
4195 
4197 {
4198  BYTE signature[8];
4199  const BYTE *pattern, *mask;
4201  HRESULT hr;
4202  UINT bytesread;
4203  int i;
4204  DWORD j, sig;
4205 
4206  /* seek to the start of the stream */
4207  seek.QuadPart = 0;
4208  hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
4209  if (FAILED(hr)) return hresult_to_status(hr);
4210 
4211  /* read the first 8 bytes */
4212  /* FIXME: This assumes all codecs have signatures <= 8 bytes in length */
4213  hr = IStream_Read(stream, signature, 8, &bytesread);
4214  if (FAILED(hr)) return hresult_to_status(hr);
4215  if (hr == S_FALSE || bytesread == 0) return GenericError;
4216 
4217  for (i = 0; i < NUM_CODECS; i++) {
4218  if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
4219  bytesread >= codecs[i].info.SigSize)
4220  {
4221  for (sig=0; sig<codecs[i].info.SigCount; sig++)
4222  {
4223  pattern = &codecs[i].info.SigPattern[codecs[i].info.SigSize*sig];
4224  mask = &codecs[i].info.SigMask[codecs[i].info.SigSize*sig];
4225  for (j=0; j<codecs[i].info.SigSize; j++)
4226  if ((signature[j] & mask[j]) != pattern[j])
4227  break;
4228  if (j == codecs[i].info.SigSize)
4229  {
4230  *result = &codecs[i];
4231  return Ok;
4232  }
4233  }
4234  }
4235  }
4236 
4237  TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
4238  signature[0],signature[1],signature[2],signature[3],
4239  signature[4],signature[5],signature[6],signature[7]);
4240 
4241  return GenericError;
4242 }
4243 
4245 {
4246  int i;
4247 
4248  for (i = 0; i < NUM_CODECS; i++) {
4249  if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
4250  IsEqualIID(&codecs[i].info.FormatID, &image->format))
4251  {
4252  *result = &codecs[i];
4253  return Ok;
4254  }
4255  }
4256 
4257  TRACE("no match for format: %s\n", wine_dbgstr_guid(&image->format));
4258  return GenericError;
4259 }
4260 
4262  UINT frame)
4263 {
4264  GpStatus stat;
4265  const struct image_codec *codec = NULL;
4266  BOOL unlock;
4267 
4268  TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
4269 
4270  if (!image || !dimensionID)
4271  return InvalidParameter;
4272  if(!image_lock(image, &unlock))
4273  return ObjectBusy;
4274 
4275  if (frame >= image->frame_count)
4276  {
4277  WARN("requested frame %u, but image has only %u\n", frame, image->frame_count);
4278  image_unlock(image, unlock);
4279  return InvalidParameter;
4280  }
4281 
4282  if (image->type != ImageTypeBitmap && image->type != ImageTypeMetafile)
4283  {
4284  WARN("invalid image type %d\n", image->type);
4285  image_unlock(image, unlock);
4286  return InvalidParameter;
4287  }
4288 
4289  if (image->current_frame == frame)
4290  {
4291  image_unlock(image, unlock);
4292  return Ok;
4293  }
4294 
4295  if (!image->decoder)
4296  {
4297  TRACE("image doesn't have an associated decoder\n");
4298  image_unlock(image, unlock);
4299  return Ok;
4300  }
4301 
4302  /* choose an appropriate image decoder */
4303  stat = get_decoder_info_from_image(image, &codec);
4304  if (stat != Ok)
4305  {
4306  WARN("can't find decoder info\n");
4307  image_unlock(image, unlock);
4308  return stat;
4309  }
4310 
4311  stat = codec->select_func(image, frame);
4312  image_unlock(image, unlock);
4313  return stat;
4314 }
4315 
4317 {
4318  GpStatus stat;
4320  HRESULT hr;
4321  const struct image_codec *codec=NULL;
4322 
4323  /* choose an appropriate image decoder */
4324  stat = get_decoder_info(stream, &codec);
4325  if (stat != Ok) return stat;
4326 
4327  /* seek to the start of the stream */
4328  seek.QuadPart = 0;
4329  hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
4330  if (FAILED(hr)) return hresult_to_status(hr);
4331 
4332  /* call on the image decoder to do the real work */
4333  stat = codec->decode_func(stream, image);
4334 
4335  /* take note of the original data format */
4336  if (stat == Ok)
4337  {
4338  memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
4339  return Ok;
4340  }
4341 
4342  return stat;
4343 }
4344 
4345 /* FIXME: no ICM */
4347 {
4348  TRACE("%p %p\n", stream, image);
4349 
4350  return GdipLoadImageFromStream(stream, image);
4351 }
4352 
4354 {
4355  static int calls;
4356 
4357  TRACE("(%p,%u)\n", image, propId);
4358 
4359  if(!image)
4360  return InvalidParameter;
4361 
4362  if(!(calls++))
4363  FIXME("not implemented\n");
4364 
4365  return NotImplemented;
4366 }
4367 
4369 {
4370  static int calls;
4371 
4372  if (!image || !item) return InvalidParameter;
4373 
4374  TRACE("(%p,%p:%#x,%u,%u,%p)\n", image, item, item->id, item->type, item->length, item->value);
4375 
4376  if(!(calls++))
4377  FIXME("not implemented\n");
4378 
4379  return Ok;
4380 }
4381 
4383  GDIPCONST CLSID *clsidEncoder,
4384  GDIPCONST EncoderParameters *encoderParams)
4385 {
4386  GpStatus stat;
4387  IStream *stream;
4388 
4389  TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
4390 
4391  if (!image || !filename|| !clsidEncoder)
4392  return InvalidParameter;
4393 
4394  stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
4395  if (stat != Ok)
4396  return GenericError;
4397 
4398  stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
4399 
4400  IStream_Release(stream);
4401  return stat;
4402 }
4403 
4404 /*************************************************************************
4405  * Encoding functions -
4406  * These functions encode an image in different image file formats.
4407  */
4408 
4411 {
4412  GpStatus stat;
4413  GpBitmap *bitmap;
4415  IWICBitmapEncoder *encoder;
4416  IWICBitmapFrameEncode *frameencode;
4417  IPropertyBag2 *encoderoptions;
4418  HRESULT hr;
4419