ReactOS  0.4.12-dev-14-gd0c8636
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 <stdarg.h>
21 #include <assert.h>
22 
23 #define NONAMELESSUNION
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "wingdi.h"
29 
30 #define COBJMACROS
31 #include "objbase.h"
32 #include "olectl.h"
33 #include "ole2.h"
34 
35 #include "initguid.h"
36 #include "wincodec.h"
37 #include "gdiplus.h"
38 #include "gdiplus_private.h"
39 #include "wine/debug.h"
40 
42 
44 
45 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
46 #define WMF_PLACEABLE_KEY 0x9ac6cdd7
47 
48 static const struct
49 {
52  /* predefined palette type to use for pixel format conversions */
54 } pixel_formats[] =
55 {
56  { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
57  { &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
58  { &GUID_WICPixelFormat4bppIndexed, PixelFormat4bppIndexed, WICBitmapPaletteTypeFixedHalftone8 },
59  { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 },
60  { &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedHalftone256 },
61  { &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555, WICBitmapPaletteTypeFixedHalftone256 },
62  { &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
63  { &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
64  { &GUID_WICPixelFormat48bppRGB, PixelFormat48bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
65  { &GUID_WICPixelFormat32bppBGRA, PixelFormat32bppARGB, WICBitmapPaletteTypeFixedHalftone256 },
66  { &GUID_WICPixelFormat32bppPBGRA, PixelFormat32bppPARGB, WICBitmapPaletteTypeFixedHalftone256 },
67  { &GUID_WICPixelFormat32bppCMYK, PixelFormat32bppCMYK, WICBitmapPaletteTypeFixedHalftone256 },
68  { &GUID_WICPixelFormat32bppGrayFloat, PixelFormat32bppARGB, WICBitmapPaletteTypeFixedGray256 },
69  { &GUID_WICPixelFormat64bppCMYK, PixelFormat48bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
70  { &GUID_WICPixelFormat64bppRGBA, PixelFormat48bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
71  { NULL }
72 };
73 
75 {
76  HRESULT hr;
78  IWICPalette *wic_palette;
80 
81  hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
82  if (hr != S_OK) return NULL;
83 
84  hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
85  if (hr == S_OK)
86  {
88  if (frame)
89  hr = IWICBitmapFrameDecode_CopyPalette(frame, wic_palette);
90  if (hr != S_OK)
91  {
92  TRACE("using predefined palette %#x\n", palette_type);
93  hr = IWICPalette_InitializePredefined(wic_palette, palette_type, FALSE);
94  }
95  if (hr == S_OK)
96  {
98  BOOL alpha;
99  UINT count;
100 
101  IWICPalette_GetColorCount(wic_palette, &count);
102  palette = heap_alloc(2 * sizeof(UINT) + count * sizeof(ARGB));
103  IWICPalette_GetColors(wic_palette, count, palette->Entries, &palette->Count);
104 
105  IWICPalette_GetType(wic_palette, &type);
106  switch(type) {
110  palette->Flags = PaletteFlagsGrayScale;
111  break;
119  palette->Flags = PaletteFlagsHalftone;
120  break;
121  default:
122  palette->Flags = 0;
123  }
124  IWICPalette_HasAlpha(wic_palette, &alpha);
125  if(alpha)
126  palette->Flags |= PaletteFlagsHasAlpha;
127  }
128  IWICPalette_Release(wic_palette);
129  }
130  IWICImagingFactory_Release(factory);
131  return palette;
132 }
133 
135  RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
136 {
137  FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
138  /*
139  * Note: According to Jose Roca's GDI+ docs, this function is not
140  * implemented in Windows's GDI+.
141  */
142  return NotImplemented;
143 }
144 
146  INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
147  GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
148 {
149  FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
150  /*
151  * Note: According to Jose Roca's GDI+ docs, this function is not
152  * implemented in Windows's GDI+.
153  */
154  return NotImplemented;
155 }
156 
157 static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
158 {
159  *index = (row[x/8]>>(7-x%8)) & 1;
160 }
161 
162 static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x)
163 {
164  if (x & 1)
165  *index = row[x/2]&0xf;
166  else
167  *index = row[x/2]>>4;
168 }
169 
170 static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
171 {
172  *index = row[x];
173 }
174 
175 static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
176  const BYTE *row, UINT x)
177 {
178  *r = *g = *b = row[x*2+1];
179  *a = 255;
180 }
181 
182 static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
183  const BYTE *row, UINT x)
184 {
185  WORD pixel = *((const WORD*)(row)+x);
186  *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
187  *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
188  *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
189  *a = 255;
190 }
191 
192 static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
193  const BYTE *row, UINT x)
194 {
195  WORD pixel = *((const WORD*)(row)+x);
196  *r = (pixel>>8&0xf8)|(pixel>>13&0x7);
197  *g = (pixel>>3&0xfc)|(pixel>>9&0x3);
198  *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
199  *a = 255;
200 }
201 
202 static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
203  const BYTE *row, UINT x)
204 {
205  WORD pixel = *((const WORD*)(row)+x);
206  *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
207  *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
208  *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
209  if ((pixel&0x8000) == 0x8000)
210  *a = 255;
211  else
212  *a = 0;
213 }
214 
215 static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
216  const BYTE *row, UINT x)
217 {
218  *r = row[x*3+2];
219  *g = row[x*3+1];
220  *b = row[x*3];
221  *a = 255;
222 }
223 
224 static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
225  const BYTE *row, UINT x)
226 {
227  *r = row[x*4+2];
228  *g = row[x*4+1];
229  *b = row[x*4];
230  *a = 255;
231 }
232 
233 static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
234  const BYTE *row, UINT x)
235 {
236  *r = row[x*4+2];
237  *g = row[x*4+1];
238  *b = row[x*4];
239  *a = row[x*4+3];
240 }
241 
242 static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
243  const BYTE *row, UINT x)
244 {
245  *a = row[x*4+3];
246  if (*a == 0)
247  *r = *g = *b = 0;
248  else
249  {
250  *r = row[x*4+2] * 255 / *a;
251  *g = row[x*4+1] * 255 / *a;
252  *b = row[x*4] * 255 / *a;
253  }
254 }
255 
256 static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
257  const BYTE *row, UINT x)
258 {
259  *r = row[x*6+5];
260  *g = row[x*6+3];
261  *b = row[x*6+1];
262  *a = 255;
263 }
264 
265 static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
266  const BYTE *row, UINT x)
267 {
268  *r = row[x*8+5];
269  *g = row[x*8+3];
270  *b = row[x*8+1];
271  *a = row[x*8+7];
272 }
273 
274 static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
275  const BYTE *row, UINT x)
276 {
277  *a = row[x*8+7];
278  if (*a == 0)
279  *r = *g = *b = 0;
280  else
281  {
282  *r = row[x*8+5] * 255 / *a;
283  *g = row[x*8+3] * 255 / *a;
284  *b = row[x*8+1] * 255 / *a;
285  }
286 }
287 
289  ARGB *color)
290 {
291  BYTE r, g, b, a;
292  BYTE index;
293  BYTE *row;
294 
295  if(!bitmap || !color ||
296  x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
297  return InvalidParameter;
298 
299  row = bitmap->bits+bitmap->stride*y;
300 
301  switch (bitmap->format)
302  {
304  getpixel_1bppIndexed(&index,row,x);
305  break;
307  getpixel_4bppIndexed(&index,row,x);
308  break;
310  getpixel_8bppIndexed(&index,row,x);
311  break;
313  getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
314  break;
316  getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
317  break;
319  getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
320  break;
322  getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
323  break;
324  case PixelFormat24bppRGB:
325  getpixel_24bppRGB(&r,&g,&b,&a,row,x);
326  break;
327  case PixelFormat32bppRGB:
328  getpixel_32bppRGB(&r,&g,&b,&a,row,x);
329  break;
331  getpixel_32bppARGB(&r,&g,&b,&a,row,x);
332  break;
334  getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
335  break;
336  case PixelFormat48bppRGB:
337  getpixel_48bppRGB(&r,&g,&b,&a,row,x);
338  break;
340  getpixel_64bppARGB(&r,&g,&b,&a,row,x);
341  break;
343  getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
344  break;
345  default:
346  FIXME("not implemented for format 0x%x\n", bitmap->format);
347  return NotImplemented;
348  }
349 
350  if (bitmap->format & PixelFormatIndexed)
351  *color = bitmap->image.palette->Entries[index];
352  else
353  *color = a<<24|r<<16|g<<8|b;
354 
355  return Ok;
356 }
357 
359 {
360  BYTE index = 0;
361  int best_distance = 0x7fff;
362  int distance;
363  UINT i;
364 
365  if (!palette) return 0;
366  /* This algorithm scans entire palette,
367  computes difference from desired color (all color components have equal weight)
368  and returns the index of color with least difference.
369 
370  Note: Maybe it could be replaced with a better algorithm for better image quality
371  and performance, though better algorithm would probably need some pre-built lookup
372  tables and thus may actually be slower if this method is called only few times per
373  every image.
374  */
375  for(i=0;i<palette->Count;i++) {
376  ARGB color=palette->Entries[i];
377  distance=abs(b-(color & 0xff)) + abs(g-(color>>8 & 0xff)) + abs(r-(color>>16 & 0xff)) + abs(a-(color>>24 & 0xff));
378  if (distance<best_distance) {
379  best_distance=distance;
380  index=i;
381  }
382  }
383  return index;
384 }
385 
386 static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
388 {
389  BYTE index = get_palette_index(r,g,b,a,palette);
390  row[x]=index;
391 }
392 
393 static inline void setpixel_1bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
395 {
396  row[x/8] = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,palette)<<(7-x%8));
397 }
398 
399 static inline void setpixel_4bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
401 {
402  if (x & 1)
403  row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,palette);
404  else
405  row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,palette)<<4;
406 }
407 
408 static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
409  BYTE *row, UINT x)
410 {
411  *((WORD*)(row)+x) = (r+g+b)*85;
412 }
413 
414 static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
415  BYTE *row, UINT x)
416 {
417  *((WORD*)(row)+x) = (r<<7&0x7c00)|
418  (g<<2&0x03e0)|
419  (b>>3&0x001f);
420 }
421 
422 static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
423  BYTE *row, UINT x)
424 {
425  *((WORD*)(row)+x) = (r<<8&0xf800)|
426  (g<<3&0x07e0)|
427  (b>>3&0x001f);
428 }
429 
430 static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
431  BYTE *row, UINT x)
432 {
433  *((WORD*)(row)+x) = (a<<8&0x8000)|
434  (r<<7&0x7c00)|
435  (g<<2&0x03e0)|
436  (b>>3&0x001f);
437 }
438 
439 static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
440  BYTE *row, UINT x)
441 {
442  row[x*3+2] = r;
443  row[x*3+1] = g;
444  row[x*3] = b;
445 }
446 
447 static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
448  BYTE *row, UINT x)
449 {
450  *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
451 }
452 
453 static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
454  BYTE *row, UINT x)
455 {
456  *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
457 }
458 
459 static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
460  BYTE *row, UINT x)
461 {
462  r = r * a / 255;
463  g = g * a / 255;
464  b = b * a / 255;
465  *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
466 }
467 
468 static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
469  BYTE *row, UINT x)
470 {
471  row[x*6+5] = row[x*6+4] = r;
472  row[x*6+3] = row[x*6+2] = g;
473  row[x*6+1] = row[x*6] = b;
474 }
475 
476 static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
477  BYTE *row, UINT x)
478 {
479  UINT64 a64=a, r64=r, g64=g, b64=b;
480  *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
481 }
482 
483 static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
484  BYTE *row, UINT x)
485 {
486  UINT64 a64, r64, g64, b64;
487  a64 = a * 257;
488  r64 = r * a / 255;
489  g64 = g * a / 255;
490  b64 = b * a / 255;
491  *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
492 }
493 
495  ARGB color)
496 {
497  BYTE a, r, g, b;
498  BYTE *row;
499 
500  if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
501  return InvalidParameter;
502 
503  a = color>>24;
504  r = color>>16;
505  g = color>>8;
506  b = color;
507 
508  row = bitmap->bits + bitmap->stride * y;
509 
510  switch (bitmap->format)
511  {
513  setpixel_16bppGrayScale(r,g,b,a,row,x);
514  break;
516  setpixel_16bppRGB555(r,g,b,a,row,x);
517  break;
519  setpixel_16bppRGB565(r,g,b,a,row,x);
520  break;
522  setpixel_16bppARGB1555(r,g,b,a,row,x);
523  break;
524  case PixelFormat24bppRGB:
525  setpixel_24bppRGB(r,g,b,a,row,x);
526  break;
527  case PixelFormat32bppRGB:
528  setpixel_32bppRGB(r,g,b,a,row,x);
529  break;
531  setpixel_32bppARGB(r,g,b,a,row,x);
532  break;
534  setpixel_32bppPARGB(r,g,b,a,row,x);
535  break;
536  case PixelFormat48bppRGB:
537  setpixel_48bppRGB(r,g,b,a,row,x);
538  break;
540  setpixel_64bppARGB(r,g,b,a,row,x);
541  break;
543  setpixel_64bppPARGB(r,g,b,a,row,x);
544  break;
546  setpixel_8bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
547  break;
549  setpixel_4bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
550  break;
552  setpixel_1bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
553  break;
554  default:
555  FIXME("not implemented for format 0x%x\n", bitmap->format);
556  return NotImplemented;
557  }
558 
559  return Ok;
560 }
561 
563  INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
564  INT src_stride, const BYTE *src_bits, PixelFormat src_format,
566 {
567  INT x, y;
568 
569  if (src_format == dst_format ||
570  (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32))
571  {
572  UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8;
573  for (y=0; y<height; y++)
574  memcpy(dst_bits+dst_stride*y, src_bits+src_stride*y, widthbytes);
575  return Ok;
576  }
577 
578 #define convert_indexed_to_rgb(getpixel_function, setpixel_function) do { \
579  for (y=0; y<height; y++) \
580  for (x=0; x<width; x++) { \
581  BYTE index; \
582  ARGB argb; \
583  BYTE *color = (BYTE *)&argb; \
584  getpixel_function(&index, src_bits+src_stride*y, x); \
585  argb = (palette && index < palette->Count) ? palette->Entries[index] : 0; \
586  setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
587  } \
588  return Ok; \
589 } while (0);
590 
591 #define convert_rgb_to_rgb(getpixel_function, setpixel_function) do { \
592  for (y=0; y<height; y++) \
593  for (x=0; x<width; x++) { \
594  BYTE r, g, b, a; \
595  getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
596  setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x); \
597  } \
598  return Ok; \
599 } while (0);
600 
601 #define convert_rgb_to_indexed(getpixel_function, setpixel_function) do { \
602  for (y=0; y<height; y++) \
603  for (x=0; x<width; x++) { \
604  BYTE r, g, b, a; \
605  getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
606  setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x, palette); \
607  } \
608  return Ok; \
609 } while (0);
610 
611  switch (src_format)
612  {
614  switch (dst_format)
615  {
624  case PixelFormat24bppRGB:
626  case PixelFormat32bppRGB:
632  case PixelFormat48bppRGB:
636  default:
637  break;
638  }
639  break;
641  switch (dst_format)
642  {
651  case PixelFormat24bppRGB:
653  case PixelFormat32bppRGB:
659  case PixelFormat48bppRGB:
663  default:
664  break;
665  }
666  break;
668  switch (dst_format)
669  {
678  case PixelFormat24bppRGB:
680  case PixelFormat32bppRGB:
686  case PixelFormat48bppRGB:
690  default:
691  break;
692  }
693  break;
695  switch (dst_format)
696  {
707  case PixelFormat24bppRGB:
709  case PixelFormat32bppRGB:
715  case PixelFormat48bppRGB:
719  default:
720  break;
721  }
722  break;
724  switch (dst_format)
725  {
736  case PixelFormat24bppRGB:
738  case PixelFormat32bppRGB:
744  case PixelFormat48bppRGB:
748  default:
749  break;
750  }
751  break;
753  switch (dst_format)
754  {
765  case PixelFormat24bppRGB:
767  case PixelFormat32bppRGB:
773  case PixelFormat48bppRGB:
777  default:
778  break;
779  }
780  break;
782  switch (dst_format)
783  {
794  case PixelFormat24bppRGB:
796  case PixelFormat32bppRGB:
802  case PixelFormat48bppRGB:
806  default:
807  break;
808  }
809  break;
810  case PixelFormat24bppRGB:
811  switch (dst_format)
812  {
825  case PixelFormat32bppRGB:
831  case PixelFormat48bppRGB:
835  default:
836  break;
837  }
838  break;
839  case PixelFormat32bppRGB:
840  switch (dst_format)
841  {
854  case PixelFormat24bppRGB:
860  case PixelFormat48bppRGB:
864  default:
865  break;
866  }
867  break;
869  switch (dst_format)
870  {
883  case PixelFormat24bppRGB:
886  convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
887  return Ok;
888  case PixelFormat48bppRGB:
892  default:
893  break;
894  }
895  break;
897  switch (dst_format)
898  {
911  case PixelFormat24bppRGB:
913  case PixelFormat32bppRGB:
917  case PixelFormat48bppRGB:
921  default:
922  break;
923  }
924  break;
925  case PixelFormat48bppRGB:
926  switch (dst_format)
927  {
940  case PixelFormat24bppRGB:
942  case PixelFormat32bppRGB:
950  default:
951  break;
952  }
953  break;
955  switch (dst_format)
956  {
969  case PixelFormat24bppRGB:
971  case PixelFormat32bppRGB:
977  case PixelFormat48bppRGB:
979  default:
980  break;
981  }
982  break;
984  switch (dst_format)
985  {
998  case PixelFormat24bppRGB:
1000  case PixelFormat32bppRGB:
1002  case PixelFormat32bppARGB:
1004  case PixelFormat32bppPARGB:
1006  case PixelFormat48bppRGB:
1008  case PixelFormat64bppARGB:
1010  default:
1011  break;
1012  }
1013  break;
1014  default:
1015  break;
1016  }
1017 
1018 #undef convert_indexed_to_rgb
1019 #undef convert_rgb_to_rgb
1020 
1021  return NotImplemented;
1022 }
1023 
1024 /* This function returns a pointer to an array of pixels that represents the
1025  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
1026  * flags. It is correct behavior that a user who calls this function with write
1027  * privileges can write to the whole bitmap (not just the area in rect).
1028  *
1029  * FIXME: only used portion of format is bits per pixel. */
1031  UINT flags, PixelFormat format, BitmapData* lockeddata)
1032 {
1033  INT bitspp = PIXELFORMATBPP(format);
1034  GpRect act_rect; /* actual rect to be used */
1035  GpStatus stat;
1036  BOOL unlock;
1037 
1038  TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
1039 
1040  if(!lockeddata || !bitmap)
1041  return InvalidParameter;
1042  if(!image_lock(&bitmap->image, &unlock))
1043  return ObjectBusy;
1044 
1045  if(rect){
1046  if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
1047  (rect->Y + rect->Height > bitmap->height) || !flags)
1048  {
1049  image_unlock(&bitmap->image, unlock);
1050  return InvalidParameter;
1051  }
1052 
1053  act_rect = *rect;
1054  }
1055  else{
1056  act_rect.X = act_rect.Y = 0;
1057  act_rect.Width = bitmap->width;
1058  act_rect.Height = bitmap->height;
1059  }
1060 
1061  if(bitmap->lockmode)
1062  {
1063  WARN("bitmap is already locked and cannot be locked again\n");
1064  image_unlock(&bitmap->image, unlock);
1065  return WrongState;
1066  }
1067 
1068  if (bitmap->bits && bitmap->format == format && !(flags & ImageLockModeUserInputBuf))
1069  {
1070  /* no conversion is necessary; just use the bits directly */
1071  lockeddata->Width = act_rect.Width;
1072  lockeddata->Height = act_rect.Height;
1073  lockeddata->PixelFormat = format;
1074  lockeddata->Reserved = flags;
1075  lockeddata->Stride = bitmap->stride;
1076  lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
1077  bitmap->stride * act_rect.Y;
1078 
1079  bitmap->lockmode = flags | ImageLockModeRead;
1080 
1081  image_unlock(&bitmap->image, unlock);
1082  return Ok;
1083  }
1084 
1085  /* Make sure we can convert to the requested format. */
1086  if (flags & ImageLockModeRead)
1087  {
1088  stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL);
1089  if (stat == NotImplemented)
1090  {
1091  FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
1092  image_unlock(&bitmap->image, unlock);
1093  return NotImplemented;
1094  }
1095  }
1096 
1097  /* If we're opening for writing, make sure we'll be able to write back in
1098  * the original format. */
1099  if (flags & ImageLockModeWrite)
1100  {
1101  stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL);
1102  if (stat == NotImplemented)
1103  {
1104  FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
1105  image_unlock(&bitmap->image, unlock);
1106  return NotImplemented;
1107  }
1108  }
1109 
1110  lockeddata->Width = act_rect.Width;
1111  lockeddata->Height = act_rect.Height;
1112  lockeddata->PixelFormat = format;
1113  lockeddata->Reserved = flags;
1114 
1115  if(!(flags & ImageLockModeUserInputBuf))
1116  {
1117  lockeddata->Stride = (((act_rect.Width * bitspp + 7) / 8) + 3) & ~3;
1118 
1119  bitmap->bitmapbits = heap_alloc_zero(lockeddata->Stride * act_rect.Height);
1120 
1121  if (!bitmap->bitmapbits)
1122  {
1123  image_unlock(&bitmap->image, unlock);
1124  return OutOfMemory;
1125  }
1126 
1127  lockeddata->Scan0 = bitmap->bitmapbits;
1128  }
1129 
1130  if (flags & ImageLockModeRead)
1131  {
1132  static BOOL fixme = FALSE;
1133 
1134  if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
1135  {
1136  FIXME("Cannot copy rows that don't start at a whole byte.\n");
1137  fixme = TRUE;
1138  }
1139 
1140  stat = convert_pixels(act_rect.Width, act_rect.Height,
1141  lockeddata->Stride, lockeddata->Scan0, format,
1142  bitmap->stride,
1143  bitmap->bits + bitmap->stride * act_rect.Y + PIXELFORMATBPP(bitmap->format) * act_rect.X / 8,
1144  bitmap->format, bitmap->image.palette);
1145 
1146  if (stat != Ok)
1147  {
1148  heap_free(bitmap->bitmapbits);
1149  bitmap->bitmapbits = NULL;
1150  image_unlock(&bitmap->image, unlock);
1151  return stat;
1152  }
1153  }
1154 
1155  bitmap->lockmode = flags | ImageLockModeRead;
1156  bitmap->lockx = act_rect.X;
1157  bitmap->locky = act_rect.Y;
1158 
1159  image_unlock(&bitmap->image, unlock);
1160  return Ok;
1161 }
1162 
1164 {
1165  TRACE("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
1166 
1167  if (!bitmap || xdpi == 0.0 || ydpi == 0.0)
1168  return InvalidParameter;
1169 
1170  bitmap->image.xres = xdpi;
1171  bitmap->image.yres = ydpi;
1172 
1173  return Ok;
1174 }
1175 
1177  BitmapData* lockeddata)
1178 {
1179  GpStatus stat;
1180  static BOOL fixme = FALSE;
1181  BOOL unlock;
1182 
1183  TRACE("(%p,%p)\n", bitmap, lockeddata);
1184 
1185  if(!bitmap || !lockeddata)
1186  return InvalidParameter;
1187  if(!image_lock(&bitmap->image, &unlock))
1188  return ObjectBusy;
1189 
1190  if(!bitmap->lockmode)
1191  {
1192  image_unlock(&bitmap->image, unlock);
1193  return WrongState;
1194  }
1195 
1196  if(!(lockeddata->Reserved & ImageLockModeWrite)){
1197  bitmap->lockmode = 0;
1198  heap_free(bitmap->bitmapbits);
1199  bitmap->bitmapbits = NULL;
1200  image_unlock(&bitmap->image, unlock);
1201  return Ok;
1202  }
1203 
1204  if (!bitmap->bitmapbits && !(lockeddata->Reserved & ImageLockModeUserInputBuf))
1205  {
1206  /* we passed a direct reference; no need to do anything */
1207  bitmap->lockmode = 0;
1208  image_unlock(&bitmap->image, unlock);
1209  return Ok;
1210  }
1211 
1212  if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
1213  {
1214  FIXME("Cannot copy rows that don't start at a whole byte.\n");
1215  fixme = TRUE;
1216  }
1217 
1218  stat = convert_pixels(lockeddata->Width, lockeddata->Height,
1219  bitmap->stride,
1220  bitmap->bits + bitmap->stride * bitmap->locky + PIXELFORMATBPP(bitmap->format) * bitmap->lockx / 8,
1221  bitmap->format,
1222  lockeddata->Stride, lockeddata->Scan0, lockeddata->PixelFormat, NULL);
1223 
1224  if (stat != Ok)
1225  {
1226  ERR("failed to convert pixels; this should never happen\n");
1227  }
1228 
1229  heap_free(bitmap->bitmapbits);
1230  bitmap->bitmapbits = NULL;
1231  bitmap->lockmode = 0;
1232 
1233  image_unlock(&bitmap->image, unlock);
1234  return stat;
1235 }
1236 
1238  PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1239 {
1240  Rect area;
1241  GpStatus stat;
1242 
1243  TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1244 
1245  if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap ||
1246  x < 0 || y < 0 ||
1247  x + width > srcBitmap->width || y + height > srcBitmap->height)
1248  {
1249  TRACE("<-- InvalidParameter\n");
1250  return InvalidParameter;
1251  }
1252 
1253  if (format == PixelFormatDontCare)
1254  format = srcBitmap->format;
1255 
1256  area.X = gdip_round(x);
1257  area.Y = gdip_round(y);
1258  area.Width = gdip_round(width);
1259  area.Height = gdip_round(height);
1260 
1261  stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap);
1262  if (stat == Ok)
1263  {
1264  stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format,
1265  srcBitmap->stride,
1266  srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8,
1267  srcBitmap->format, srcBitmap->image.palette);
1268 
1269  if (stat == Ok && srcBitmap->image.palette)
1270  {
1271  ColorPalette *src_palette, *dst_palette;
1272 
1273  src_palette = srcBitmap->image.palette;
1274 
1275  dst_palette = heap_alloc_zero(sizeof(UINT) * 2 + sizeof(ARGB) * src_palette->Count);
1276 
1277  if (dst_palette)
1278  {
1279  dst_palette->Flags = src_palette->Flags;
1280  dst_palette->Count = src_palette->Count;
1281  memcpy(dst_palette->Entries, src_palette->Entries, sizeof(ARGB) * src_palette->Count);
1282 
1283  heap_free((*dstBitmap)->image.palette);
1284  (*dstBitmap)->image.palette = dst_palette;
1285  }
1286  else
1287  stat = OutOfMemory;
1288  }
1289 
1290  if (stat != Ok)
1291  GdipDisposeImage(&(*dstBitmap)->image);
1292  }
1293 
1294  if (stat != Ok)
1295  *dstBitmap = NULL;
1296 
1297  return stat;
1298 }
1299 
1301  PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
1302 {
1303  TRACE("(%i,%i,%i,%i,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
1304 
1305  return GdipCloneBitmapArea(x, y, width, height, format, srcBitmap, dstBitmap);
1306 }
1307 
1309 {
1310  TRACE("%p, %p\n", image, cloneImage);
1311 
1312  if (!image || !cloneImage)
1313  return InvalidParameter;
1314 
1315  if (image->type == ImageTypeBitmap)
1316  {
1317  GpBitmap *bitmap = (GpBitmap *)image;
1318 
1319  return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height,
1320  bitmap->format, bitmap, (GpBitmap **)cloneImage);
1321  }
1322  else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
1323  {
1325 
1326  metafile = (GpMetafile*)image;
1327 
1328  result = heap_alloc_zero(sizeof(*result));
1329  if (!result)
1330  return OutOfMemory;
1331 
1332  result->image.type = ImageTypeMetafile;
1333  result->image.format = image->format;
1334  result->image.flags = image->flags;
1335  result->image.frame_count = 1;
1336  result->image.xres = image->xres;
1337  result->image.yres = image->yres;
1338  result->bounds = metafile->bounds;
1339  result->unit = metafile->unit;
1340  result->metafile_type = metafile->metafile_type;
1341  result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
1342  list_init(&result->containers);
1343 
1344  if (!result->hemf)
1345  {
1346  heap_free(result);
1347  return OutOfMemory;
1348  }
1349 
1350  *cloneImage = &result->image;
1351  return Ok;
1352  }
1353  else
1354  {
1355  WARN("GpImage with no image data (metafile in wrong state?)\n");
1356  return InvalidParameter;
1357  }
1358 }
1359 
1361  GpBitmap **bitmap)
1362 {
1363  GpStatus stat;
1364  IStream *stream;
1365 
1366  TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1367 
1368  if(!filename || !bitmap)
1369  return InvalidParameter;
1370 
1371  *bitmap = NULL;
1372 
1373  stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
1374 
1375  if(stat != Ok)
1376  return stat;
1377 
1378  stat = GdipCreateBitmapFromStream(stream, bitmap);
1379 
1380  IStream_Release(stream);
1381 
1382  return stat;
1383 }
1384 
1386  VOID *bits, GpBitmap **bitmap)
1387 {
1388  DWORD height, stride;
1390 
1391  FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
1392 
1393  if (!info || !bits || !bitmap)
1394  return InvalidParameter;
1395 
1396  height = abs(info->bmiHeader.biHeight);
1397  stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
1398 
1399  if(info->bmiHeader.biHeight > 0) /* bottom-up */
1400  {
1401  bits = (BYTE*)bits + (height - 1) * stride;
1402  stride = -stride;
1403  }
1404 
1405  switch(info->bmiHeader.biBitCount) {
1406  case 1:
1407  format = PixelFormat1bppIndexed;
1408  break;
1409  case 4:
1410  format = PixelFormat4bppIndexed;
1411  break;
1412  case 8:
1413  format = PixelFormat8bppIndexed;
1414  break;
1415  case 16:
1416  format = PixelFormat16bppRGB555;
1417  break;
1418  case 24:
1419  format = PixelFormat24bppRGB;
1420  break;
1421  case 32:
1422  format = PixelFormat32bppRGB;
1423  break;
1424  default:
1425  FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
1426  *bitmap = NULL;
1427  return InvalidParameter;
1428  }
1429 
1430  return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
1431  bits, bitmap);
1432 
1433 }
1434 
1435 /* FIXME: no icm */
1437  GpBitmap **bitmap)
1438 {
1439  TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
1440 
1441  return GdipCreateBitmapFromFile(filename, bitmap);
1442 }
1443 
1445  GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
1446 {
1447  HBITMAP hbm;
1449 
1450  TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
1451 
1452  if(!lpBitmapName || !bitmap)
1453  return InvalidParameter;
1454 
1455  /* load DIB */
1456  hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
1458 
1459  if(hbm){
1460  stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
1461  DeleteObject(hbm);
1462  }
1463 
1464  return stat;
1465 }
1466 
1468 {
1469  BYTE b = (BYTE)src;
1470  BYTE g = (BYTE)(src >> 8);
1471  BYTE r = (BYTE)(src >> 16);
1472  DWORD alpha = (BYTE)(src >> 24);
1473  return ((b + ((BYTE)bkgnd * (255 - alpha) + 127) / 255) |
1474  (g + ((BYTE)(bkgnd >> 8) * (255 - alpha) + 127) / 255) << 8 |
1475  (r + ((BYTE)(bkgnd >> 16) * (255 - alpha) + 127) / 255) << 16 |
1476  (alpha << 24));
1477 }
1478 
1480  HBITMAP* hbmReturn, ARGB background)
1481 {
1482  GpStatus stat;
1483  HBITMAP result;
1484  UINT width, height;
1485  BITMAPINFOHEADER bih;
1486  LPBYTE bits;
1487  BOOL unlock;
1488 
1489  TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
1490 
1491  if (!bitmap || !hbmReturn) return InvalidParameter;
1492  if (!image_lock(&bitmap->image, &unlock)) return ObjectBusy;
1493 
1494  GdipGetImageWidth(&bitmap->image, &width);
1495  GdipGetImageHeight(&bitmap->image, &height);
1496 
1497  bih.biSize = sizeof(bih);
1498  bih.biWidth = width;
1499  bih.biHeight = height;
1500  bih.biPlanes = 1;
1501  bih.biBitCount = 32;
1502  bih.biCompression = BI_RGB;
1503  bih.biSizeImage = 0;
1504  bih.biXPelsPerMeter = 0;
1505  bih.biYPelsPerMeter = 0;
1506  bih.biClrUsed = 0;
1507  bih.biClrImportant = 0;
1508 
1509  result = CreateDIBSection(0, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1510  if (!result)
1511  {
1512  image_unlock(&bitmap->image, unlock);
1513  return GenericError;
1514  }
1515 
1516  stat = convert_pixels(width, height, -width*4,
1517  bits + (width * 4 * (height - 1)), PixelFormat32bppPARGB,
1518  bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette);
1519  if (stat != Ok)
1520  {
1521  DeleteObject(result);
1522  image_unlock(&bitmap->image, unlock);
1523  return stat;
1524  }
1525 
1526  if (background & 0xffffff)
1527  {
1528  DWORD *ptr;
1529  UINT i;
1530  for (ptr = (DWORD*)bits, i = 0; i < width * height; ptr++, i++)
1531  {
1532  if ((*ptr & 0xff000000) == 0xff000000) continue;
1533  *ptr = blend_argb_no_bkgnd_alpha(*ptr, background);
1534  }
1535  }
1536 
1537  *hbmReturn = result;
1538  image_unlock(&bitmap->image, unlock);
1539  return Ok;
1540 }
1541 
1544 {
1545  GpStatus ret;
1546 
1547  TRACE("(%d, %d, %p, %p)\n", width, height, target, bitmap);
1548 
1549  if(!target || !bitmap)
1550  return InvalidParameter;
1551 
1552  ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
1553  NULL, bitmap);
1554 
1555  if (ret == Ok)
1556  {
1557  GdipGetDpiX(target, &(*bitmap)->image.xres);
1558  GdipGetDpiY(target, &(*bitmap)->image.yres);
1559  }
1560 
1561  return ret;
1562 }
1563 
1565 {
1566  GpStatus stat;
1567  ICONINFO iinfo;
1568  BITMAP bm;
1569  int ret;
1570  UINT width, height, stride;
1571  GpRect rect;
1572  BitmapData lockeddata;
1573  HDC screendc;
1574  BOOL has_alpha;
1575  int x, y;
1576  BITMAPINFOHEADER bih;
1577  DWORD *src;
1578  BYTE *dst_row;
1579  DWORD *dst;
1580 
1581  TRACE("%p, %p\n", hicon, bitmap);
1582 
1583  if(!bitmap || !GetIconInfo(hicon, &iinfo))
1584  return InvalidParameter;
1585 
1586  /* get the size of the icon */
1587  ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
1588  if (ret == 0) {
1589  DeleteObject(iinfo.hbmColor);
1590  DeleteObject(iinfo.hbmMask);
1591  return GenericError;
1592  }
1593 
1594  width = bm.bmWidth;
1595  height = iinfo.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2;
1596  stride = width * 4;
1597 
1598  stat = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat32bppARGB, NULL, bitmap);
1599  if (stat != Ok) {
1600  DeleteObject(iinfo.hbmColor);
1601  DeleteObject(iinfo.hbmMask);
1602  return stat;
1603  }
1604 
1605  rect.X = 0;
1606  rect.Y = 0;
1607  rect.Width = width;
1608  rect.Height = height;
1609 
1610  stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
1611  if (stat != Ok) {
1612  DeleteObject(iinfo.hbmColor);
1613  DeleteObject(iinfo.hbmMask);
1614  GdipDisposeImage(&(*bitmap)->image);
1615  return stat;
1616  }
1617 
1618  bih.biSize = sizeof(bih);
1619  bih.biWidth = width;
1620  bih.biHeight = iinfo.hbmColor ? -height: -height * 2;
1621  bih.biPlanes = 1;
1622  bih.biBitCount = 32;
1623  bih.biCompression = BI_RGB;
1624  bih.biSizeImage = 0;
1625  bih.biXPelsPerMeter = 0;
1626  bih.biYPelsPerMeter = 0;
1627  bih.biClrUsed = 0;
1628  bih.biClrImportant = 0;
1629 
1630  screendc = CreateCompatibleDC(0);
1631  if (iinfo.hbmColor)
1632  {
1633  GetDIBits(screendc, iinfo.hbmColor, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1634 
1635  if (bm.bmBitsPixel == 32)
1636  {
1637  has_alpha = FALSE;
1638 
1639  /* If any pixel has a non-zero alpha, ignore hbmMask */
1640  src = (DWORD*)lockeddata.Scan0;
1641  for (x=0; x<width && !has_alpha; x++)
1642  for (y=0; y<height && !has_alpha; y++)
1643  if ((*src++ & 0xff000000) != 0)
1644  has_alpha = TRUE;
1645  }
1646  else has_alpha = FALSE;
1647  }
1648  else
1649  {
1650  GetDIBits(screendc, iinfo.hbmMask, 0, height, lockeddata.Scan0, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1651  has_alpha = FALSE;
1652  }
1653 
1654  if (!has_alpha)
1655  {
1656  if (iinfo.hbmMask)
1657  {
1658  BYTE *bits = heap_alloc(height * stride);
1659 
1660  /* read alpha data from the mask */
1661  if (iinfo.hbmColor)
1662  GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1663  else
1664  GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
1665 
1666  src = (DWORD*)bits;
1667  dst_row = lockeddata.Scan0;
1668  for (y=0; y<height; y++)
1669  {
1670  dst = (DWORD*)dst_row;
1671  for (x=0; x<height; x++)
1672  {
1673  DWORD src_value = *src++;
1674  if (src_value)
1675  *dst++ = 0;
1676  else
1677  *dst++ |= 0xff000000;
1678  }
1679  dst_row += lockeddata.Stride;
1680  }
1681 
1682  heap_free(bits);
1683  }
1684  else
1685  {
1686  /* set constant alpha of 255 */
1687  dst_row = lockeddata.Scan0;
1688  for (y=0; y<height; y++)
1689  {
1690  dst = (DWORD*)dst_row;
1691  for (x=0; x<height; x++)
1692  *dst++ |= 0xff000000;
1693  dst_row += lockeddata.Stride;
1694  }
1695  }
1696  }
1697 
1698  DeleteDC(screendc);
1699 
1700  DeleteObject(iinfo.hbmColor);
1701  DeleteObject(iinfo.hbmMask);
1702 
1703  GdipBitmapUnlockBits(*bitmap, &lockeddata);
1704 
1705  return Ok;
1706 }
1707 
1709 {
1710  static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
1711  UINT i;
1712 
1713  for (i=0; i<8 && i<count; i++)
1714  {
1715  entries[i] = 0xff000000;
1716  if (i&1) entries[i] |= 0x800000;
1717  if (i&2) entries[i] |= 0x8000;
1718  if (i&4) entries[i] |= 0x80;
1719  }
1720 
1721  if (8 < count)
1722  entries[i] = 0xffc0c0c0;
1723 
1724  for (i=9; i<16 && i<count; i++)
1725  {
1726  entries[i] = 0xff000000;
1727  if (i&1) entries[i] |= 0xff0000;
1728  if (i&2) entries[i] |= 0xff00;
1729  if (i&4) entries[i] |= 0xff;
1730  }
1731 
1732  for (i=16; i<40 && i<count; i++)
1733  {
1734  entries[i] = 0;
1735  }
1736 
1737  for (i=40; i<256 && i<count; i++)
1738  {
1739  entries[i] = 0xff000000;
1740  entries[i] |= halftone_values[(i-40)%6];
1741  entries[i] |= halftone_values[((i-40)/6)%6] << 8;
1742  entries[i] |= halftone_values[((i-40)/36)%6] << 16;
1743  }
1744 }
1745 
1747 {
1748  HDC screendc = CreateCompatibleDC(0);
1749 
1750  if (!screendc) return GenericError;
1751 
1752  *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
1753  *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
1754 
1755  DeleteDC(screendc);
1756 
1757  return Ok;
1758 }
1759 
1761  PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
1762 {
1764  INT row_size, dib_stride;
1765  BYTE *bits=NULL, *own_bits=NULL;
1766  REAL xres, yres;
1767  GpStatus stat;
1768 
1769  TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
1770 
1771  if (!bitmap) return InvalidParameter;
1772 
1773  if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
1774  *bitmap = NULL;
1775  return InvalidParameter;
1776  }
1777 
1778  if(scan0 && !stride)
1779  return InvalidParameter;
1780 
1781  stat = get_screen_resolution(&xres, &yres);
1782  if (stat != Ok) return stat;
1783 
1784  row_size = (width * PIXELFORMATBPP(format)+7) / 8;
1785  dib_stride = (row_size + 3) & ~3;
1786 
1787  if(stride == 0)
1788  stride = dib_stride;
1789 
1790  if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
1791  {
1792  char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
1793  BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
1794 
1795  pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1796  pbmi->bmiHeader.biWidth = width;
1797  pbmi->bmiHeader.biHeight = -height;
1798  pbmi->bmiHeader.biPlanes = 1;
1799  /* FIXME: use the rest of the data from format */
1800  pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
1801  pbmi->bmiHeader.biCompression = BI_RGB;
1802  pbmi->bmiHeader.biSizeImage = 0;
1803  pbmi->bmiHeader.biXPelsPerMeter = 0;
1804  pbmi->bmiHeader.biYPelsPerMeter = 0;
1805  pbmi->bmiHeader.biClrUsed = 0;
1806  pbmi->bmiHeader.biClrImportant = 0;
1807 
1808  hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1809 
1810  if (!hbitmap) return GenericError;
1811 
1812  stride = dib_stride;
1813  }
1814  else
1815  {
1816  /* Not a GDI format; don't try to make an HBITMAP. */
1817  if (scan0)
1818  bits = scan0;
1819  else
1820  {
1821  INT size = abs(stride) * height;
1822 
1823  own_bits = bits = heap_alloc_zero(size);
1824  if (!own_bits) return OutOfMemory;
1825 
1826  if (stride < 0)
1827  bits += stride * (1 - height);
1828  }
1829  }
1830 
1831  *bitmap = heap_alloc_zero(sizeof(GpBitmap));
1832  if(!*bitmap)
1833  {
1834  DeleteObject(hbitmap);
1835  heap_free(own_bits);
1836  return OutOfMemory;
1837  }
1838 
1839  (*bitmap)->image.type = ImageTypeBitmap;
1840  memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
1841  (*bitmap)->image.flags = ImageFlagsNone;
1842  (*bitmap)->image.frame_count = 1;
1843  (*bitmap)->image.current_frame = 0;
1844  (*bitmap)->image.palette = NULL;
1845  (*bitmap)->image.xres = xres;
1846  (*bitmap)->image.yres = yres;
1847  (*bitmap)->width = width;
1848  (*bitmap)->height = height;
1849  (*bitmap)->format = format;
1850  (*bitmap)->image.decoder = NULL;
1851  (*bitmap)->hbitmap = hbitmap;
1852  (*bitmap)->hdc = NULL;
1853  (*bitmap)->bits = bits;
1854  (*bitmap)->stride = stride;
1855  (*bitmap)->own_bits = own_bits;
1856  (*bitmap)->metadata_reader = NULL;
1857  (*bitmap)->prop_count = 0;
1858  (*bitmap)->prop_item = NULL;
1859 
1860  /* set format-related flags */
1862  (*bitmap)->image.flags |= ImageFlagsHasAlpha;
1863 
1864  if (format == PixelFormat1bppIndexed ||
1865  format == PixelFormat4bppIndexed ||
1866  format == PixelFormat8bppIndexed)
1867  {
1868  (*bitmap)->image.palette = heap_alloc_zero(sizeof(UINT) * 2 + sizeof(ARGB) * (1 << PIXELFORMATBPP(format)));
1869 
1870  if (!(*bitmap)->image.palette)
1871  {
1872  GdipDisposeImage(&(*bitmap)->image);
1873  *bitmap = NULL;
1874  return OutOfMemory;
1875  }
1876 
1877  (*bitmap)->image.palette->Count = 1 << PIXELFORMATBPP(format);
1878 
1879  if (format == PixelFormat1bppIndexed)
1880  {
1881  (*bitmap)->image.palette->Flags = PaletteFlagsGrayScale;
1882  (*bitmap)->image.palette->Entries[0] = 0xff000000;
1883  (*bitmap)->image.palette->Entries[1] = 0xffffffff;
1884  }
1885  else
1886  {
1887  if (format == PixelFormat8bppIndexed)
1888  (*bitmap)->image.palette->Flags = PaletteFlagsHalftone;
1889 
1890  generate_halftone_palette((*bitmap)->image.palette->Entries,
1891  (*bitmap)->image.palette->Count);
1892  }
1893  }
1894 
1895  TRACE("<-- %p\n", *bitmap);
1896 
1897  return Ok;
1898 }
1899 
1901  GpBitmap **bitmap)
1902 {
1903  GpStatus stat;
1904 
1905  TRACE("%p %p\n", stream, bitmap);
1906 
1907  stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
1908 
1909  if(stat != Ok)
1910  return stat;
1911 
1912  if((*bitmap)->image.type != ImageTypeBitmap){
1913  GdipDisposeImage(&(*bitmap)->image);
1914  *bitmap = NULL;
1915  return GenericError; /* FIXME: what error to return? */
1916  }
1917 
1918  return Ok;
1919 }
1920 
1921 /* FIXME: no icm */
1923  GpBitmap **bitmap)
1924 {
1925  TRACE("%p %p\n", stream, bitmap);
1926 
1927  return GdipCreateBitmapFromStream(stream, bitmap);
1928 }
1929 
1931  GpCachedBitmap **cachedbmp)
1932 {
1933  GpStatus stat;
1934 
1935  TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
1936 
1937  if(!bitmap || !graphics || !cachedbmp)
1938  return InvalidParameter;
1939 
1940  *cachedbmp = heap_alloc_zero(sizeof(GpCachedBitmap));
1941  if(!*cachedbmp)
1942  return OutOfMemory;
1943 
1944  stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
1945  if(stat != Ok){
1946  heap_free(*cachedbmp);
1947  return stat;
1948  }
1949 
1950  return Ok;
1951 }
1952 
1954 {
1955  GpStatus stat;
1956  BitmapData lockeddata;
1957  ULONG andstride, xorstride, bitssize;
1958  LPBYTE andbits, xorbits, androw, xorrow, srcrow;
1959  UINT x, y;
1960 
1961  TRACE("(%p, %p)\n", bitmap, hicon);
1962 
1963  if (!bitmap || !hicon)
1964  return InvalidParameter;
1965 
1966  stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead,
1967  PixelFormat32bppPARGB, &lockeddata);
1968  if (stat == Ok)
1969  {
1970  andstride = ((lockeddata.Width+31)/32)*4;
1971  xorstride = lockeddata.Width*4;
1972  bitssize = (andstride + xorstride) * lockeddata.Height;
1973 
1974  andbits = heap_alloc_zero(bitssize);
1975 
1976  if (andbits)
1977  {
1978  xorbits = andbits + andstride * lockeddata.Height;
1979 
1980  for (y=0; y<lockeddata.Height; y++)
1981  {
1982  srcrow = ((LPBYTE)lockeddata.Scan0) + lockeddata.Stride * y;
1983 
1984  androw = andbits + andstride * y;
1985  for (x=0; x<lockeddata.Width; x++)
1986  if (srcrow[3+4*x] >= 128)
1987  androw[x/8] |= 1 << (7-x%8);
1988 
1989  xorrow = xorbits + xorstride * y;
1990  memcpy(xorrow, srcrow, xorstride);
1991  }
1992 
1993  *hicon = CreateIcon(NULL, lockeddata.Width, lockeddata.Height, 1, 32,
1994  andbits, xorbits);
1995 
1996  heap_free(andbits);
1997  }
1998  else
1999  stat = OutOfMemory;
2000 
2001  GdipBitmapUnlockBits(bitmap, &lockeddata);
2002  }
2003 
2004  return stat;
2005 }
2006 
2008 {
2009  TRACE("%p\n", cachedbmp);
2010 
2011  if(!cachedbmp)
2012  return InvalidParameter;
2013 
2014  GdipDisposeImage(cachedbmp->image);
2015  heap_free(cachedbmp);
2016 
2017  return Ok;
2018 }
2019 
2021  GpCachedBitmap *cachedbmp, INT x, INT y)
2022 {
2023  TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
2024 
2025  if(!graphics || !cachedbmp)
2026  return InvalidParameter;
2027 
2028  return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
2029 }
2030 
2031 /* Internal utility function: Replace the image data of dst with that of src,
2032  * and free src. */
2033 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
2034 {
2035  assert(src->image.type == ImageTypeBitmap);
2036  assert(dst->image.type == ImageTypeBitmap);
2037 
2038  heap_free(dst->bitmapbits);
2039  heap_free(dst->own_bits);
2040  DeleteDC(dst->hdc);
2041  DeleteObject(dst->hbitmap);
2042 
2043  if (clobber_palette)
2044  {
2045  heap_free(dst->image.palette);
2046  dst->image.palette = src->image.palette;
2047  }
2048  else
2049  heap_free(src->image.palette);
2050 
2051  dst->image.xres = src->image.xres;
2052  dst->image.yres = src->image.yres;
2053  dst->width = src->width;
2054  dst->height = src->height;
2055  dst->format = src->format;
2056  dst->hbitmap = src->hbitmap;
2057  dst->hdc = src->hdc;
2058  dst->bits = src->bits;
2059  dst->stride = src->stride;
2060  dst->own_bits = src->own_bits;
2061  if (dst->metadata_reader)
2062  IWICMetadataReader_Release(dst->metadata_reader);
2063  dst->metadata_reader = src->metadata_reader;
2064  heap_free(dst->prop_item);
2065  dst->prop_item = src->prop_item;
2066  dst->prop_count = src->prop_count;
2067  if (dst->image.decoder)
2068  IWICBitmapDecoder_Release(dst->image.decoder);
2069  dst->image.decoder = src->image.decoder;
2070  dst->image.frame_count = src->image.frame_count;
2071  dst->image.current_frame = src->image.current_frame;
2072  dst->image.format = src->image.format;
2073 
2074  src->image.type = ~0;
2075  heap_free(src);
2076 }
2077 
2079 {
2080  if(!image)
2081  return InvalidParameter;
2082 
2083  if (image->type == ImageTypeBitmap)
2084  {
2085  heap_free(((GpBitmap*)image)->bitmapbits);
2086  heap_free(((GpBitmap*)image)->own_bits);
2087  DeleteDC(((GpBitmap*)image)->hdc);
2088  DeleteObject(((GpBitmap*)image)->hbitmap);
2089  if (((GpBitmap*)image)->metadata_reader)
2090  IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader);
2091  heap_free(((GpBitmap*)image)->prop_item);
2092  }
2093  else if (image->type == ImageTypeMetafile)
2094  METAFILE_Free((GpMetafile *)image);
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 < ARRAY_SIZE(vt2type); 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 < ARRAY_SIZE(keywords); j++)
3464  if (!strcmp(keywords[j].name, name.u.pszVal))
3465  break;
3466  if (j < ARRAY_SIZE(keywords) && !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  TRACE("%p %p\n", stream, image);
4324 
4325  if (!stream || !image)
4326  return InvalidParameter;
4327 
4328  /* choose an appropriate image decoder */
4329  stat = get_decoder_info(stream, &codec);
4330  if (stat != Ok) return stat;
4331 
4332  /* seek to the start of the stream */
4333  seek.QuadPart = 0;
4334  hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
4335  if (FAILED(hr)) return hresult_to_status(hr);
4336 
4337  /* call on the image decoder to do the real work */
4338  stat = codec->decode_func(stream, image);
4339 
4340  /* take note of the original data format */
4341  if (stat == Ok)
4342  {
4343  memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
4344  return Ok;
4345  }
4346 
4347  return stat;
4348 }
4349 
4350 /* FIXME: no ICM */
4352 {
4353  TRACE("%p %p\n", stream, image);
4354 
4355  return GdipLoadImageFromStream(stream, image);
4356 }
4357 
4359 {
4360  static int calls;
4361 
4362  TRACE("(%p,%u)\n", image, propId);
4363 
4364  if(!image)
4365  return InvalidParameter;
4366 
4367  if(!(calls++))
4368  FIXME("not implemented\n");
4369 
4370  return NotImplemented;
4371 }
4372 
4374 {
4375  static int calls;
4376 
4377  if (!image || !item) return InvalidParameter;
4378 
4379  TRACE("(%p,%p:%#x,%u,%u,%p)\n", image, item, item->id, item->type, item->length, item->value);
4380 
4381  if(!(calls++))
4382  FIXME("not implemented\n");
4383 
4384  return Ok;
4385 }
4386 
4388  GDIPCONST CLSID *clsidEncoder,
4389  GDIPCONST EncoderParameters *encoderParams)
4390 {
4391  GpStatus stat;
4392  IStream *stream;
4393 
4394  TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
4395 
4396  if (!image || !filename|| !clsidEncoder)
4397  return InvalidParameter;
4398 
4399  stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
4400  if (stat != Ok)
4401  return GenericError;
4402 
4403  stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
4404 
4405  IStream_Release(stream);
4406  return stat;
4407 }
4408 
4409 /*************************************************************************
4410  * Encoding functions -
4411  * These functions encode an image in different image file formats.
4412  */
4413 
4416 {
4417  GpStatus stat;
4418  GpBitmap *bitmap;
4420  IWICBitmapEncoder *encoder;
4421  IWICBitmapFrameEncode *frameencode;
4422  IPropertyBag2 *encoderoptions;
4423  HRESULT hr;
4424  UINT width, height;
4425  PixelFormat gdipformat=0;
4426  const WICPixelFormatGUID *desired_wicformat;
4427  WICPixelFormatGUID wicformat;
4428  GpRect rc;
4429  BitmapData lockeddata;
4430  UINT i;
4431 
4432  if (image->type != ImageTypeBitmap)
4433  return GenericError;
4434 
4435  bitmap = (GpBitmap*)image;
4436 
4437  GdipGetImageWidth(image, &width);
4438  GdipGetImageHeight(image, &height);
4439 
4440  rc.X = 0;
4441  rc.Y = 0;
4442  rc.Width = width;
4443  rc.Height = height;
4444 
4445  hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
4446  if (FAILED(hr))
4447  return hresult_to_status(hr);
4448  hr = IWICImagingFactory_CreateEncoder(factory, container, NULL, &encoder);
4449  IWICImagingFactory_Release(factory);
4450  if (FAILED(hr))
4451  return hresult_to_status(hr);
4452 
4453  hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
4454 
4455  if (SUCCEEDED(hr))
4456  {
4457  hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
4458  }
4459 
4460  if (SUCCEEDED(hr)) /* created frame */
4461  {
4462  hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
4463 
4464  if (SUCCEEDED(hr))
4465  hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
4466 
4467  if (SUCCEEDED(hr))
4468  hr = IWICBitmapFrameEncode_SetResolution(frameencode, image->xres, image->yres);
4469 
4470  if (SUCCEEDED(hr))
4471  {
4472  for (i=0; pixel_formats[i].wic_format; i++)
4473  {
4474  if (pixel_formats[i].gdip_format == bitmap->format)
4475  {
4476&