ReactOS 0.4.15-dev-5672-gf73ac17
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
48static 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;
120 break;
121 default:
122 palette->Flags = 0;
123 }
124 IWICPalette_HasAlpha(wic_palette, &alpha);
125 if(alpha)
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
157static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
158{
159 *index = (row[x/8]>>(7-x%8)) & 1;
160}
161
162static 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
170static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
171{
172 *index = row[x];
173}
174
175static 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
182static 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
192static 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
202static 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
215static 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
224static 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
233static 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
242static 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
256static 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
265static 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
274static 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;
317 break;
320 break;
323 break;
325 getpixel_24bppRGB(&r,&g,&b,&a,row,x);
326 break;
328 getpixel_32bppRGB(&r,&g,&b,&a,row,x);
329 break;
332 break;
335 break;
337 getpixel_48bppRGB(&r,&g,&b,&a,row,x);
338 break;
341 break;
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
386static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
388{
390 row[x]=index;
391}
392
393static 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
399static 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
409 BYTE *row, UINT x)
410{
411 *((WORD*)(row)+x) = (r+g+b)*85;
412}
413
414static 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
422static 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
430static 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
439static 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
447static 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
453static 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
459static 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
468static 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
476static 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
483static 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;
526 break;
529 break;
532 break;
535 break;
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 {
636 default:
637 break;
638 }
639 break;
641 switch (dst_format)
642 {
663 default:
664 break;
665 }
666 break;
668 switch (dst_format)
669 {
690 default:
691 break;
692 }
693 break;
695 switch (dst_format)
696 {
719 default:
720 break;
721 }
722 break;
724 switch (dst_format)
725 {
748 default:
749 break;
750 }
751 break;
753 switch (dst_format)
754 {
777 default:
778 break;
779 }
780 break;
782 switch (dst_format)
783 {
806 default:
807 break;
808 }
809 break;
811 switch (dst_format)
812 {
835 default:
836 break;
837 }
838 break;
840 switch (dst_format)
841 {
864 default:
865 break;
866 }
867 break;
869 switch (dst_format)
870 {
886 convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
887 return Ok;
892 default:
893 break;
894 }
895 break;
897 switch (dst_format)
898 {
921 default:
922 break;
923 }
924 break;
926 switch (dst_format)
927 {
950 default:
951 break;
952 }
953 break;
955 switch (dst_format)
956 {
979 default:
980 break;
981 }
982 break;
984 switch (dst_format)
985 {
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. */
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. */
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
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
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 {
1318
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 {
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
1387{
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){
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;
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;
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
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 */
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
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__
1901static 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
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. */
2081static 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{
2158
2159 TRACE("%p\n", image);
2160
2162 if (status != Ok) return status;
2163 image->type = ~0;
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){
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
2502static 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
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{
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 {
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;
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
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
3081{
3082 HRESULT hr;
3083 GUID format;
3084 PROPVARIANT id, value;
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);
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;
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 };
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 {
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
3294static 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);
3384 heap_free(loop);
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
3419static PropertyItem* create_prop(PROPID propid, PROPVARIANT* value)
3420{
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
3461static 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;
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 {
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;
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 {
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;
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;
3582 rational = item->value = item + 1;
3583 rational[0] =