ReactOS  0.4.15-dev-4863-gba0d16f
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) {
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  {
305  break;
308  break;
311  break;
314  break;
316  getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
317  break;
319  getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
320  break;
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 {
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  {
514  break;
517  break;
520  break;
523  break;
524  case PixelFormat24bppRGB:
526  break;
527  case PixelFormat32bppRGB:
529  break;
532  break;
535  break;
536  case PixelFormat48bppRGB:
538  break;
541  break;
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 
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 
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 
1374 
1375  if(stat != Ok)
1376  return stat;
1377 
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:
1408  break;
1409  case 4:
1411  break;
1412  case 8:
1414  break;
1415  case 16:
1417  break;
1418  case 24:
1420  break;
1421  case 32:
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 
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){
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 
1517  bits + (width * 4 * (height - 1)), PixelFormat32bppPARGB,
1518  bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette);
1519  if (stat != Ok)
1520  {
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 
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 
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 
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  {
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 
1791  {
1792  char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
1793  BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
1794 
1798  pbmi->bmiHeader.biPlanes = 1;
1799  /* FIXME: use the rest of the data from format */
1802  pbmi->bmiHeader.biSizeImage = 0;
1805  pbmi->bmiHeader.biClrUsed = 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  {
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 ||
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 
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  {
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 
1900 #ifdef __REACTOS__
1901 static HBITMAP hbitmap_from_emf(HENHMETAFILE hemf)
1902 {
1903  BITMAPINFO bmi;
1904  HBITMAP hbm;
1905  SIZE size;
1907  HGDIOBJ hbmOld;
1908  RECT rc;
1909  HDC hdc;
1910 
1911  GetEnhMetaFileHeader(hemf, sizeof(header), &header);
1912  size.cx = header.rclBounds.right - header.rclBounds.left + 1;
1913  size.cy = header.rclBounds.bottom - header.rclBounds.top + 1;
1914 
1915  ZeroMemory(&bmi, sizeof(bmi));
1916  bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1917  bmi.bmiHeader.biWidth = size.cx;
1918  bmi.bmiHeader.biHeight = size.cy;
1919  bmi.bmiHeader.biPlanes = 1;
1920  bmi.bmiHeader.biBitCount = 24;
1921 
1924 
1925  hbmOld = SelectObject(hdc, hbm);
1926  SetRect(&rc, 0, 0, size.cx, size.cy);
1927  PlayEnhMetaFile(hdc, hemf, &rc);
1928  SelectObject(hdc, hbmOld);
1929 
1930  DeleteDC(hdc);
1931  return hbm;
1932 }
1933 
1934 #endif
1936  GpBitmap **bitmap)
1937 {
1938  GpStatus stat;
1939 
1940  TRACE("%p %p\n", stream, bitmap);
1941 
1943 
1944  if(stat != Ok)
1945  return stat;
1946 
1947 #ifdef __REACTOS__
1948  if ((*bitmap)->image.type == ImageTypeMetafile)
1949  {
1950  HBITMAP hbm = hbitmap_from_emf(((GpMetafile*)*bitmap)->hemf);
1951  GdipDisposeImage(&(*bitmap)->image);
1952  if (!hbm)
1953  return GenericError; /* FIXME: what error to return? */
1954 
1956  DeleteObject(hbm);
1957  }
1958  else
1959 #endif
1960  if((*bitmap)->image.type != ImageTypeBitmap){
1961  GdipDisposeImage(&(*bitmap)->image);
1962  *bitmap = NULL;
1963  return GenericError; /* FIXME: what error to return? */
1964  }
1965 
1966  return Ok;
1967 }
1968 
1969 /* FIXME: no icm */
1971  GpBitmap **bitmap)
1972 {
1973  TRACE("%p %p\n", stream, bitmap);
1974 
1976 }
1977 
1979  GpCachedBitmap **cachedbmp)
1980 {
1981  GpStatus stat;
1982 
1983  TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
1984 
1985  if(!bitmap || !graphics || !cachedbmp)
1986  return InvalidParameter;
1987 
1988  *cachedbmp = heap_alloc_zero(sizeof(GpCachedBitmap));
1989  if(!*cachedbmp)
1990  return OutOfMemory;
1991 
1992  stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
1993  if(stat != Ok){
1994  heap_free(*cachedbmp);
1995  return stat;
1996  }
1997 
1998  return Ok;
1999 }
2000 
2002 {
2003  GpStatus stat;
2004  BitmapData lockeddata;
2005  ULONG andstride, xorstride, bitssize;
2006  LPBYTE andbits, xorbits, androw, xorrow, srcrow;
2007  UINT x, y;
2008 
2009  TRACE("(%p, %p)\n", bitmap, hicon);
2010 
2011  if (!bitmap || !hicon)
2012  return InvalidParameter;
2013 
2015  PixelFormat32bppPARGB, &lockeddata);
2016  if (stat == Ok)
2017  {
2018  andstride = ((lockeddata.Width+31)/32)*4;
2019  xorstride = lockeddata.Width*4;
2020  bitssize = (andstride + xorstride) * lockeddata.Height;
2021 
2022  andbits = heap_alloc_zero(bitssize);
2023 
2024  if (andbits)
2025  {
2026  xorbits = andbits + andstride * lockeddata.Height;
2027 
2028  for (y=0; y<lockeddata.Height; y++)
2029  {
2030  srcrow = ((LPBYTE)lockeddata.Scan0) + lockeddata.Stride * y;
2031 
2032  androw = andbits + andstride * y;
2033  for (x=0; x<lockeddata.Width; x++)
2034  if (srcrow[3+4*x] >= 128)
2035  androw[x/8] |= 1 << (7-x%8);
2036 
2037  xorrow = xorbits + xorstride * y;
2038  memcpy(xorrow, srcrow, xorstride);
2039  }
2040 
2041  *hicon = CreateIcon(NULL, lockeddata.Width, lockeddata.Height, 1, 32,
2042  andbits, xorbits);
2043 
2044  heap_free(andbits);
2045  }
2046  else
2047  stat = OutOfMemory;
2048 
2049  GdipBitmapUnlockBits(bitmap, &lockeddata);
2050  }
2051 
2052  return stat;
2053 }
2054 
2056 {
2057  TRACE("%p\n", cachedbmp);
2058 
2059  if(!cachedbmp)
2060  return InvalidParameter;
2061 
2062  GdipDisposeImage(cachedbmp->image);
2063  heap_free(cachedbmp);
2064 
2065  return Ok;
2066 }
2067 
2069  GpCachedBitmap *cachedbmp, INT x, INT y)
2070 {
2071  TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
2072 
2073  if(!graphics || !cachedbmp)
2074  return InvalidParameter;
2075 
2076  return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
2077 }
2078 
2079 /* Internal utility function: Replace the image data of dst with that of src,
2080  * and free src. */
2081 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
2082 {
2083  assert(src->image.type == ImageTypeBitmap);
2084  assert(dst->image.type == ImageTypeBitmap);
2085 
2086  heap_free(dst->bitmapbits);
2087  heap_free(dst->own_bits);
2088  DeleteDC(dst->hdc);
2089  DeleteObject(dst->hbitmap);
2090 
2091  if (clobber_palette)
2092  {
2093  heap_free(dst->image.palette);
2094  dst->image.palette = src->image.palette;
2095  }
2096  else
2097  heap_free(src->image.palette);
2098 
2099  dst->image.xres = src->image.xres;
2100  dst->image.yres = src->image.yres;
2101  dst->width = src->width;
2102  dst->height = src->height;
2103  dst->format = src->format;
2104  dst->hbitmap = src->hbitmap;
2105  dst->hdc = src->hdc;
2106  dst->bits = src->bits;
2107  dst->stride = src->stride;
2108  dst->own_bits = src->own_bits;
2109  if (dst->metadata_reader)
2110  IWICMetadataReader_Release(dst->metadata_reader);
2111  dst->metadata_reader = src->metadata_reader;
2112  heap_free(dst->prop_item);
2113  dst->prop_item = src->prop_item;
2114  dst->prop_count = src->prop_count;
2115  if (dst->image.decoder)
2116  IWICBitmapDecoder_Release(dst->image.decoder);
2117  dst->image.decoder = src->image.decoder;
2118  dst->image.frame_count = src->image.frame_count;
2119  dst->image.current_frame = src->image.current_frame;
2120  dst->image.format = src->image.format;
2121 
2122  src->image.type = ~0;
2123  heap_free(src);
2124 }
2125 
2127 {
2128  if(!image)
2129  return InvalidParameter;
2130 
2131  if (image->type == ImageTypeBitmap)
2132  {
2133  heap_free(((GpBitmap*)image)->bitmapbits);
2134  heap_free(((GpBitmap*)image)->own_bits);
2135  DeleteDC(((GpBitmap*)image)->hdc);
2137  if (((GpBitmap*)image)->metadata_reader)
2138  IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader);
2139  heap_free(((GpBitmap*)image)->prop_item);
2140  }
2141  else if (image->type == ImageTypeMetafile)
2143  else
2144  {
2145  WARN("invalid image: %p\n", image);
2146  return ObjectBusy;
2147  }
2148  if (image->decoder)
2149  IWICBitmapDecoder_Release(image->decoder);
2150  heap_free(image->palette);
2151 
2152  return Ok;
2153 }
2154 
2156 {
2157  GpStatus status;
2158 
2159  TRACE("%p\n", image);
2160 
2162  if (status != Ok) return status;
2163  image->type = ~0;
2164  heap_free(image);
2165 
2166  return Ok;
2167 }
2168 
2170 {
2171  static int calls;
2172 
2173  TRACE("(%p,%p)\n", image, item);
2174 
2175  if(!image || !item)
2176  return InvalidParameter;
2177 
2178  if (!(calls++))
2179  FIXME("not implemented\n");
2180 
2181  return NotImplemented;
2182 }
2183 
2185 {
2186  static int calls;
2187 
2188  TRACE("(%p,%p)\n", image, item);
2189 
2190  if (!(calls++))
2191  FIXME("not implemented\n");
2192 
2193  return NotImplemented;
2194 }
2195 
2197  GpUnit *srcUnit)
2198 {
2199  TRACE("%p %p %p\n", image, srcRect, srcUnit);
2200 
2201  if(!image || !srcRect || !srcUnit)
2202  return InvalidParameter;
2203  if(image->type == ImageTypeMetafile){
2204  *srcRect = ((GpMetafile*)image)->bounds;
2205  *srcUnit = ((GpMetafile*)image)->unit;
2206  }
2207  else if(image->type == ImageTypeBitmap){
2208  srcRect->X = srcRect->Y = 0.0;
2209  srcRect->Width = (REAL) ((GpBitmap*)image)->width;
2210  srcRect->Height = (REAL) ((GpBitmap*)image)->height;
2211  *srcUnit = UnitPixel;
2212  }
2213  else{
2214  WARN("GpImage with no image data\n");
2215  return InvalidParameter;
2216  }
2217 
2218  TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
2219  srcRect->Width, srcRect->Height, *srcUnit);
2220 
2221  return Ok;
2222 }
2223 
2225  REAL *height)
2226 {
2227  TRACE("%p %p %p\n", image, width, height);
2228 
2229  if(!image || !height || !width)
2230  return InvalidParameter;
2231 
2232  if(image->type == ImageTypeMetafile){
2233  *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2234  *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2235  }
2236  else if(image->type == ImageTypeBitmap){
2237  *height = ((GpBitmap*)image)->height;
2238  *width = ((GpBitmap*)image)->width;
2239  }
2240  else{
2241  WARN("GpImage with no image data\n");
2242  return InvalidParameter;
2243  }
2244 
2245  TRACE("returning (%f, %f)\n", *height, *width);
2246  return Ok;
2247 }
2248 
2250  GpGraphics **graphics)
2251 {
2252  HDC hdc;
2253  GpStatus stat;
2254 
2255  TRACE("%p %p\n", image, graphics);
2256 
2257  if(!image || !graphics)
2258  return InvalidParameter;
2259 
2260  if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
2261  {
2262  hdc = ((GpBitmap*)image)->hdc;
2263 
2264  if(!hdc){
2265  hdc = CreateCompatibleDC(0);
2267  ((GpBitmap*)image)->hdc = hdc;
2268  }
2269 
2270  stat = GdipCreateFromHDC(hdc, graphics);
2271 
2272  if (stat == Ok)
2273  {
2274  (*graphics)->image = image;
2275  (*graphics)->xres = image->xres;
2276  (*graphics)->yres = image->yres;
2277  }
2278  }
2279  else if (image->type == ImageTypeMetafile)
2281  else
2282  stat = graphics_from_image(image, graphics);
2283 
2284  return stat;
2285 }
2286 
2288 {
2289  TRACE("%p %p\n", image, height);
2290 
2291  if(!image || !height)
2292  return InvalidParameter;
2293 
2294  if(image->type == ImageTypeMetafile)
2295  *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
2296  else if(image->type == ImageTypeBitmap)
2297  *height = ((GpBitmap*)image)->height;
2298  else
2299  {
2300  WARN("GpImage with no image data\n");
2301  return InvalidParameter;
2302  }
2303 
2304  TRACE("returning %d\n", *height);
2305 
2306  return Ok;
2307 }
2308 
2310 {
2311  if(!image || !res)
2312  return InvalidParameter;
2313 
2314  *res = image->xres;
2315 
2316  TRACE("(%p) <-- %0.2f\n", image, *res);
2317 
2318  return Ok;
2319 }
2320 
2322 {
2323  TRACE("%p %p\n", image, size);
2324 
2325  if(!image || !size)
2326  return InvalidParameter;
2327 
2328  if (!image->palette || image->palette->Count == 0)
2329  *size = sizeof(ColorPalette);
2330  else
2331  *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette->Count;
2332 
2333  TRACE("<-- %u\n", *size);
2334 
2335  return Ok;
2336 }
2337 
2338 /* FIXME: test this function for non-bitmap types */
2340 {
2341  TRACE("%p %p\n", image, format);
2342 
2343  if(!image || !format)
2344  return InvalidParameter;
2345 
2346  if(image->type != ImageTypeBitmap)
2348  else
2349  *format = ((GpBitmap*) image)->format;
2350 
2351  return Ok;
2352 }
2353 
2355 {
2356  TRACE("(%p, %p)\n", image, format);
2357 
2358  if(!image || !format)
2359  return InvalidParameter;
2360 
2361  memcpy(format, &image->format, sizeof(GUID));
2362 
2363  return Ok;
2364 }
2365 
2367 {
2368  TRACE("%p %p\n", image, type);
2369 
2370  if(!image || !type)
2371  return InvalidParameter;
2372 
2373  *type = image->type;
2374 
2375  return Ok;
2376 }
2377 
2379 {
2380  if(!image || !res)
2381  return InvalidParameter;
2382 
2383  *res = image->yres;
2384 
2385  TRACE("(%p) <-- %0.2f\n", image, *res);
2386 
2387  return Ok;
2388 }
2389 
2391 {
2392  TRACE("%p %p\n", image, width);
2393 
2394  if(!image || !width)
2395  return InvalidParameter;
2396 
2397  if(image->type == ImageTypeMetafile)
2398  *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
2399  else if(image->type == ImageTypeBitmap)
2400  *width = ((GpBitmap*)image)->width;
2401  else
2402  {
2403  WARN("GpImage with no image data\n");
2404  return InvalidParameter;
2405  }
2406 
2407  TRACE("returning %d\n", *width);
2408 
2409  return Ok;
2410 }
2411 
2413 {
2414  TRACE("(%p, %p)\n", image, num);
2415 
2416  if (!image || !num) return InvalidParameter;
2417 
2418  *num = 0;
2419 
2420  if (image->type == ImageTypeBitmap)
2421  {
2422  if (((GpBitmap *)image)->prop_item)
2423  {
2424  *num = ((GpBitmap *)image)->prop_count;
2425  return Ok;
2426  }
2427 
2428  if (((GpBitmap *)image)->metadata_reader)
2429  IWICMetadataReader_GetCount(((GpBitmap *)image)->metadata_reader, num);
2430  }
2431 
2432  return Ok;
2433 }
2434 
2436 {
2437  HRESULT hr;
2439  IWICEnumMetadataItem *enumerator;
2440  UINT prop_count, i, items_returned;
2441 
2442  TRACE("(%p, %u, %p)\n", image, num, list);
2443 
2444  if (!image || !list) return InvalidParameter;
2445 
2446  if (image->type != ImageTypeBitmap)
2447  {
2448  FIXME("Not implemented for type %d\n", image->type);
2449  return NotImplemented;
2450  }
2451 
2452  if (((GpBitmap *)image)->prop_item)
2453  {
2454  if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter;
2455 
2456  for (i = 0; i < num; i++)
2457  {
2458  list[i] = ((GpBitmap *)image)->prop_item[i].id;
2459  }
2460 
2461  return Ok;
2462  }
2463 
2464  reader = ((GpBitmap *)image)->metadata_reader;
2465  if (!reader)
2466  {
2467  if (num != 0) return InvalidParameter;
2468  return Ok;
2469  }
2470 
2471  hr = IWICMetadataReader_GetCount(reader, &prop_count);
2472  if (FAILED(hr)) return hresult_to_status(hr);
2473 
2474  if (num != prop_count) return InvalidParameter;
2475 
2476  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2477  if (FAILED(hr)) return hresult_to_status(hr);
2478 
2479  IWICEnumMetadataItem_Reset(enumerator);
2480 
2481  for (i = 0; i < num; i++)
2482  {
2483  PROPVARIANT id;
2484 
2485  hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, NULL, &items_returned);
2486  if (hr != S_OK) break;
2487 
2488  if (id.vt != VT_UI2)
2489  {
2490  FIXME("not supported propvariant type for id: %u\n", id.vt);
2491  list[i] = 0;
2492  continue;
2493  }
2494  list[i] = id.u.uiVal;
2495  }
2496 
2497  IWICEnumMetadataItem_Release(enumerator);
2498 
2499  return hr == S_OK ? Ok : hresult_to_status(hr);
2500 }
2501 
2502 static UINT propvariant_size(PROPVARIANT *value)
2503 {
2504  switch (value->vt & ~VT_VECTOR)
2505  {
2506  case VT_EMPTY:
2507  return 0;
2508  case VT_I1:
2509  case VT_UI1:
2510  if (!(value->vt & VT_VECTOR)) return 1;
2511  return value->u.caub.cElems;
2512  case VT_I2:
2513  case VT_UI2:
2514  if (!(value->vt & VT_VECTOR)) return 2;
2515  return value->u.caui.cElems * 2;
2516  case VT_I4:
2517  case VT_UI4:
2518  case VT_R4:
2519  if (!(value->vt & VT_VECTOR)) return 4;
2520  return value->u.caul.cElems * 4;
2521  case VT_I8:
2522  case VT_UI8:
2523  case VT_R8:
2524  if (!(value->vt & VT_VECTOR)) return 8;
2525  return value->u.cauh.cElems * 8;
2526  case VT_LPSTR:
2527  return value->u.pszVal ? strlen(value->u.pszVal) + 1 : 0;
2528  case VT_BLOB:
2529  return value->u.blob.cbSize;
2530  default:
2531  FIXME("not supported variant type %d\n", value->vt);
2532  return 0;
2533  }
2534 }
2535 
2537 {
2538  HRESULT hr;
2540  PROPVARIANT id, value;
2541 
2542  TRACE("(%p,%#x,%p)\n", image, propid, size);
2543 
2544  if (!size || !image) return InvalidParameter;
2545 
2546  if (image->type != ImageTypeBitmap)
2547  {
2548  FIXME("Not implemented for type %d\n", image->type);
2549  return NotImplemented;
2550  }
2551 
2552  if (((GpBitmap *)image)->prop_item)
2553  {
2554  UINT i;
2555 
2556  for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2557  {
2558  if (propid == ((GpBitmap *)image)->prop_item[i].id)
2559  {
2560  *size = sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2561  return Ok;
2562  }
2563  }
2564 
2565  return PropertyNotFound;
2566  }
2567 
2568  reader = ((GpBitmap *)image)->metadata_reader;
2569  if (!reader) return PropertyNotFound;
2570 
2571  id.vt = VT_UI2;
2572  id.u.uiVal = propid;
2573  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2574  if (FAILED(hr)) return PropertyNotFound;
2575 
2577  if (*size) *size += sizeof(PropertyItem);
2579 
2580  return Ok;
2581 }
2582 
2583 #ifndef PropertyTagTypeSByte
2584 #define PropertyTagTypeSByte 6
2585 #define PropertyTagTypeSShort 8
2586 #define PropertyTagTypeFloat 11
2587 #define PropertyTagTypeDouble 12
2588 #endif
2589 
2591 {
2592  static const struct
2593  {
2594  UINT vt, type;
2595  } vt2type[] =
2596  {
2609  };
2610  UINT i;
2611  for (i = 0; i < ARRAY_SIZE(vt2type); i++)
2612  {
2613  if (vt2type[i].vt == vt) return vt2type[i].type;
2614  }
2615  FIXME("not supported variant type %u\n", vt);
2616  return 0;
2617 }
2618 
2620  UINT size, PROPID id)
2621 {
2622  UINT item_size, item_type;
2623 
2624  item_size = propvariant_size(value);
2625  if (size != item_size + sizeof(PropertyItem)) return InvalidParameter;
2626 
2627  item_type = vt_to_itemtype(value->vt & ~VT_VECTOR);
2628  if (!item_type) return InvalidParameter;
2629 
2630  item->value = item + 1;
2631 
2632  switch (value->vt & ~VT_VECTOR)
2633  {
2634  case VT_I1:
2635  case VT_UI1:
2636  if (!(value->vt & VT_VECTOR))
2637  *(BYTE *)item->value = value->u.bVal;
2638  else
2639  memcpy(item->value, value->u.caub.pElems, item_size);
2640  break;
2641  case VT_I2:
2642  case VT_UI2:
2643  if (!(value->vt & VT_VECTOR))
2644  *(USHORT *)item->value = value->u.uiVal;
2645  else
2646  memcpy(item->value, value->u.caui.pElems, item_size);
2647  break;
2648  case VT_I4:
2649  case VT_UI4:
2650  case VT_R4:
2651  if (!(value->vt & VT_VECTOR))
2652  *(ULONG *)item->value = value->u.ulVal;
2653  else
2654  memcpy(item->value, value->u.caul.pElems, item_size);
2655  break;
2656  case VT_I8:
2657  case VT_UI8:
2658  case VT_R8:
2659  if (!(value->vt & VT_VECTOR))
2660  *(ULONGLONG *)item->value = value->u.uhVal.QuadPart;
2661  else
2662  memcpy(item->value, value->u.cauh.pElems, item_size);
2663  break;
2664  case VT_LPSTR:
2665  memcpy(item->value, value->u.pszVal, item_size);
2666  break;
2667  case VT_BLOB:
2668  memcpy(item->value, value->u.blob.pBlobData, item_size);
2669  break;
2670  default:
2671  FIXME("not supported variant type %d\n", value->vt);
2672  return InvalidParameter;
2673  }
2674 
2675  item->length = item_size;
2676  item->type = item_type;
2677  item->id = id;
2678 
2679  return Ok;
2680 }
2681 
2684 {
2685  GpStatus stat;
2686  HRESULT hr;
2688  PROPVARIANT id, value;
2689 
2690  TRACE("(%p,%#x,%u,%p)\n", image, propid, size, buffer);
2691 
2692  if (!image || !buffer) return InvalidParameter;
2693 
2694  if (image->type != ImageTypeBitmap)
2695  {
2696  FIXME("Not implemented for type %d\n", image->type);
2697  return NotImplemented;
2698  }
2699 
2700  if (((GpBitmap *)image)->prop_item)
2701  {
2702  UINT i;
2703 
2704  for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2705  {
2706  if (propid == ((GpBitmap *)image)->prop_item[i].id)
2707  {
2708  if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length)
2709  return InvalidParameter;
2710 
2711  *buffer = ((GpBitmap *)image)->prop_item[i];
2712  buffer->value = buffer + 1;
2713  memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length);
2714  return Ok;
2715  }
2716  }
2717 
2718  return PropertyNotFound;
2719  }
2720 
2721  reader = ((GpBitmap *)image)->metadata_reader;
2722  if (!reader) return PropertyNotFound;
2723 
2724  id.vt = VT_UI2;
2725  id.u.uiVal = propid;
2726  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2727  if (FAILED(hr)) return PropertyNotFound;
2728 
2729  stat = propvariant_to_item(&value, buffer, size, propid);
2731 
2732  return stat;
2733 }
2734 
2736 {
2737  HRESULT hr;
2739  IWICEnumMetadataItem *enumerator;
2740  UINT prop_count, prop_size, i;
2741  PROPVARIANT id, value;
2742 
2743  TRACE("(%p,%p,%p)\n", image, size, count);
2744 
2745  if (!image || !size || !count) return InvalidParameter;
2746 
2747  if (image->type != ImageTypeBitmap)
2748  {
2749  FIXME("Not implemented for type %d\n", image->type);
2750  return NotImplemented;
2751  }
2752 
2753  if (((GpBitmap *)image)->prop_item)
2754  {
2755  *count = ((GpBitmap *)image)->prop_count;
2756  *size = 0;
2757 
2758  for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
2759  {
2760  *size += sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
2761  }
2762 
2763  return Ok;
2764  }
2765 
2766  reader = ((GpBitmap *)image)->metadata_reader;
2767  if (!reader) return PropertyNotFound;
2768 
2769  hr = IWICMetadataReader_GetCount(reader, &prop_count);
2770  if (FAILED(hr)) return hresult_to_status(hr);
2771 
2772  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2773  if (FAILED(hr)) return hresult_to_status(hr);
2774 
2775  IWICEnumMetadataItem_Reset(enumerator);
2776 
2777  prop_size = 0;
2778 
2779  PropVariantInit(&id);
2780  PropVariantInit(&value);
2781 
2782  for (i = 0; i < prop_count; i++)
2783  {
2784  UINT items_returned, item_size;
2785 
2786  hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2787  if (hr != S_OK) break;
2788 
2789  item_size = propvariant_size(&value);
2790  if (item_size) prop_size += sizeof(PropertyItem) + item_size;
2791 
2792  PropVariantClear(&id);
2794  }
2795 
2796  IWICEnumMetadataItem_Release(enumerator);
2797 
2798  if (hr != S_OK) return PropertyNotFound;
2799 
2800  *count = prop_count;
2801  *size = prop_size;
2802  return Ok;
2803 }
2804 
2807 {
2808  GpStatus status;
2809  HRESULT hr;
2811  IWICEnumMetadataItem *enumerator;
2812  UINT prop_count, prop_size, i;
2813  PROPVARIANT id, value;
2814  char *item_value;
2815 
2816  TRACE("(%p,%u,%u,%p)\n", image, size, count, buf);
2817 
2818  if (!image || !buf) return InvalidParameter;
2819 
2820  if (image->type != ImageTypeBitmap)
2821  {
2822  FIXME("Not implemented for type %d\n", image->type);
2823  return NotImplemented;
2824  }
2825 
2826  status = GdipGetPropertySize(image, &prop_size, &prop_count);
2827  if (status != Ok) return status;
2828 
2829  if (prop_count != count || prop_size != size) return InvalidParameter;
2830 
2831  if (((GpBitmap *)image)->prop_item)
2832  {
2833  memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size);
2834 
2835  item_value = (char *)(buf + prop_count);
2836 
2837  for (i = 0; i < prop_count; i++)
2838  {
2839  buf[i].value = item_value;
2840  item_value += buf[i].length;
2841  }
2842 
2843  return Ok;
2844  }
2845 
2846  reader = ((GpBitmap *)image)->metadata_reader;
2847  if (!reader) return PropertyNotFound;
2848 
2849  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
2850  if (FAILED(hr)) return hresult_to_status(hr);
2851 
2852  IWICEnumMetadataItem_Reset(enumerator);
2853 
2854  item_value = (char *)(buf + prop_count);
2855 
2856  PropVariantInit(&id);
2857  PropVariantInit(&value);
2858 
2859  for (i = 0; i < prop_count; i++)
2860  {
2861  PropertyItem *item;
2862  UINT items_returned, item_size;
2863 
2864  hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
2865  if (hr != S_OK) break;
2866 
2867  if (id.vt != VT_UI2)
2868  {
2869  FIXME("not supported propvariant type for id: %u\n", id.vt);
2870  continue;
2871  }
2872 
2873  item_size = propvariant_size(&value);
2874  if (item_size)
2875  {
2876  item = heap_alloc(item_size + sizeof(*item));
2877 
2878  propvariant_to_item(&value, item, item_size + sizeof(*item), id.u.uiVal);
2879  buf[i].id = item->id;
2880  buf[i].type = item->type;
2881  buf[i].length = item_size;
2882  buf[i].value = item_value;
2883  memcpy(item_value, item->value, item_size);
2884  item_value += item_size;
2885 
2886  heap_free(item);
2887  }
2888 
2889  PropVariantClear(&id);
2891  }
2892 
2893  IWICEnumMetadataItem_Release(enumerator);
2894 
2895  if (hr != S_OK) return PropertyNotFound;
2896 
2897  return Ok;
2898 }
2899 
2901 {
2902  const GUID *format;
2903  const GUID *dimension;
2904 };
2905 
2907 {
2908  {&ImageFormatGIF, &FrameDimensionTime},
2909  {&ImageFormatIcon, &FrameDimensionResolution},
2910  {NULL}
2911 };
2912 
2914  GDIPCONST GUID* dimensionID, UINT* count)
2915 {
2916  TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
2917 
2918  if(!image || !count)
2919  return InvalidParameter;
2920 
2921  if (!dimensionID ||
2922  IsEqualGUID(dimensionID, &image->format) ||
2923  IsEqualGUID(dimensionID, &FrameDimensionPage) ||
2924  IsEqualGUID(dimensionID, &FrameDimensionTime))
2925  {
2926  *count = image->frame_count;
2927  return Ok;
2928  }
2929 
2930  return InvalidParameter;
2931 }
2932 
2934  UINT* count)
2935 {
2936  TRACE("(%p, %p)\n", image, count);
2937 
2938  /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
2939 
2940  if(!image || !count)
2941  return InvalidParameter;
2942 
2943  *count = 1;
2944 
2945  return Ok;
2946 }
2947 
2949  GUID* dimensionIDs, UINT count)
2950 {
2951  int i;
2952  const GUID *result=NULL;
2953 
2954  TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
2955 
2956  if(!image || !dimensionIDs || count != 1)
2957  return InvalidParameter;
2958 
2959  for (i=0; image_format_dimensions[i].format; i++)
2960  {
2961  if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
2962  {
2963  result = image_format_dimensions[i].dimension;
2964  break;
2965  }
2966  }
2967 
2968  if (!result)
2969  result = &FrameDimensionPage;
2970 
2971  memcpy(dimensionIDs, result, sizeof(GUID));
2972 
2973  return Ok;
2974 }
2975 
2977  GpImage **image)
2978 {
2979  GpStatus stat;
2980  IStream *stream;
2981 
2982  TRACE("(%s) %p\n", debugstr_w(filename), image);
2983 
2984  if (!filename || !image)
2985  return InvalidParameter;
2986 
2987  *image = NULL;
2988 
2990 
2991  if (stat != Ok)
2992  return stat;
2993 
2995 
2996  IStream_Release(stream);
2997 
2998  return stat;
2999 }
3000 
3001 /* FIXME: no icm handling */
3003 {
3004  TRACE("(%s) %p\n", debugstr_w(filename), image);
3005 
3007 }
3008 
3010 {
3011  UINT prop_size, prop_count;
3012  PropertyItem *prop_item;
3013 
3014  if (bitmap->prop_item == NULL)
3015  {
3016  prop_size = prop_count = 0;
3017  prop_item = heap_alloc_zero(item->length + sizeof(PropertyItem));
3018  if (!prop_item) return;
3019  }
3020  else
3021  {
3022  UINT i;
3023  char *item_value;
3024 
3025  GdipGetPropertySize(&bitmap->image, &prop_size, &prop_count);
3026 
3027  prop_item = heap_alloc_zero(prop_size + item->length + sizeof(PropertyItem));
3028  if (!prop_item) return;
3029  memcpy(prop_item, bitmap->prop_item, sizeof(PropertyItem) * bitmap->prop_count);
3030  prop_size -= sizeof(PropertyItem) * bitmap->prop_count;
3031  memcpy(prop_item + prop_count + 1, bitmap->prop_item + prop_count, prop_size);
3032 
3033  item_value = (char *)(prop_item + prop_count + 1);
3034 
3035  for (i = 0; i < prop_count; i++)
3036  {
3037  prop_item[i].value = item_value;
3038  item_value += prop_item[i].length;
3039  }
3040  }
3041 
3042  prop_item[prop_count].id = item->id;
3043  prop_item[prop_count].type = item->type;
3044  prop_item[prop_count].length = item->length;
3045  prop_item[prop_count].value = (char *)(prop_item + prop_count + 1) + prop_size;
3046  memcpy(prop_item[prop_count].value, item->value, item->length);
3047 
3048  heap_free(bitmap->prop_item);
3049  bitmap->prop_item = prop_item;
3050  bitmap->prop_count++;
3051 }
3052 
3053 static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3054 {
3055  HRESULT hr;
3056  GUID format;
3057  PROPVARIANT id, value;
3058  BOOL ret = FALSE;
3059 
3060  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
3061  if (FAILED(hr) || !IsEqualGUID(&format, guid)) return FALSE;
3062 
3063  PropVariantInit(&id);
3064  PropVariantInit(&value);
3065 
3066  id.vt = VT_LPWSTR;
3067  id.u.pwszVal = CoTaskMemAlloc((lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3068  if (!id.u.pwszVal) return FALSE;
3069  lstrcpyW(id.u.pwszVal, prop_name);
3070  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3071  if (hr == S_OK && value.vt == VT_BOOL)
3072  ret = value.u.boolVal;
3073 
3074  PropVariantClear(&id);
3076 
3077  return ret;
3078 }
3079 
3080 static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
3081 {
3082  HRESULT hr;
3083  GUID format;
3084  PROPVARIANT id, value;
3085  PropertyItem *item = NULL;
3086 
3087  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
3088  if (FAILED(hr) || !IsEqualGUID(&format, guid)) return NULL;
3089 
3090  PropVariantInit(&id);
3091  PropVariantInit(&value);
3092 
3093  id.vt = VT_LPWSTR;
3094  id.u.pwszVal = CoTaskMemAlloc((lstrlenW(prop_name) + 1) * sizeof(WCHAR));
3095  if (!id.u.pwszVal) return NULL;
3096  lstrcpyW(id.u.pwszVal, prop_name);
3097  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
3098  if (hr == S_OK)
3099  {
3100  UINT item_size = propvariant_size(&value);
3101  if (item_size)
3102  {
3103  item_size += sizeof(*item);
3104  item = heap_alloc_zero(item_size);
3105  if (propvariant_to_item(&value, item, item_size, 0) != Ok)
3106  {
3107  heap_free(item);
3108  item = NULL;
3109  }
3110  }
3111  }
3112 
3113  PropVariantClear(&id);
3115 
3116  return item;
3117 }
3118 
3120 {
3121  static const WCHAR textentryW[] = { 'T','e','x','t','E','n','t','r','y',0 };
3123 
3124  comment = get_property(reader, &GUID_MetadataFormatGifComment, textentryW);
3125  if (comment)
3127 
3128  return comment;
3129 }
3130 
3132 {
3133  static const WCHAR applicationW[] = { 'A','p','p','l','i','c','a','t','i','o','n',0 };
3134  static const WCHAR dataW[] = { 'D','a','t','a',0 };
3135  PropertyItem *appext = NULL, *appdata = NULL, *loop = NULL;
3136 
3137  appext = get_property(reader, &GUID_MetadataFormatAPE, applicationW);
3138  if (appext)
3139  {
3140  if (appext->type == PropertyTagTypeByte && appext->length == 11 &&
3141  (!memcmp(appext->value, "NETSCAPE2.0", 11) || !memcmp(appext->value, "ANIMEXTS1.0", 11)))
3142  {
3143  appdata = get_property(reader, &GUID_MetadataFormatAPE, dataW);
3144  if (appdata)
3145  {
3146  if (appdata->type == PropertyTagTypeByte && appdata->length == 4)
3147  {
3148  BYTE *data = appdata->value;
3149  if (data[0] == 3 && data[1] == 1)
3150  {
3151  loop = heap_alloc_zero(sizeof(*loop) + sizeof(SHORT));
3152  if (loop)
3153  {
3154  loop->type = PropertyTagTypeShort;
3155  loop->id = PropertyTagLoopCount;
3156  loop->length = sizeof(SHORT);
3157  loop->value = loop + 1;
3158  *(SHORT *)loop->value = data[2] | (data[3] << 8);
3159  }
3160  }
3161  }
3162  }
3163  }
3164  }
3165 
3166  heap_free(appext);
3167  heap_free(appdata);
3168 
3169  return loop;
3170 }
3171 
3173 {
3174  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 };
3175  PropertyItem *background;
3176 
3177  background = get_property(reader, &GUID_MetadataFormatLSD, backgroundW);
3178  if (background)
3179  background->id = PropertyTagIndexBackground;
3180 
3181  return background;
3182 }
3183 
3185 {
3186  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 };
3187  HRESULT hr;
3190  UINT count = 0;
3191  WICColor colors[256];
3192 
3193  if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW))
3194  return NULL;
3195 
3196  hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
3197  if (hr != S_OK) return NULL;
3198 
3199  hr = IWICImagingFactory_CreatePalette(factory, &palette);
3200  if (hr == S_OK)
3201  {
3202  hr = IWICBitmapDecoder_CopyPalette(decoder, palette);
3203  if (hr == S_OK)
3204  IWICPalette_GetColors(palette, 256, colors, &count);
3205 
3206  IWICPalette_Release(palette);
3207  }
3208 
3209  IWICImagingFactory_Release(factory);
3210 
3211  if (count)
3212  {
3213  PropertyItem *pal;
3214  UINT i;
3215  BYTE *rgb;
3216 
3217  pal = heap_alloc_zero(sizeof(*pal) + count * 3);
3218  if (!pal) return NULL;
3219  pal->type = PropertyTagTypeByte;
3221  pal->value = pal + 1;
3222  pal->length = count * 3;
3223 
3224  rgb = pal->value;
3225 
3226  for (i = 0; i < count; i++)
3227  {
3228  rgb[i*3] = (colors[i] >> 16) & 0xff;
3229  rgb[i*3 + 1] = (colors[i] >> 8) & 0xff;
3230  rgb[i*3 + 2] = colors[i] & 0xff;
3231  }
3232 
3233  return pal;
3234  }
3235 
3236  return NULL;
3237 }
3238 
3240 {
3241  static const WCHAR transparency_flagW[] = { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 };
3242  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 };
3243  PropertyItem *index = NULL;
3244 
3245  if (get_bool_property(reader, &GUID_MetadataFormatGCE, transparency_flagW))
3246  {
3247  index = get_property(reader, &GUID_MetadataFormatGCE, colorW);
3248  if (index)
3250  }
3251  return index;
3252 }
3253 
3255 {
3256  HRESULT hr;
3257  IWICMetadataBlockReader *block_reader;
3259  UINT block_count, i;
3260  PropertyItem *prop;
3261  LONG value = 0;
3262 
3263  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3264  if (hr == S_OK)
3265  {
3266  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3267  if (hr == S_OK)
3268  {
3269  for (i = 0; i < block_count; i++)
3270  {
3271  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3272  if (hr == S_OK)
3273  {
3274  prop = get_property(reader, format, property);
3275  if (prop)
3276  {
3277  if (prop->type == PropertyTagTypeByte && prop->length == 1)
3278  value = *(BYTE *)prop->value;
3279  else if (prop->type == PropertyTagTypeShort && prop->length == 2)
3280  value = *(SHORT *)prop->value;
3281 
3282  heap_free(prop);
3283  }
3284  IWICMetadataReader_Release(reader);
3285  }
3286  }
3287  }
3288  IWICMetadataBlockReader_Release(block_reader);
3289  }
3290 
3291  return value;
3292 }
3293 
3294 static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
3295 {
3296  static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
3297  HRESULT hr;
3298  IWICBitmapFrameDecode *frame;
3299  IWICMetadataBlockReader *block_reader;
3301  UINT frame_count, block_count, i;
3302  PropertyItem *delay = NULL, *comment = NULL, *background = NULL;
3303  PropertyItem *transparent_idx = NULL, *loop = NULL, *palette = NULL;
3304 
3305  IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3306  if (frame_count > 1)
3307  {
3308  delay = heap_alloc_zero(sizeof(*delay) + frame_count * sizeof(LONG));
3309  if (delay)
3310  {
3311  LONG *value;
3312 
3313  delay->type = PropertyTagTypeLong;
3314  delay->id = PropertyTagFrameDelay;
3315  delay->length = frame_count * sizeof(LONG);
3316  delay->value = delay + 1;
3317 
3318  value = delay->value;
3319 
3320  for (i = 0; i < frame_count; i++)
3321  {
3322  hr = IWICBitmapDecoder_GetFrame(decoder, i, &frame);
3323  if (hr == S_OK)
3324  {
3325  value[i] = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, delayW);
3326  IWICBitmapFrameDecode_Release(frame);
3327  }
3328  else value[i] = 0;
3329  }
3330  }
3331  }
3332 
3333  hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3334  if (hr == S_OK)
3335  {
3336  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3337  if (hr == S_OK)
3338  {
3339  for (i = 0; i < block_count; i++)
3340  {
3341  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3342  if (hr == S_OK)
3343  {
3344  if (!comment)
3346 
3347  if (frame_count > 1 && !loop)
3348  loop = get_gif_loopcount(reader);
3349 
3350  if (!background)
3351  background = get_gif_background(reader);
3352 
3353  if (!palette)
3354  palette = get_gif_palette(decoder, reader);
3355 
3356  IWICMetadataReader_Release(reader);
3357  }
3358  }
3359  }
3360  IWICMetadataBlockReader_Release(block_reader);
3361  }
3362 
3363  if (frame_count > 1 && !loop)
3364  {
3365  loop = heap_alloc_zero(sizeof(*loop) + sizeof(SHORT));
3366  if (loop)
3367  {
3368  loop->type = PropertyTagTypeShort;
3369  loop->id = PropertyTagLoopCount;
3370  loop->length = sizeof(SHORT);
3371  loop->value = loop + 1;
3372  *(SHORT *)loop->value = 1;
3373  }
3374  }
3375 
3376  if (delay) add_property(bitmap, delay);
3378  if (loop) add_property(bitmap, loop);
3380  if (background) add_property(bitmap, background);
3381 
3382  heap_free(delay);
3383  heap_free(comment);
3384  heap_free(loop);
3385  heap_free(palette);
3386  heap_free(background);
3387 
3388  /* Win7 gdiplus always returns transparent color index from frame 0 */
3389  hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
3390  if (hr != S_OK) return;
3391 
3392  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3393  if (hr == S_OK)
3394  {
3395  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3396  if (hr == S_OK)
3397  {
3398  for (i = 0; i < block_count; i++)
3399  {
3400  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3401  if (hr == S_OK)
3402  {
3403  if (!transparent_idx)
3404  transparent_idx = get_gif_transparent_idx(reader);
3405 
3406  IWICMetadataReader_Release(reader);
3407  }
3408  }
3409  }
3410  IWICMetadataBlockReader_Release(block_reader);
3411  }
3412 
3413  if (transparent_idx) add_property(bitmap, transparent_idx);
3414  heap_free(transparent_idx);
3415 
3416  IWICBitmapFrameDecode_Release(frame);
3417 }
3418 
3419 static PropertyItem* create_prop(PROPID propid, PROPVARIANT* value)
3420 {
3421  PropertyItem *item = NULL;
3422  UINT item_size = propvariant_size(value);
3423 
3424  if (item_size)
3425  {
3426  item_size += sizeof(*item);
3427  item = heap_alloc_zero(item_size);
3428  if (propvariant_to_item(value, item, item_size, propid) != Ok)
3429  {
3430  heap_free(item);
3431  item = NULL;
3432  }
3433  }
3434 
3435  return item;
3436 }
3437 
3439 {
3440  PROPVARIANT value;
3441  HRESULT hr;
3442  ULONG result=0;
3443 
3444  hr = IWICMetadataReader_GetValueByIndex(reader, index, NULL, NULL, &value);
3445  if (SUCCEEDED(hr))
3446  {
3447  switch (value.vt)
3448  {
3449  case VT_UI4:
3450  result = value.u.ulVal;
3451  break;
3452  default:
3453  ERR("unhandled case %u\n", value.vt);
3454  break;
3455  }
3457  }
3458  return result;
3459 }
3460 
3461 static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
3462 {
3463  HRESULT hr;
3464  IWICBitmapFrameDecode *frame;
3465  IWICMetadataBlockReader *block_reader;
3467  UINT block_count, i, j;
3468  struct keyword_info {
3469  const char* name;
3470  PROPID propid;
3471  BOOL seen;
3472  } keywords[] = {
3473  { "Title", PropertyTagImageTitle },
3474  { "Author", PropertyTagArtist },
3475  { "Description", PropertyTagImageDescription },
3476  { "Copyright", PropertyTagCopyright },
3477  { "Software", PropertyTagSoftwareUsed },
3478  { "Source", PropertyTagEquipModel },
3479  { "Comment", PropertyTagExifUserComment },
3480  };
3481  BOOL seen_gamma=FALSE, seen_whitepoint=FALSE, seen_chrm=FALSE;
3482 
3483  hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
3484  if (hr != S_OK) return;
3485 
3486  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
3487  if (hr == S_OK)
3488  {
3489  hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
3490  if (hr == S_OK)
3491  {
3492  for (i = 0; i < block_count; i++)
3493  {
3494  hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
3495  if (hr == S_OK)
3496  {
3497  GUID format;
3498 
3499  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
3500  if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunktEXt, &format))
3501  {
3502  PROPVARIANT name, value;
3503  PropertyItem* item;
3504 
3505  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &name, &value);
3506 
3507  if (SUCCEEDED(hr))
3508  {
3509  if (name.vt == VT_LPSTR)
3510  {
3511  for (j = 0; j < ARRAY_SIZE(keywords); j++)
3512  if (!strcmp(keywords[j].name, name.u.pszVal))
3513  break;
3514  if (j < ARRAY_SIZE(keywords) && !keywords[j].seen)
3515  {
3516  keywords[j].seen = TRUE;
3517  item = create_prop(keywords[j].propid, &value);
3518  if (item)
3520  heap_free(item);
3521  }
3522  }
3523 
3526  }
3527  }
3528  else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkgAMA, &format))
3529  {
3530  PropertyItem* item;
3531 
3532  if (!seen_gamma)
3533  {
3534  item = heap_alloc_zero(sizeof(PropertyItem) + sizeof(ULONG) * 2);
3535  if (item)
3536  {
3537  ULONG *rational;
3538  item->length = sizeof(ULONG) * 2;
3539  item->type = PropertyTagTypeRational;
3540  item->id = PropertyTagGamma;
3541  rational = item->value = item + 1;
3542  rational[0] = 100000;
3543  rational[1] = get_ulong_by_index(reader, 0);
3545  seen_gamma = TRUE;
3546  heap_free(item);
3547  }
3548  }
3549  }
3550  else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkcHRM, &format))
3551  {
3552  PropertyItem* item;
3553 
3554  if (!seen_whitepoint)
3555  {
3556  item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 4);
3557  if (item)
3558  {
3559  ULONG *rational;
3560  item->length = sizeof(ULONG) * 4;
3561  item->type = PropertyTagTypeRational;
3563  rational = item->value = item + 1;
3564  rational[0] = get_ulong_by_index(reader, 0);
3565  rational[1] = 100000;
3566  rational[2] = get_ulong_by_index(reader, 1);
3567  rational[3] = 100000;
3569  seen_whitepoint = TRUE;
3570  GdipFree(item);
3571  }
3572  }
3573  if (!seen_chrm)
3574  {
3575  item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 12);
3576  if (item)
3577  {
3578  ULONG *rational;
3579  item->length = sizeof(ULONG) * 12;
3580  item->type = PropertyTagTypeRational;
3582  rational = item->value = item + 1;
3583  rational[0] = get_ulong_by_index(reader, 2);
3584  rational[1] = 100000;
3585  rational[2] = get_ulong_by_index(reader, 3);
3586  rational[3] = 100000;
3587  rational[4] = get_ulong_by_index(reader, 4);
3588  rational[5] = 100000;
3589  rational[6] = get_ulong_by_index(reader, 5);
3590  rational[7] = 100000;
3591  rational[8] = get_ulong_by_index(reader, 6);
3592  rational[9] = 100000;
3593  rational[10] = get_ulong_by_index(reader, 7);
3594  rational[11] = 100000;
3596  seen_chrm = TRUE;
3597  GdipFree(item);
3598  }
3599  }
3600  }
3601 
3602  IWICMetadataReader_Release(reader);
3603  }
3604  }
3605  }
3606  IWICMetadataBlockReader_Release(block_reader);
3607  }
3608 
3609  IWICBitmapFrameDecode_Release(frame);
3610 }
3611 
3613 {
3615  HRESULT hr;
3616 
3617  TRACE("%p,%s\n", stream, wine_dbgstr_guid(container));
3618 
3619  hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
3620  if (FAILED(hr)) return hresult_to_status(hr);
3621  hr = IWICImagingFactory_CreateDecoder(factory, container, NULL, decoder);
3622  IWICImagingFactory_Release(factory);
3623  if (FAILED(hr)) return hresult_to_status(hr);
3624 
3625  hr = IWICBitmapDecoder_Initialize(*decoder, stream, WICDecodeMetadataCacheOnLoad);
3626  if (FAILED(hr)) return hresult_to_status(hr);
3627  return Ok;
3628 }
3629 
3631 
3632 static GpStatus decode_frame_wic(IWICBitmapDecoder *decoder, BOOL force_conversion,
3633  UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
3634 {
3635  GpStatus status=Ok;
3636  GpBitmap *bitmap;
3637  HRESULT hr;
3638  IWICBitmapFrameDecode *frame;
3640  IWICMetadataBlockReader *block_reader;
3645  int i;
3646  UINT width, height, frame_count;
3647  BitmapData lockeddata;
3648  WICRect wrc;
3649 
3650  TRACE("%p,%u,%p\n", decoder, active_frame, image);
3651 
3652  IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
3653  hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
3654  if (SUCCEEDED(hr)) /* got frame */
3655  {
3656  hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
3657 
3658  if (SUCCEEDED(hr))
3659  {
3660  if (!force_conversion)
3661  {
3662  for (i=0; pixel_formats[i].wic_format; i++)
3663  {
3665  {
3666  source = (IWICBitmapSource*)frame;
3667  IWICBitmapSource_AddRef(source);
3668  gdip_format = pixel_formats[i].gdip_format;
3669  palette_type = pixel_formats[i].palette_type;
3670  break;
3671  }
3672  }
3673  }
3674  if (!source)
3675  {
3676  /* unknown format; fall back on 32bppARGB */
3677  hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
3679  }
3680  TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format);
3681  }
3682 
3683  if (SUCCEEDED(hr)) /* got source */
3684  {
3685  hr = IWICBitmapSource_GetSize(source, &width, &height);
3686 
3687  if (SUCCEEDED(hr))
3689  NULL, &bitmap);
3690 
3691  if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
3692  {
3694  gdip_format, &lockeddata);
3695  if (status == Ok) /* locked bitmap */
3696  {
3697  wrc.X = 0;
3698  wrc.Width = width;
3699  wrc.Height = 1;
3700  for (i=0; i<height; i++)
3701  {
3702  wrc.Y = i;
3703  hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
3704  abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
3705  if (FAILED(hr)) break;
3706  }
3707 
3708  GdipBitmapUnlockBits(bitmap, &lockeddata);
3709  }
3710 
3711  if (SUCCEEDED(hr) && status == Ok)
3712  *image = &bitmap->image;
3713  else
3714  {
3715  *image = NULL;
3716  GdipDisposeImage(&bitmap->image);
3717  }
3718 
3719  if (SUCCEEDED(hr) && status == Ok)
3720  {
3721  double dpix, dpiy;
3722  hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy);
3723  if (SUCCEEDED(hr))
3724  {
3725  bitmap->image.xres = dpix;
3726  bitmap->image.yres = dpiy;
3727  }
3728  hr = S_OK;
3729  }
3730  }
3731 
3732  IWICBitmapSource_Release(source);
3733  }
3734 
3735  if (SUCCEEDED(hr)) {
3736  bitmap->metadata_reader = NULL;
3737 
3738  if (metadata_reader)
3739  metadata_reader(bitmap, decoder, active_frame);
3740  else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK)
3741  {
3742  UINT block_count = 0;
3743  if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count)
3744  IWICMetadataBlockReader_GetReaderByIndex(block_reader, 0, &bitmap->metadata_reader);
3745  IWICMetadataBlockReader_Release(block_reader);
3746  }
3747 
3748  palette = get_palette(frame, palette_type);
3749  IWICBitmapFrameDecode_Release(frame);
3750  }
3751  }
3752 
3753  if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
3754 
3755  if (status == Ok)
3756  {
3757  /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
3759  if (IsEqualGUID(&wic_format, &GUID_WICPixelFormat2bppGray) ||
3760  IsEqualGUID(&wic_format, &GUID_WICPixelFormat4bppGray) ||
3761  IsEqualGUID(&wic_format, &GUID_WICPixelFormat8bppGray) ||
3762  IsEqualGUID(&wic_format, &GUID_WICPixelFormat16bppGray))
3763  bitmap->image.flags |= ImageFlagsColorSpaceGRAY;
3764  else
3765  bitmap->image.flags |= ImageFlagsColorSpaceRGB;
3766  bitmap->image.frame_count = frame_count;
3767  bitmap->image.current_frame = active_frame;
3768  bitmap->image.decoder = decoder;
3769  IWICBitmapDecoder_AddRef(decoder);
3770  if (palette)
3771  {
3772  heap_free(bitmap->image.palette);
3773  bitmap->image.palette = palette;
3774  }
3775  else
3776  {
3777  if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite))
3778  bitmap->image.palette->Flags = 0;
3779  }
3780  TRACE("=> %p\n", *image);
3781  }
3782 
3783  return status;
3784 }
3785 
3787  metadata_reader_func metadata_reader, GpImage **image)
3788 {
3789  IWICBitmapDecoder *decoder;
3790  GpStatus status;
3791 
3793  if(status != Ok)
3794  return status;
3795 
3796  status = decode_frame_wic(decoder, FALSE, 0, metadata_reader, image);
3797  IWICBitmapDecoder_Release(decoder);
3798  return status;
3799 }
3800 
3802 {
3803  GpImage *new_image;
3804  GpStatus status;
3805 
3806  status = decode_frame_wic(image->decoder, FALSE, active_frame, NULL, &new_image);
3807  if(status != Ok)
3808  return status;
3809 
3810  new_image->busy = image->busy;
3811  memcpy(&new_image->format, &image->format, sizeof(GUID));
3813  if (image->type == ImageTypeBitmap)
3814  *(GpBitmap *)image = *(GpBitmap *)new_image;
3815  else if (image->type == ImageTypeMetafile)
3816  *(GpMetafile *)image = *(GpMetafile *)new_image;
3817  new_image->type = ~0;
3818  heap_free(new_image);
3819  return Ok;
3820 }
3821 
3823  UINT *left, UINT *top, UINT *width, UINT *height)
3824 {
3825  static const WCHAR leftW[] = {'L','e','f','t',0};
3826  static const WCHAR topW[] = {'T','o','p',0};
3827 
3828  *left = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, leftW);
3829  *top = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, topW);
3830 
3831  return IWICBitmapFrameDecode_GetSize(frame, width, height);
3832 }
3833 
3835 {
3836  UINT i, j, left, top, width, height;
3838  BYTE *new_bits;
3839  HRESULT hr;
3840 
3841  hr = get_gif_frame_rect(frame, &left, &top, &width, &height);
3842  if(FAILED(hr))
3843  return hr;
3844 
3845  hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
3846  if(FAILED(hr))
3847  return hr;
3848 
3849  new_bits = heap_alloc_zero(width*height*4);
3850  if(!new_bits)
3851  return E_OUTOFMEMORY;
3852 
3853  hr = IWICBitmapSource_CopyPixels(source, NULL, width*4, width*height*4, new_bits);
3854  IWICBitmapSource_Release(source);
3855  if(FAILED(hr)) {
3856  heap_free(new_bits);
3857  return hr;
3858  }
3859 
3860  for(i=0; i<height && i+top<bitmap->height; i++) {
3861  for(j=0; j<width && j+left<bitmap->width; j++) {
3862  DWORD *src = (DWORD*)(new_bits+i*width*4+j*4);
3863  DWORD *dst = (DWORD*)(bitmap->bits+(i+top)*bitmap->stride+(j+left)*4);
3864 
3865  if(first_frame || *src>>24 != 0)
3866  *dst = *src;
3867  }
3868  }
3869  heap_free(new_bits);
3870  return hr;
3871 }
3872 
3874 {
3875  BYTE bgcolor_idx = 0;
3876  UINT i;
3877 
3878  for(i=0; i<bitmap->prop_count; i++) {
3879  if(bitmap->prop_item[i].id == PropertyTagIndexBackground) {
3880  bgcolor_idx = *(BYTE*)bitmap->prop_item[i].value;
3881  break;
3882  }
3883  }
3884 
3885  for(i=0; i<bitmap->prop_count; i++) {
3886  if(bitmap->prop_item[i].id == PropertyTagIndexTransparent) {
3887  BYTE transparent_idx;
3888  transparent_idx = *(BYTE*)bitmap->prop_item[i].value;
3889 
3890  if(transparent_idx == bgcolor_idx)
3891  return 0;
3892  }
3893  }