2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2012,2016 Dmitry Timoshkov
4 * Copyright 2016 Sebastian Lackner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
39 IWICPalette IWICPalette_iface
;
43 WICBitmapPaletteType type
;
44 CRITICAL_SECTION lock
; /* must be held when count, colors, or type is accessed */
47 static inline PaletteImpl
*impl_from_IWICPalette(IWICPalette
*iface
)
49 return CONTAINING_RECORD(iface
, PaletteImpl
, IWICPalette_iface
);
52 static HRESULT WINAPI
PaletteImpl_QueryInterface(IWICPalette
*iface
, REFIID iid
,
55 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
56 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
58 if (!ppv
) return E_INVALIDARG
;
60 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICPalette
, iid
))
62 *ppv
= &This
->IWICPalette_iface
;
70 IUnknown_AddRef((IUnknown
*)*ppv
);
74 static ULONG WINAPI
PaletteImpl_AddRef(IWICPalette
*iface
)
76 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
77 ULONG ref
= InterlockedIncrement(&This
->ref
);
79 TRACE("(%p) refcount=%u\n", iface
, ref
);
84 static ULONG WINAPI
PaletteImpl_Release(IWICPalette
*iface
)
86 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
87 ULONG ref
= InterlockedDecrement(&This
->ref
);
89 TRACE("(%p) refcount=%u\n", iface
, ref
);
93 This
->lock
.DebugInfo
->Spare
[0] = 0;
94 DeleteCriticalSection(&This
->lock
);
95 HeapFree(GetProcessHeap(), 0, This
->colors
);
96 HeapFree(GetProcessHeap(), 0, This
);
102 static WICColor
*generate_gray16_palette(UINT
*count
)
108 entries
= HeapAlloc(GetProcessHeap(), 0, 16 * sizeof(WICColor
));
109 if (!entries
) return NULL
;
111 for (i
= 0; i
< 16; i
++)
113 entries
[i
] = 0xff000000;
114 entries
[i
] |= (i
<<20) | (i
<<16) | (i
<<12) | (i
<<8) | (i
<<4) | i
;
119 static WICColor
*generate_gray256_palette(UINT
*count
)
125 entries
= HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor
));
126 if (!entries
) return NULL
;
128 for (i
= 0; i
< 256; i
++)
130 entries
[i
] = 0xff000000;
131 entries
[i
] |= (i
<<16) | (i
<<8) | i
;
136 static WICColor
*generate_halftone8_palette(UINT
*count
, BOOL add_transparent
)
141 *count
= add_transparent
? 17 : 16;
142 entries
= HeapAlloc(GetProcessHeap(), 0, *count
* sizeof(WICColor
));
143 if (!entries
) return NULL
;
145 for (i
= 0; i
< 8; i
++)
147 entries
[i
] = 0xff000000;
148 if (i
& 1) entries
[i
] |= 0xff;
149 if (i
& 2) entries
[i
] |= 0xff00;
150 if (i
& 4) entries
[i
] |= 0xff0000;
153 for (i
= 8; i
< 16; i
++)
155 static const DWORD halftone
[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
156 0x000080, 0x808000, 0x800080, 0x008080 };
157 entries
[i
] = 0xff000000;
158 entries
[i
] |= halftone
[i
-8];
167 static WICColor
*generate_halftone27_palette(UINT
*count
, BOOL add_transparent
)
172 *count
= add_transparent
? 29 : 28;
173 entries
= HeapAlloc(GetProcessHeap(), 0, *count
* sizeof(WICColor
));
174 if (!entries
) return NULL
;
176 for (i
= 0; i
< 27; i
++)
178 static const BYTE halftone_values
[4] = { 0x00,0x80,0xff };
179 entries
[i
] = 0xff000000;
180 entries
[i
] |= halftone_values
[i
%3];
181 entries
[i
] |= halftone_values
[(i
/3)%3] << 8;
182 entries
[i
] |= halftone_values
[(i
/9)%3] << 16;
185 entries
[i
++] = 0xffc0c0c0;
192 static WICColor
*generate_halftone64_palette(UINT
*count
, BOOL add_transparent
)
197 *count
= add_transparent
? 73 : 72;
198 entries
= HeapAlloc(GetProcessHeap(), 0, *count
* sizeof(WICColor
));
199 if (!entries
) return NULL
;
201 for (i
= 0; i
< 64; i
++)
203 static const BYTE halftone_values
[4] = { 0x00,0x55,0xaa,0xff };
204 entries
[i
] = 0xff000000;
205 entries
[i
] |= halftone_values
[i
%4];
206 entries
[i
] |= halftone_values
[(i
/4)%4] << 8;
207 entries
[i
] |= halftone_values
[(i
/16)%4] << 16;
210 for (i
= 64; i
< 72; i
++)
212 static const DWORD halftone
[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
213 0x000080, 0x808000, 0x800080, 0x008080 };
214 entries
[i
] = 0xff000000;
215 entries
[i
] |= halftone
[i
-64];
224 static WICColor
*generate_halftone125_palette(UINT
*count
, BOOL add_transparent
)
229 *count
= add_transparent
? 127 : 126;
230 entries
= HeapAlloc(GetProcessHeap(), 0, *count
* sizeof(WICColor
));
231 if (!entries
) return NULL
;
233 for (i
= 0; i
< 125; i
++)
235 static const BYTE halftone_values
[5] = { 0x00,0x40,0x80,0xbf,0xff };
236 entries
[i
] = 0xff000000;
237 entries
[i
] |= halftone_values
[i
%5];
238 entries
[i
] |= halftone_values
[(i
/5)%5] << 8;
239 entries
[i
] |= halftone_values
[(i
/25)%5] << 16;
242 entries
[i
++] = 0xffc0c0c0;
249 static WICColor
*generate_halftone216_palette(UINT
*count
, BOOL add_transparent
)
254 *count
= add_transparent
? 225 : 224;
255 entries
= HeapAlloc(GetProcessHeap(), 0, *count
* sizeof(WICColor
));
256 if (!entries
) return NULL
;
258 for (i
= 0; i
< 216; i
++)
260 static const BYTE halftone_values
[6] = { 0x00,0x33,0x66,0x99,0xcc,0xff };
261 entries
[i
] = 0xff000000;
262 entries
[i
] |= halftone_values
[i
%6];
263 entries
[i
] |= halftone_values
[(i
/6)%6] << 8;
264 entries
[i
] |= halftone_values
[(i
/36)%6] << 16;
267 for (i
= 216; i
< 224; i
++)
269 static const DWORD halftone
[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
270 0x000080, 0x808000, 0x800080, 0x008080 };
271 entries
[i
] = 0xff000000;
272 entries
[i
] |= halftone
[i
-216];
281 static WICColor
*generate_halftone252_palette(UINT
*count
, BOOL add_transparent
)
286 *count
= add_transparent
? 253 : 252;
287 entries
= HeapAlloc(GetProcessHeap(), 0, *count
* sizeof(WICColor
));
288 if (!entries
) return NULL
;
290 for (i
= 0; i
< 252; i
++)
292 static const BYTE halftone_values_rb
[6] = { 0x00,0x33,0x66,0x99,0xcc,0xff };
293 static const BYTE halftone_values_g
[7] = { 0x00,0x2b,0x55,0x80,0xaa,0xd5,0xff };
294 entries
[i
] = 0xff000000;
295 entries
[i
] |= halftone_values_rb
[i
%6];
296 entries
[i
] |= halftone_values_g
[(i
/6)%7] << 8;
297 entries
[i
] |= halftone_values_rb
[(i
/42)%6] << 16;
306 static WICColor
*generate_halftone256_palette(UINT
*count
, BOOL add_transparent
)
312 entries
= HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor
));
313 if (!entries
) return NULL
;
315 for (i
= 0; i
< 256; i
++)
317 static const BYTE halftone_values_b
[4] = { 0x00,0x55,0xaa,0xff };
318 static const BYTE halftone_values_gr
[8] = { 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff };
319 entries
[i
] = 0xff000000;
320 entries
[i
] |= halftone_values_b
[i
%4];
321 entries
[i
] |= halftone_values_gr
[(i
/4)%8] << 8;
322 entries
[i
] |= halftone_values_gr
[(i
/32)%8] << 16;
331 static HRESULT WINAPI
PaletteImpl_InitializePredefined(IWICPalette
*iface
,
332 WICBitmapPaletteType type
, BOOL add_transparent
)
334 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
338 TRACE("(%p,%u,%d)\n", iface
, type
, add_transparent
);
342 case WICBitmapPaletteTypeFixedBW
:
344 colors
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WICColor
));
345 if (!colors
) return E_OUTOFMEMORY
;
346 colors
[0] = 0xff000000;
347 colors
[1] = 0xffffffff;
350 case WICBitmapPaletteTypeFixedGray4
:
352 colors
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WICColor
));
353 if (!colors
) return E_OUTOFMEMORY
;
354 colors
[0] = 0xff000000;
355 colors
[1] = 0xff555555;
356 colors
[2] = 0xffaaaaaa;
357 colors
[3] = 0xffffffff;
360 case WICBitmapPaletteTypeFixedGray16
:
361 colors
= generate_gray16_palette(&count
);
362 if (!colors
) return E_OUTOFMEMORY
;
365 case WICBitmapPaletteTypeFixedGray256
:
366 colors
= generate_gray256_palette(&count
);
367 if (!colors
) return E_OUTOFMEMORY
;
370 case WICBitmapPaletteTypeFixedHalftone8
:
371 colors
= generate_halftone8_palette(&count
, add_transparent
);
372 if (!colors
) return E_OUTOFMEMORY
;
375 case WICBitmapPaletteTypeFixedHalftone27
:
376 colors
= generate_halftone27_palette(&count
, add_transparent
);
377 if (!colors
) return E_OUTOFMEMORY
;
380 case WICBitmapPaletteTypeFixedHalftone64
:
381 colors
= generate_halftone64_palette(&count
, add_transparent
);
382 if (!colors
) return E_OUTOFMEMORY
;
385 case WICBitmapPaletteTypeFixedHalftone125
:
386 colors
= generate_halftone125_palette(&count
, add_transparent
);
387 if (!colors
) return E_OUTOFMEMORY
;
390 case WICBitmapPaletteTypeFixedHalftone216
:
391 colors
= generate_halftone216_palette(&count
, add_transparent
);
392 if (!colors
) return E_OUTOFMEMORY
;
395 case WICBitmapPaletteTypeFixedHalftone252
:
396 colors
= generate_halftone252_palette(&count
, add_transparent
);
397 if (!colors
) return E_OUTOFMEMORY
;
400 case WICBitmapPaletteTypeFixedHalftone256
:
401 colors
= generate_halftone256_palette(&count
, add_transparent
);
402 if (!colors
) return E_OUTOFMEMORY
;
406 WARN("invalid palette type %u\n", type
);
410 EnterCriticalSection(&This
->lock
);
411 HeapFree(GetProcessHeap(), 0, This
->colors
);
412 This
->colors
= colors
;
415 LeaveCriticalSection(&This
->lock
);
420 static HRESULT WINAPI
PaletteImpl_InitializeCustom(IWICPalette
*iface
,
421 WICColor
*pColors
, UINT colorCount
)
423 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
424 WICColor
*new_colors
;
426 TRACE("(%p,%p,%u)\n", iface
, pColors
, colorCount
);
434 if (!pColors
) return E_INVALIDARG
;
435 new_colors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * colorCount
);
436 if (!new_colors
) return E_OUTOFMEMORY
;
437 memcpy(new_colors
, pColors
, sizeof(WICColor
) * colorCount
);
440 EnterCriticalSection(&This
->lock
);
441 HeapFree(GetProcessHeap(), 0, This
->colors
);
442 This
->colors
= new_colors
;
443 This
->count
= colorCount
;
444 This
->type
= WICBitmapPaletteTypeCustom
;
445 LeaveCriticalSection(&This
->lock
);
450 #define R_COUNT (1 << 5)
451 #define R_SHIFT (8 - 5)
454 #define G_COUNT (1 << 6)
455 #define G_SHIFT (8 - 6)
458 #define B_COUNT (1 << 5)
459 #define B_SHIFT (8 - 5)
464 unsigned int data
[R_COUNT
][G_COUNT
][B_COUNT
];
476 /* count nonzero elements in the histogram range [r_min, r_max] x [g_min, g_max] x [b_min, b_max] */
477 static inline unsigned int histogram_count(struct histogram
*h
, int r_min
, int r_max
,
478 int g_min
, int g_max
, int b_min
, int b_max
)
480 unsigned int count
= 0;
482 for (r
= r_min
; r
<= r_max
; r
++)
483 for (g
= g_min
; g
<= g_max
; g
++)
484 for (b
= b_min
; b
<= b_max
; b
++)
485 if (h
->data
[r
][g
][b
] != 0) count
++;
489 /* compute weighted average color in the range [r_min, r_max] x [g_min, g_max] x [b_min, b_max] */
490 static unsigned int histogram_color(struct histogram
*h
, int r_min
, int r_max
,
491 int g_min
, int g_max
, int b_min
, int b_max
)
493 unsigned long long r_sum
= 0, g_sum
= 0, b_sum
= 0;
494 unsigned int tmp
, count
= 0;
497 for (r
= r_min
; r
<= r_max
; r
++)
498 for (g
= g_min
; g
<= g_max
; g
++)
499 for (b
= b_min
; b
<= b_max
; b
++)
501 if (!(tmp
= h
->data
[r
][g
][b
])) continue;
502 r_sum
+= ((r
<< R_SHIFT
) + ((1 << R_SHIFT
) / 2)) * tmp
;
503 g_sum
+= ((g
<< G_SHIFT
) + ((1 << G_SHIFT
) / 2)) * tmp
;
504 b_sum
+= ((b
<< B_SHIFT
) + ((1 << B_SHIFT
) / 2)) * tmp
;
508 return ((b_sum
+ (count
/ 2)) / count
) |
509 ((g_sum
+ (count
/ 2)) / count
) << 8 |
510 ((r_sum
+ (count
/ 2)) / count
) << 16 | 0xff000000;
513 /* same as histogram_count */
514 static inline unsigned int box_count(struct histogram
*h
, struct box
*b
)
516 return histogram_count(h
, b
->r_min
, b
->r_max
, b
->g_min
, b
->g_max
, b
->b_min
, b
->b_max
);
519 /* same as histogram_color */
520 static inline unsigned int box_color(struct histogram
*h
, struct box
*b
)
522 return histogram_color(h
, b
->r_min
, b
->r_max
, b
->g_min
, b
->g_max
, b
->b_min
, b
->b_max
);
525 /* compute score used to determine best split (also called "volume") */
526 static inline unsigned int box_score(struct box
*b
)
528 unsigned int tmp
, sum
= 0;
529 tmp
= ((b
->r_max
- b
->r_min
) << R_SHIFT
) * R_SCALE
; sum
+= tmp
* tmp
;
530 tmp
= ((b
->g_max
- b
->g_min
) << G_SHIFT
) * G_SCALE
; sum
+= tmp
* tmp
;
531 tmp
= ((b
->b_max
- b
->b_min
) << B_SHIFT
) * B_SCALE
; sum
+= tmp
* tmp
;
535 /* attempt to shrink a box */
536 static void shrink_box(struct histogram
*h
, struct box
*b
)
539 for (i
= b
->r_min
; i
<= b
->r_max
; i
++)
540 if (histogram_count(h
, i
, i
, b
->g_min
, b
->g_max
, b
->b_min
, b
->b_max
)) { b
->r_min
= i
; break; }
541 for (i
= b
->r_max
; i
>= b
->r_min
; i
--)
542 if (histogram_count(h
, i
, i
, b
->g_min
, b
->g_max
, b
->b_min
, b
->b_max
)) { b
->r_max
= i
; break; }
543 for (i
= b
->g_min
; i
<= b
->g_max
; i
++)
544 if (histogram_count(h
, b
->r_min
, b
->r_max
, i
, i
, b
->b_min
, b
->b_max
)) { b
->g_min
= i
; break; }
545 for (i
= b
->g_max
; i
>= b
->g_min
; i
--)
546 if (histogram_count(h
, b
->r_min
, b
->r_max
, i
, i
, b
->b_min
, b
->b_max
)) { b
->g_max
= i
; break; }
547 for (i
= b
->b_min
; i
<= b
->b_max
; i
++)
548 if (histogram_count(h
, b
->r_min
, b
->r_max
, b
->g_min
, b
->g_max
, i
, i
)) { b
->b_min
= i
; break; }
549 for (i
= b
->b_max
; i
>= b
->b_min
; i
--)
550 if (histogram_count(h
, b
->r_min
, b
->r_max
, b
->g_min
, b
->g_max
, i
, i
)) { b
->b_max
= i
; break; }
551 b
->count
= box_count(h
, b
);
552 b
->score
= box_score(b
);
555 /* helper for split_box */
556 static inline void set_avg(int *min
, int *max
)
558 int avg
= (*min
+ *max
) / 2;
563 /* split a box based on the best axis */
564 static void split_box(struct histogram
*h
, struct box
*b1
, struct box
*b2
)
566 int r
= ((b1
->r_max
- b1
->r_min
) << R_SHIFT
) * R_SCALE
;
567 int g
= ((b1
->g_max
- b1
->g_min
) << G_SHIFT
) * G_SCALE
;
568 int b
= ((b1
->b_max
- b1
->b_min
) << B_SHIFT
) * B_SCALE
;
574 if (b
> r
) set_avg(&b1
->b_min
, &b2
->b_max
);
575 else set_avg(&b1
->r_min
, &b2
->r_max
);
579 if (b
> g
) set_avg(&b1
->b_min
, &b2
->b_max
);
580 else set_avg(&b1
->g_min
, &b2
->g_max
);
587 /* find box suitable for split based on count */
588 static struct box
*find_box_max_count(struct box
*b
, int count
)
590 struct box
*best
= NULL
;
592 if (b
->score
&& (!best
|| b
->count
> best
->count
)) best
= b
;
596 /* find box suitable for split based on score */
597 static struct box
*find_box_max_score(struct box
*b
, int count
)
599 struct box
*best
= NULL
;
601 if (b
->score
&& (!best
|| b
->score
> best
->score
)) best
= b
;
605 /* compute color map with at most 'desired' colors
606 * image must be in 24bpp BGR format and colors are returned in 0xAARRGGBB format */
607 static int median_cut(unsigned char *image
, unsigned int width
, unsigned int height
,
608 unsigned int stride
, int desired
, unsigned int *colors
)
610 struct box boxes
[256];
617 if (!(h
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*h
))))
620 for (y
= 0; y
< height
; y
++)
621 for (x
= 0, p
= image
+ y
* stride
; x
< width
; x
++, p
+= 3)
622 h
->data
[p
[2] >> R_SHIFT
][p
[1] >> G_SHIFT
][p
[0] >> B_SHIFT
]++;
625 boxes
[0].r_min
= 0; boxes
[0].r_max
= R_COUNT
- 1;
626 boxes
[0].g_min
= 0; boxes
[0].g_max
= G_COUNT
- 1;
627 boxes
[0].b_min
= 0; boxes
[0].b_max
= B_COUNT
- 1;
628 shrink_box(h
, &boxes
[0]);
630 while (numboxes
<= desired
/ 2)
632 if (!(b1
= find_box_max_count(boxes
, numboxes
))) break;
633 b2
= &boxes
[numboxes
++];
634 split_box(h
, b1
, b2
);
636 while (numboxes
< desired
)
638 if (!(b1
= find_box_max_score(boxes
, numboxes
))) break;
639 b2
= &boxes
[numboxes
++];
640 split_box(h
, b1
, b2
);
643 for (i
= 0; i
< numboxes
; i
++)
644 colors
[i
] = box_color(h
, &boxes
[i
]);
646 HeapFree(GetProcessHeap(), 0, h
);
651 static HRESULT WINAPI
PaletteImpl_InitializeFromBitmap(IWICPalette
*palette
,
652 IWICBitmapSource
*source
, UINT desired
, BOOL add_transparent
)
654 IWICImagingFactory
*factory
= NULL
;
655 IWICBitmap
*rgb24_bitmap
= NULL
;
656 IWICBitmapSource
*rgb24_source
;
657 IWICBitmapLock
*lock
= NULL
;
658 WICPixelFormatGUID format
;
660 UINT width
, height
, stride
, size
, actual_number_of_colors
;
662 WICColor colors
[256];
664 TRACE("(%p,%p,%u,%d)\n", palette
, source
, desired
, add_transparent
);
666 if (!source
|| desired
< 2 || desired
> 256)
669 hr
= IWICBitmapSource_GetPixelFormat(source
, &format
);
670 if (hr
!= S_OK
) return hr
;
672 /* For interoperability with gdiplus where PixelFormat24bppRGB is actually stored
673 * as BGR (and there is no corresponding RGB format), we have to use 24bppBGR
674 * to avoid format conversions.
676 if (!IsEqualGUID(&format
, &GUID_WICPixelFormat24bppBGR
))
678 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat24bppBGR
, source
, &rgb24_source
);
679 if (hr
!= S_OK
) return hr
;
682 rgb24_source
= source
;
684 hr
= ImagingFactory_CreateInstance(&IID_IWICImagingFactory
, (void **)&factory
);
685 if (hr
!= S_OK
) goto fail
;
687 hr
= IWICImagingFactory_CreateBitmapFromSource(factory
, rgb24_source
, WICBitmapCacheOnLoad
, &rgb24_bitmap
);
688 if (hr
!= S_OK
) goto fail
;
690 hr
= IWICBitmap_Lock(rgb24_bitmap
, NULL
, WICBitmapLockRead
, &lock
);
691 if (hr
!= S_OK
) goto fail
;
693 IWICBitmapLock_GetSize(lock
, &width
, &height
);
694 IWICBitmapLock_GetStride(lock
, &stride
);
695 IWICBitmapLock_GetDataPointer(lock
, &size
, &src
);
697 actual_number_of_colors
= median_cut(src
, width
, height
, stride
, add_transparent
? desired
- 1 : desired
, colors
);
698 TRACE("actual number of colors: %u\n", actual_number_of_colors
);
700 if (actual_number_of_colors
)
702 if (add_transparent
) colors
[actual_number_of_colors
++] = 0;
704 hr
= IWICPalette_InitializeCustom(palette
, colors
, actual_number_of_colors
);
711 IWICBitmapLock_Release(lock
);
714 IWICBitmap_Release(rgb24_bitmap
);
717 IWICImagingFactory_Release(factory
);
719 if (rgb24_source
!= source
)
720 IWICBitmapSource_Release(rgb24_source
);
725 static HRESULT WINAPI
PaletteImpl_InitializeFromPalette(IWICPalette
*iface
,
728 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
730 WICColor
*colors
= NULL
;
731 WICBitmapPaletteType type
;
734 TRACE("(%p,%p)\n", iface
, source
);
736 if (!source
) return E_INVALIDARG
;
738 hr
= IWICPalette_GetType(source
, &type
);
739 if (hr
!= S_OK
) return hr
;
740 hr
= IWICPalette_GetColorCount(source
, &count
);
741 if (hr
!= S_OK
) return hr
;
744 colors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * count
);
745 if (!colors
) return E_OUTOFMEMORY
;
746 hr
= IWICPalette_GetColors(source
, count
, colors
, &count
);
749 HeapFree(GetProcessHeap(), 0, colors
);
754 EnterCriticalSection(&This
->lock
);
755 HeapFree(GetProcessHeap(), 0, This
->colors
);
756 This
->colors
= colors
;
759 LeaveCriticalSection(&This
->lock
);
764 static HRESULT WINAPI
PaletteImpl_GetType(IWICPalette
*iface
,
765 WICBitmapPaletteType
*pePaletteType
)
767 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
769 TRACE("(%p,%p)\n", iface
, pePaletteType
);
771 if (!pePaletteType
) return E_INVALIDARG
;
773 EnterCriticalSection(&This
->lock
);
774 *pePaletteType
= This
->type
;
775 LeaveCriticalSection(&This
->lock
);
780 static HRESULT WINAPI
PaletteImpl_GetColorCount(IWICPalette
*iface
, UINT
*pcCount
)
782 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
784 TRACE("(%p,%p)\n", iface
, pcCount
);
786 if (!pcCount
) return E_INVALIDARG
;
788 EnterCriticalSection(&This
->lock
);
789 *pcCount
= This
->count
;
790 LeaveCriticalSection(&This
->lock
);
795 static HRESULT WINAPI
PaletteImpl_GetColors(IWICPalette
*iface
, UINT colorCount
,
796 WICColor
*pColors
, UINT
*pcActualColors
)
798 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
800 TRACE("(%p,%i,%p,%p)\n", iface
, colorCount
, pColors
, pcActualColors
);
802 if (!pColors
|| !pcActualColors
) return E_INVALIDARG
;
804 EnterCriticalSection(&This
->lock
);
806 if (This
->count
< colorCount
) colorCount
= This
->count
;
808 memcpy(pColors
, This
->colors
, sizeof(WICColor
) * colorCount
);
810 *pcActualColors
= colorCount
;
812 LeaveCriticalSection(&This
->lock
);
817 static HRESULT WINAPI
PaletteImpl_IsBlackWhite(IWICPalette
*iface
, BOOL
*pfIsBlackWhite
)
819 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
821 TRACE("(%p,%p)\n", iface
, pfIsBlackWhite
);
823 if (!pfIsBlackWhite
) return E_INVALIDARG
;
825 EnterCriticalSection(&This
->lock
);
826 if (This
->type
== WICBitmapPaletteTypeFixedBW
)
827 *pfIsBlackWhite
= TRUE
;
829 *pfIsBlackWhite
= FALSE
;
830 LeaveCriticalSection(&This
->lock
);
835 static HRESULT WINAPI
PaletteImpl_IsGrayscale(IWICPalette
*iface
, BOOL
*pfIsGrayscale
)
837 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
839 TRACE("(%p,%p)\n", iface
, pfIsGrayscale
);
841 if (!pfIsGrayscale
) return E_INVALIDARG
;
843 EnterCriticalSection(&This
->lock
);
846 case WICBitmapPaletteTypeFixedBW
:
847 case WICBitmapPaletteTypeFixedGray4
:
848 case WICBitmapPaletteTypeFixedGray16
:
849 case WICBitmapPaletteTypeFixedGray256
:
850 *pfIsGrayscale
= TRUE
;
853 *pfIsGrayscale
= FALSE
;
855 LeaveCriticalSection(&This
->lock
);
860 static HRESULT WINAPI
PaletteImpl_HasAlpha(IWICPalette
*iface
, BOOL
*pfHasAlpha
)
862 PaletteImpl
*This
= impl_from_IWICPalette(iface
);
865 TRACE("(%p,%p)\n", iface
, pfHasAlpha
);
867 if (!pfHasAlpha
) return E_INVALIDARG
;
871 EnterCriticalSection(&This
->lock
);
872 for (i
=0; i
<This
->count
; i
++)
873 if ((This
->colors
[i
]&0xff000000) != 0xff000000)
878 LeaveCriticalSection(&This
->lock
);
883 static const IWICPaletteVtbl PaletteImpl_Vtbl
= {
884 PaletteImpl_QueryInterface
,
887 PaletteImpl_InitializePredefined
,
888 PaletteImpl_InitializeCustom
,
889 PaletteImpl_InitializeFromBitmap
,
890 PaletteImpl_InitializeFromPalette
,
892 PaletteImpl_GetColorCount
,
893 PaletteImpl_GetColors
,
894 PaletteImpl_IsBlackWhite
,
895 PaletteImpl_IsGrayscale
,
899 HRESULT
PaletteImpl_Create(IWICPalette
**palette
)
903 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(PaletteImpl
));
904 if (!This
) return E_OUTOFMEMORY
;
906 This
->IWICPalette_iface
.lpVtbl
= &PaletteImpl_Vtbl
;
910 This
->type
= WICBitmapPaletteTypeCustom
;
911 InitializeCriticalSection(&This
->lock
);
912 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PaletteImpl.lock");
914 *palette
= &This
->IWICPalette_iface
;