* Sync up to trunk HEAD (r62286).
[reactos.git] / dll / win32 / windowscodecs / palette.c
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2012 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 "wincodecs_private.h"
21
22 typedef struct {
23 IWICPalette IWICPalette_iface;
24 LONG ref;
25 UINT count;
26 WICColor *colors;
27 WICBitmapPaletteType type;
28 CRITICAL_SECTION lock; /* must be held when count, colors, or type is accessed */
29 } PaletteImpl;
30
31 static inline PaletteImpl *impl_from_IWICPalette(IWICPalette *iface)
32 {
33 return CONTAINING_RECORD(iface, PaletteImpl, IWICPalette_iface);
34 }
35
36 static HRESULT WINAPI PaletteImpl_QueryInterface(IWICPalette *iface, REFIID iid,
37 void **ppv)
38 {
39 PaletteImpl *This = impl_from_IWICPalette(iface);
40 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
41
42 if (!ppv) return E_INVALIDARG;
43
44 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICPalette, iid))
45 {
46 *ppv = &This->IWICPalette_iface;
47 }
48 else
49 {
50 *ppv = NULL;
51 return E_NOINTERFACE;
52 }
53
54 IUnknown_AddRef((IUnknown*)*ppv);
55 return S_OK;
56 }
57
58 static ULONG WINAPI PaletteImpl_AddRef(IWICPalette *iface)
59 {
60 PaletteImpl *This = impl_from_IWICPalette(iface);
61 ULONG ref = InterlockedIncrement(&This->ref);
62
63 TRACE("(%p) refcount=%u\n", iface, ref);
64
65 return ref;
66 }
67
68 static ULONG WINAPI PaletteImpl_Release(IWICPalette *iface)
69 {
70 PaletteImpl *This = impl_from_IWICPalette(iface);
71 ULONG ref = InterlockedDecrement(&This->ref);
72
73 TRACE("(%p) refcount=%u\n", iface, ref);
74
75 if (ref == 0)
76 {
77 This->lock.DebugInfo->Spare[0] = 0;
78 DeleteCriticalSection(&This->lock);
79 HeapFree(GetProcessHeap(), 0, This->colors);
80 HeapFree(GetProcessHeap(), 0, This);
81 }
82
83 return ref;
84 }
85
86 static WICColor *generate_gray16_palette(UINT *count)
87 {
88 WICColor *entries;
89 UINT i;
90
91 *count = 16;
92 entries = HeapAlloc(GetProcessHeap(), 0, 16 * sizeof(WICColor));
93 if (!entries) return NULL;
94
95 for (i = 0; i < 16; i++)
96 {
97 entries[i] = 0xff000000;
98 entries[i] |= (i<<20) | (i<<16) | (i<<12) | (i<<8) | (i<<4) | i;
99 }
100 return entries;
101 }
102
103 static WICColor *generate_gray256_palette(UINT *count)
104 {
105 WICColor *entries;
106 UINT i;
107
108 *count = 256;
109 entries = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor));
110 if (!entries) return NULL;
111
112 for (i = 0; i < 256; i++)
113 {
114 entries[i] = 0xff000000;
115 entries[i] |= (i<<16) | (i<<8) | i;
116 }
117 return entries;
118 }
119
120 static WICColor *generate_halftone8_palette(UINT *count, BOOL add_transparent)
121 {
122 WICColor *entries;
123 UINT i;
124
125 *count = add_transparent ? 17 : 16;
126 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
127 if (!entries) return NULL;
128
129 for (i = 0; i < 8; i++)
130 {
131 entries[i] = 0xff000000;
132 if (i & 1) entries[i] |= 0xff;
133 if (i & 2) entries[i] |= 0xff00;
134 if (i & 4) entries[i] |= 0xff0000;
135 }
136
137 for (i = 8; i < 16; i++)
138 {
139 static const DWORD halftone[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
140 0x000080, 0x808000, 0x800080, 0x008080 };
141 entries[i] = 0xff000000;
142 entries[i] |= halftone[i-8];
143 }
144
145 if (add_transparent)
146 entries[i] = 0;
147
148 return entries;
149 }
150
151 static WICColor *generate_halftone27_palette(UINT *count, BOOL add_transparent)
152 {
153 WICColor *entries;
154 UINT i;
155
156 *count = add_transparent ? 29 : 28;
157 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
158 if (!entries) return NULL;
159
160 for (i = 0; i < 27; i++)
161 {
162 static const BYTE halftone_values[4] = { 0x00,0x80,0xff };
163 entries[i] = 0xff000000;
164 entries[i] |= halftone_values[i%3];
165 entries[i] |= halftone_values[(i/3)%3] << 8;
166 entries[i] |= halftone_values[(i/9)%3] << 16;
167 }
168
169 entries[i++] = 0xffc0c0c0;
170 if (add_transparent)
171 entries[i] = 0;
172
173 return entries;
174 }
175
176 static WICColor *generate_halftone64_palette(UINT *count, BOOL add_transparent)
177 {
178 WICColor *entries;
179 UINT i;
180
181 *count = add_transparent ? 73 : 72;
182 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
183 if (!entries) return NULL;
184
185 for (i = 0; i < 64; i++)
186 {
187 static const BYTE halftone_values[4] = { 0x00,0x55,0xaa,0xff };
188 entries[i] = 0xff000000;
189 entries[i] |= halftone_values[i%4];
190 entries[i] |= halftone_values[(i/4)%4] << 8;
191 entries[i] |= halftone_values[(i/16)%4] << 16;
192 }
193
194 for (i = 64; i < 72; i++)
195 {
196 static const DWORD halftone[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
197 0x000080, 0x808000, 0x800080, 0x008080 };
198 entries[i] = 0xff000000;
199 entries[i] |= halftone[i-64];
200 }
201
202 if (add_transparent)
203 entries[i] = 0;
204
205 return entries;
206 }
207
208 static WICColor *generate_halftone125_palette(UINT *count, BOOL add_transparent)
209 {
210 WICColor *entries;
211 UINT i;
212
213 *count = add_transparent ? 127 : 126;
214 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
215 if (!entries) return NULL;
216
217 for (i = 0; i < 125; i++)
218 {
219 static const BYTE halftone_values[5] = { 0x00,0x40,0x80,0xbf,0xff };
220 entries[i] = 0xff000000;
221 entries[i] |= halftone_values[i%5];
222 entries[i] |= halftone_values[(i/5)%5] << 8;
223 entries[i] |= halftone_values[(i/25)%5] << 16;
224 }
225
226 entries[i++] = 0xffc0c0c0;
227 if (add_transparent)
228 entries[i] = 0;
229
230 return entries;
231 }
232
233 static WICColor *generate_halftone216_palette(UINT *count, BOOL add_transparent)
234 {
235 WICColor *entries;
236 UINT i;
237
238 *count = add_transparent ? 225 : 224;
239 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
240 if (!entries) return NULL;
241
242 for (i = 0; i < 216; i++)
243 {
244 static const BYTE halftone_values[6] = { 0x00,0x33,0x66,0x99,0xcc,0xff };
245 entries[i] = 0xff000000;
246 entries[i] |= halftone_values[i%6];
247 entries[i] |= halftone_values[(i/6)%6] << 8;
248 entries[i] |= halftone_values[(i/36)%6] << 16;
249 }
250
251 for (i = 216; i < 224; i++)
252 {
253 static const DWORD halftone[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
254 0x000080, 0x808000, 0x800080, 0x008080 };
255 entries[i] = 0xff000000;
256 entries[i] |= halftone[i-216];
257 }
258
259 if (add_transparent)
260 entries[i] = 0;
261
262 return entries;
263 }
264
265 static WICColor *generate_halftone252_palette(UINT *count, BOOL add_transparent)
266 {
267 WICColor *entries;
268 UINT i;
269
270 *count = add_transparent ? 253 : 252;
271 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
272 if (!entries) return NULL;
273
274 for (i = 0; i < 252; i++)
275 {
276 static const BYTE halftone_values_rb[6] = { 0x00,0x33,0x66,0x99,0xcc,0xff };
277 static const BYTE halftone_values_g[7] = { 0x00,0x2b,0x55,0x80,0xaa,0xd5,0xff };
278 entries[i] = 0xff000000;
279 entries[i] |= halftone_values_rb[i%6];
280 entries[i] |= halftone_values_g[(i/6)%7] << 8;
281 entries[i] |= halftone_values_rb[(i/42)%6] << 16;
282 }
283
284 if (add_transparent)
285 entries[i] = 0;
286
287 return entries;
288 }
289
290 static WICColor *generate_halftone256_palette(UINT *count, BOOL add_transparent)
291 {
292 WICColor *entries;
293 UINT i;
294
295 *count = 256;
296 entries = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor));
297 if (!entries) return NULL;
298
299 for (i = 0; i < 256; i++)
300 {
301 static const BYTE halftone_values_b[4] = { 0x00,0x55,0xaa,0xff };
302 static const BYTE halftone_values_gr[8] = { 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff };
303 entries[i] = 0xff000000;
304 entries[i] |= halftone_values_b[i%4];
305 entries[i] |= halftone_values_gr[(i/4)%8] << 8;
306 entries[i] |= halftone_values_gr[(i/32)%8] << 16;
307 }
308
309 if (add_transparent)
310 entries[255] = 0;
311
312 return entries;
313 }
314
315 static HRESULT WINAPI PaletteImpl_InitializePredefined(IWICPalette *iface,
316 WICBitmapPaletteType type, BOOL add_transparent)
317 {
318 PaletteImpl *This = impl_from_IWICPalette(iface);
319 WICColor *colors;
320 UINT count;
321
322 TRACE("(%p,%u,%d)\n", iface, type, add_transparent);
323
324 switch (type)
325 {
326 case WICBitmapPaletteTypeFixedBW:
327 count = 2;
328 colors = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WICColor));
329 if (!colors) return E_OUTOFMEMORY;
330 colors[0] = 0xff000000;
331 colors[1] = 0xffffffff;
332 break;
333
334 case WICBitmapPaletteTypeFixedGray4:
335 count = 4;
336 colors = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WICColor));
337 if (!colors) return E_OUTOFMEMORY;
338 colors[0] = 0xff000000;
339 colors[1] = 0xff555555;
340 colors[2] = 0xffaaaaaa;
341 colors[3] = 0xffffffff;
342 break;
343
344 case WICBitmapPaletteTypeFixedGray16:
345 colors = generate_gray16_palette(&count);
346 if (!colors) return E_OUTOFMEMORY;
347 break;
348
349 case WICBitmapPaletteTypeFixedGray256:
350 colors = generate_gray256_palette(&count);
351 if (!colors) return E_OUTOFMEMORY;
352 break;
353
354 case WICBitmapPaletteTypeFixedHalftone8:
355 colors = generate_halftone8_palette(&count, add_transparent);
356 if (!colors) return E_OUTOFMEMORY;
357 break;
358
359 case WICBitmapPaletteTypeFixedHalftone27:
360 colors = generate_halftone27_palette(&count, add_transparent);
361 if (!colors) return E_OUTOFMEMORY;
362 break;
363
364 case WICBitmapPaletteTypeFixedHalftone64:
365 colors = generate_halftone64_palette(&count, add_transparent);
366 if (!colors) return E_OUTOFMEMORY;
367 break;
368
369 case WICBitmapPaletteTypeFixedHalftone125:
370 colors = generate_halftone125_palette(&count, add_transparent);
371 if (!colors) return E_OUTOFMEMORY;
372 break;
373
374 case WICBitmapPaletteTypeFixedHalftone216:
375 colors = generate_halftone216_palette(&count, add_transparent);
376 if (!colors) return E_OUTOFMEMORY;
377 break;
378
379 case WICBitmapPaletteTypeFixedHalftone252:
380 colors = generate_halftone252_palette(&count, add_transparent);
381 if (!colors) return E_OUTOFMEMORY;
382 break;
383
384 case WICBitmapPaletteTypeFixedHalftone256:
385 colors = generate_halftone256_palette(&count, add_transparent);
386 if (!colors) return E_OUTOFMEMORY;
387 break;
388
389 default:
390 WARN("invalid palette type %u\n", type);
391 return E_INVALIDARG;
392 }
393
394 EnterCriticalSection(&This->lock);
395 HeapFree(GetProcessHeap(), 0, This->colors);
396 This->colors = colors;
397 This->count = count;
398 This->type = type;
399 LeaveCriticalSection(&This->lock);
400
401 return S_OK;
402 }
403
404 static HRESULT WINAPI PaletteImpl_InitializeCustom(IWICPalette *iface,
405 WICColor *pColors, UINT colorCount)
406 {
407 PaletteImpl *This = impl_from_IWICPalette(iface);
408 WICColor *new_colors;
409
410 TRACE("(%p,%p,%u)\n", iface, pColors, colorCount);
411
412 if (colorCount == 0)
413 {
414 new_colors = NULL;
415 }
416 else
417 {
418 if (!pColors) return E_INVALIDARG;
419 new_colors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * colorCount);
420 if (!new_colors) return E_OUTOFMEMORY;
421 memcpy(new_colors, pColors, sizeof(WICColor) * colorCount);
422 }
423
424 EnterCriticalSection(&This->lock);
425 HeapFree(GetProcessHeap(), 0, This->colors);
426 This->colors = new_colors;
427 This->count = colorCount;
428 This->type = WICBitmapPaletteTypeCustom;
429 LeaveCriticalSection(&This->lock);
430
431 return S_OK;
432 }
433
434 static HRESULT WINAPI PaletteImpl_InitializeFromBitmap(IWICPalette *iface,
435 IWICBitmapSource *pISurface, UINT colorCount, BOOL fAddTransparentColor)
436 {
437 FIXME("(%p,%p,%u,%i): stub\n", iface, pISurface, colorCount, fAddTransparentColor);
438 return E_NOTIMPL;
439 }
440
441 static HRESULT WINAPI PaletteImpl_InitializeFromPalette(IWICPalette *iface,
442 IWICPalette *source)
443 {
444 PaletteImpl *This = impl_from_IWICPalette(iface);
445 UINT count;
446 WICColor *colors = NULL;
447 WICBitmapPaletteType type;
448 HRESULT hr;
449
450 TRACE("(%p,%p)\n", iface, source);
451
452 if (!source) return E_INVALIDARG;
453
454 hr = IWICPalette_GetType(source, &type);
455 if (hr != S_OK) return hr;
456 hr = IWICPalette_GetColorCount(source, &count);
457 if (hr != S_OK) return hr;
458 if (count)
459 {
460 colors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count);
461 if (!colors) return E_OUTOFMEMORY;
462 hr = IWICPalette_GetColors(source, count, colors, &count);
463 if (hr != S_OK)
464 {
465 HeapFree(GetProcessHeap(), 0, colors);
466 return hr;
467 }
468 }
469
470 EnterCriticalSection(&This->lock);
471 HeapFree(GetProcessHeap(), 0, This->colors);
472 This->colors = colors;
473 This->count = count;
474 This->type = type;
475 LeaveCriticalSection(&This->lock);
476
477 return S_OK;
478 }
479
480 static HRESULT WINAPI PaletteImpl_GetType(IWICPalette *iface,
481 WICBitmapPaletteType *pePaletteType)
482 {
483 PaletteImpl *This = impl_from_IWICPalette(iface);
484
485 TRACE("(%p,%p)\n", iface, pePaletteType);
486
487 if (!pePaletteType) return E_INVALIDARG;
488
489 EnterCriticalSection(&This->lock);
490 *pePaletteType = This->type;
491 LeaveCriticalSection(&This->lock);
492
493 return S_OK;
494 }
495
496 static HRESULT WINAPI PaletteImpl_GetColorCount(IWICPalette *iface, UINT *pcCount)
497 {
498 PaletteImpl *This = impl_from_IWICPalette(iface);
499
500 TRACE("(%p,%p)\n", iface, pcCount);
501
502 if (!pcCount) return E_INVALIDARG;
503
504 EnterCriticalSection(&This->lock);
505 *pcCount = This->count;
506 LeaveCriticalSection(&This->lock);
507
508 return S_OK;
509 }
510
511 static HRESULT WINAPI PaletteImpl_GetColors(IWICPalette *iface, UINT colorCount,
512 WICColor *pColors, UINT *pcActualColors)
513 {
514 PaletteImpl *This = impl_from_IWICPalette(iface);
515
516 TRACE("(%p,%i,%p,%p)\n", iface, colorCount, pColors, pcActualColors);
517
518 if (!pColors || !pcActualColors) return E_INVALIDARG;
519
520 EnterCriticalSection(&This->lock);
521
522 if (This->count < colorCount) colorCount = This->count;
523
524 memcpy(pColors, This->colors, sizeof(WICColor) * colorCount);
525
526 *pcActualColors = colorCount;
527
528 LeaveCriticalSection(&This->lock);
529
530 return S_OK;
531 }
532
533 static HRESULT WINAPI PaletteImpl_IsBlackWhite(IWICPalette *iface, BOOL *pfIsBlackWhite)
534 {
535 PaletteImpl *This = impl_from_IWICPalette(iface);
536
537 TRACE("(%p,%p)\n", iface, pfIsBlackWhite);
538
539 if (!pfIsBlackWhite) return E_INVALIDARG;
540
541 EnterCriticalSection(&This->lock);
542 if (This->type == WICBitmapPaletteTypeFixedBW)
543 *pfIsBlackWhite = TRUE;
544 else
545 *pfIsBlackWhite = FALSE;
546 LeaveCriticalSection(&This->lock);
547
548 return S_OK;
549 }
550
551 static HRESULT WINAPI PaletteImpl_IsGrayscale(IWICPalette *iface, BOOL *pfIsGrayscale)
552 {
553 PaletteImpl *This = impl_from_IWICPalette(iface);
554
555 TRACE("(%p,%p)\n", iface, pfIsGrayscale);
556
557 if (!pfIsGrayscale) return E_INVALIDARG;
558
559 EnterCriticalSection(&This->lock);
560 switch(This->type)
561 {
562 case WICBitmapPaletteTypeFixedBW:
563 case WICBitmapPaletteTypeFixedGray4:
564 case WICBitmapPaletteTypeFixedGray16:
565 case WICBitmapPaletteTypeFixedGray256:
566 *pfIsGrayscale = TRUE;
567 break;
568 default:
569 *pfIsGrayscale = FALSE;
570 }
571 LeaveCriticalSection(&This->lock);
572
573 return S_OK;
574 }
575
576 static HRESULT WINAPI PaletteImpl_HasAlpha(IWICPalette *iface, BOOL *pfHasAlpha)
577 {
578 PaletteImpl *This = impl_from_IWICPalette(iface);
579 UINT i;
580
581 TRACE("(%p,%p)\n", iface, pfHasAlpha);
582
583 if (!pfHasAlpha) return E_INVALIDARG;
584
585 *pfHasAlpha = FALSE;
586
587 EnterCriticalSection(&This->lock);
588 for (i=0; i<This->count; i++)
589 if ((This->colors[i]&0xff000000) != 0xff000000)
590 {
591 *pfHasAlpha = TRUE;
592 break;
593 }
594 LeaveCriticalSection(&This->lock);
595
596 return S_OK;
597 }
598
599 static const IWICPaletteVtbl PaletteImpl_Vtbl = {
600 PaletteImpl_QueryInterface,
601 PaletteImpl_AddRef,
602 PaletteImpl_Release,
603 PaletteImpl_InitializePredefined,
604 PaletteImpl_InitializeCustom,
605 PaletteImpl_InitializeFromBitmap,
606 PaletteImpl_InitializeFromPalette,
607 PaletteImpl_GetType,
608 PaletteImpl_GetColorCount,
609 PaletteImpl_GetColors,
610 PaletteImpl_IsBlackWhite,
611 PaletteImpl_IsGrayscale,
612 PaletteImpl_HasAlpha
613 };
614
615 HRESULT PaletteImpl_Create(IWICPalette **palette)
616 {
617 PaletteImpl *This;
618
619 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PaletteImpl));
620 if (!This) return E_OUTOFMEMORY;
621
622 This->IWICPalette_iface.lpVtbl = &PaletteImpl_Vtbl;
623 This->ref = 1;
624 This->count = 0;
625 This->colors = NULL;
626 This->type = WICBitmapPaletteTypeCustom;
627 InitializeCriticalSection(&This->lock);
628 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PaletteImpl.lock");
629
630 *palette = &This->IWICPalette_iface;
631
632 return S_OK;
633 }