1 /* 2 * Copyright 2009 Vincent Povirk for CodeWeavers 3 * Copyright 2012,2016 Dmitry Timoshkov 4 * Copyright 2016 Sebastian Lackner 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 #include "config.h" 22 23 #include <stdarg.h> 24 25 #define COBJMACROS 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winreg.h" 30 #include "objbase.h" 31 32 #include "wincodecs_private.h" 33 34 #include "wine/debug.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 37 38 typedef struct { 39 IWICPalette IWICPalette_iface; 40 LONG ref; 41 UINT count; 42 WICColor *colors; 43 WICBitmapPaletteType type; 44 CRITICAL_SECTION lock; /* must be held when count, colors, or type is accessed */ 45 } PaletteImpl; 46 47 static inline PaletteImpl *impl_from_IWICPalette(IWICPalette *iface) 48 { 49 return CONTAINING_RECORD(iface, PaletteImpl, IWICPalette_iface); 50 } 51 52 static HRESULT WINAPI PaletteImpl_QueryInterface(IWICPalette *iface, REFIID iid, 53 void **ppv) 54 { 55 PaletteImpl *This = impl_from_IWICPalette(iface); 56 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 57 58 if (!ppv) return E_INVALIDARG; 59 60 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICPalette, iid)) 61 { 62 *ppv = &This->IWICPalette_iface; 63 } 64 else 65 { 66 *ppv = NULL; 67 return E_NOINTERFACE; 68 } 69 70 IUnknown_AddRef((IUnknown*)*ppv); 71 return S_OK; 72 } 73 74 static ULONG WINAPI PaletteImpl_AddRef(IWICPalette *iface) 75 { 76 PaletteImpl *This = impl_from_IWICPalette(iface); 77 ULONG ref = InterlockedIncrement(&This->ref); 78 79 TRACE("(%p) refcount=%u\n", iface, ref); 80 81 return ref; 82 } 83 84 static ULONG WINAPI PaletteImpl_Release(IWICPalette *iface) 85 { 86 PaletteImpl *This = impl_from_IWICPalette(iface); 87 ULONG ref = InterlockedDecrement(&This->ref); 88 89 TRACE("(%p) refcount=%u\n", iface, ref); 90 91 if (ref == 0) 92 { 93 This->lock.DebugInfo->Spare[0] = 0; 94 DeleteCriticalSection(&This->lock); 95 HeapFree(GetProcessHeap(), 0, This->colors); 96 HeapFree(GetProcessHeap(), 0, This); 97 } 98 99 return ref; 100 } 101 102 static WICColor *generate_gray16_palette(UINT *count) 103 { 104 WICColor *entries; 105 UINT i; 106 107 *count = 16; 108 entries = HeapAlloc(GetProcessHeap(), 0, 16 * sizeof(WICColor)); 109 if (!entries) return NULL; 110 111 for (i = 0; i < 16; i++) 112 { 113 entries[i] = 0xff000000; 114 entries[i] |= (i<<20) | (i<<16) | (i<<12) | (i<<8) | (i<<4) | i; 115 } 116 return entries; 117 } 118 119 static WICColor *generate_gray256_palette(UINT *count) 120 { 121 WICColor *entries; 122 UINT i; 123 124 *count = 256; 125 entries = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor)); 126 if (!entries) return NULL; 127 128 for (i = 0; i < 256; i++) 129 { 130 entries[i] = 0xff000000; 131 entries[i] |= (i<<16) | (i<<8) | i; 132 } 133 return entries; 134 } 135 136 static WICColor *generate_halftone8_palette(UINT *count, BOOL add_transparent) 137 { 138 WICColor *entries; 139 UINT i; 140 141 *count = add_transparent ? 17 : 16; 142 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor)); 143 if (!entries) return NULL; 144 145 for (i = 0; i < 8; i++) 146 { 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; 151 } 152 153 for (i = 8; i < 16; i++) 154 { 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]; 159 } 160 161 if (add_transparent) 162 entries[i] = 0; 163 164 return entries; 165 } 166 167 static WICColor *generate_halftone27_palette(UINT *count, BOOL add_transparent) 168 { 169 WICColor *entries; 170 UINT i; 171 172 *count = add_transparent ? 29 : 28; 173 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor)); 174 if (!entries) return NULL; 175 176 for (i = 0; i < 27; i++) 177 { 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; 183 } 184 185 entries[i++] = 0xffc0c0c0; 186 if (add_transparent) 187 entries[i] = 0; 188 189 return entries; 190 } 191 192 static WICColor *generate_halftone64_palette(UINT *count, BOOL add_transparent) 193 { 194 WICColor *entries; 195 UINT i; 196 197 *count = add_transparent ? 73 : 72; 198 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor)); 199 if (!entries) return NULL; 200 201 for (i = 0; i < 64; i++) 202 { 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; 208 } 209 210 for (i = 64; i < 72; i++) 211 { 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]; 216 } 217 218 if (add_transparent) 219 entries[i] = 0; 220 221 return entries; 222 } 223 224 static WICColor *generate_halftone125_palette(UINT *count, BOOL add_transparent) 225 { 226 WICColor *entries; 227 UINT i; 228 229 *count = add_transparent ? 127 : 126; 230 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor)); 231 if (!entries) return NULL; 232 233 for (i = 0; i < 125; i++) 234 { 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; 240 } 241 242 entries[i++] = 0xffc0c0c0; 243 if (add_transparent) 244 entries[i] = 0; 245 246 return entries; 247 } 248 249 static WICColor *generate_halftone216_palette(UINT *count, BOOL add_transparent) 250 { 251 WICColor *entries; 252 UINT i; 253 254 *count = add_transparent ? 225 : 224; 255 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor)); 256 if (!entries) return NULL; 257 258 for (i = 0; i < 216; i++) 259 { 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; 265 } 266 267 for (i = 216; i < 224; i++) 268 { 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]; 273 } 274 275 if (add_transparent) 276 entries[i] = 0; 277 278 return entries; 279 } 280 281 static WICColor *generate_halftone252_palette(UINT *count, BOOL add_transparent) 282 { 283 WICColor *entries; 284 UINT i; 285 286 *count = add_transparent ? 253 : 252; 287 entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor)); 288 if (!entries) return NULL; 289 290 for (i = 0; i < 252; i++) 291 { 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; 298 } 299 300 if (add_transparent) 301 entries[i] = 0; 302 303 return entries; 304 } 305 306 static WICColor *generate_halftone256_palette(UINT *count, BOOL add_transparent) 307 { 308 WICColor *entries; 309 UINT i; 310 311 *count = 256; 312 entries = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor)); 313 if (!entries) return NULL; 314 315 for (i = 0; i < 256; i++) 316 { 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; 323 } 324 325 if (add_transparent) 326 entries[255] = 0; 327 328 return entries; 329 } 330 331 static HRESULT WINAPI PaletteImpl_InitializePredefined(IWICPalette *iface, 332 WICBitmapPaletteType type, BOOL add_transparent) 333 { 334 PaletteImpl *This = impl_from_IWICPalette(iface); 335 WICColor *colors; 336 UINT count; 337 338 TRACE("(%p,%u,%d)\n", iface, type, add_transparent); 339 340 switch (type) 341 { 342 case WICBitmapPaletteTypeFixedBW: 343 count = 2; 344 colors = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WICColor)); 345 if (!colors) return E_OUTOFMEMORY; 346 colors[0] = 0xff000000; 347 colors[1] = 0xffffffff; 348 break; 349 350 case WICBitmapPaletteTypeFixedGray4: 351 count = 4; 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; 358 break; 359 360 case WICBitmapPaletteTypeFixedGray16: 361 colors = generate_gray16_palette(&count); 362 if (!colors) return E_OUTOFMEMORY; 363 break; 364 365 case WICBitmapPaletteTypeFixedGray256: 366 colors = generate_gray256_palette(&count); 367 if (!colors) return E_OUTOFMEMORY; 368 break; 369 370 case WICBitmapPaletteTypeFixedHalftone8: 371 colors = generate_halftone8_palette(&count, add_transparent); 372 if (!colors) return E_OUTOFMEMORY; 373 break; 374 375 case WICBitmapPaletteTypeFixedHalftone27: 376 colors = generate_halftone27_palette(&count, add_transparent); 377 if (!colors) return E_OUTOFMEMORY; 378 break; 379 380 case WICBitmapPaletteTypeFixedHalftone64: 381 colors = generate_halftone64_palette(&count, add_transparent); 382 if (!colors) return E_OUTOFMEMORY; 383 break; 384 385 case WICBitmapPaletteTypeFixedHalftone125: 386 colors = generate_halftone125_palette(&count, add_transparent); 387 if (!colors) return E_OUTOFMEMORY; 388 break; 389 390 case WICBitmapPaletteTypeFixedHalftone216: 391 colors = generate_halftone216_palette(&count, add_transparent); 392 if (!colors) return E_OUTOFMEMORY; 393 break; 394 395 case WICBitmapPaletteTypeFixedHalftone252: 396 colors = generate_halftone252_palette(&count, add_transparent); 397 if (!colors) return E_OUTOFMEMORY; 398 break; 399 400 case WICBitmapPaletteTypeFixedHalftone256: 401 colors = generate_halftone256_palette(&count, add_transparent); 402 if (!colors) return E_OUTOFMEMORY; 403 break; 404 405 default: 406 WARN("invalid palette type %u\n", type); 407 return E_INVALIDARG; 408 } 409 410 EnterCriticalSection(&This->lock); 411 HeapFree(GetProcessHeap(), 0, This->colors); 412 This->colors = colors; 413 This->count = count; 414 This->type = type; 415 LeaveCriticalSection(&This->lock); 416 417 return S_OK; 418 } 419 420 static HRESULT WINAPI PaletteImpl_InitializeCustom(IWICPalette *iface, 421 WICColor *pColors, UINT colorCount) 422 { 423 PaletteImpl *This = impl_from_IWICPalette(iface); 424 WICColor *new_colors; 425 426 TRACE("(%p,%p,%u)\n", iface, pColors, colorCount); 427 428 if (colorCount == 0) 429 { 430 new_colors = NULL; 431 } 432 else 433 { 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); 438 } 439 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); 446 447 return S_OK; 448 } 449 450 #define R_COUNT (1 << 5) 451 #define R_SHIFT (8 - 5) 452 #define R_SCALE 2 453 454 #define G_COUNT (1 << 6) 455 #define G_SHIFT (8 - 6) 456 #define G_SCALE 3 457 458 #define B_COUNT (1 << 5) 459 #define B_SHIFT (8 - 5) 460 #define B_SCALE 1 461 462 struct histogram 463 { 464 unsigned int data[R_COUNT][G_COUNT][B_COUNT]; 465 }; 466 467 struct box 468 { 469 int r_min, r_max; 470 int g_min, g_max; 471 int b_min, b_max; 472 unsigned int count; 473 unsigned int score; 474 }; 475 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) 479 { 480 unsigned int count = 0; 481 int r, g, b; 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++; 486 return count; 487 } 488 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) 492 { 493 unsigned long long r_sum = 0, g_sum = 0, b_sum = 0; 494 unsigned int tmp, count = 0; 495 int r, g, b; 496 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++) 500 { 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; 505 count += tmp; 506 } 507 508 return ((b_sum + (count / 2)) / count) | 509 ((g_sum + (count / 2)) / count) << 8 | 510 ((r_sum + (count / 2)) / count) << 16 | 0xff000000; 511 } 512 513 /* same as histogram_count */ 514 static inline unsigned int box_count(struct histogram *h, struct box *b) 515 { 516 return histogram_count(h, b->r_min, b->r_max, b->g_min, b->g_max, b->b_min, b->b_max); 517 } 518 519 /* same as histogram_color */ 520 static inline unsigned int box_color(struct histogram *h, struct box *b) 521 { 522 return histogram_color(h, b->r_min, b->r_max, b->g_min, b->g_max, b->b_min, b->b_max); 523 } 524 525 /* compute score used to determine best split (also called "volume") */ 526 static inline unsigned int box_score(struct box *b) 527 { 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; 532 return sum; 533 } 534 535 /* attempt to shrink a box */ 536 static void shrink_box(struct histogram *h, struct box *b) 537 { 538 int i; 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); 553 } 554 555 /* helper for split_box */ 556 static inline void set_avg(int *min, int *max) 557 { 558 int avg = (*min + *max) / 2; 559 *min = avg + 1; 560 *max = avg; 561 } 562 563 /* split a box based on the best axis */ 564 static void split_box(struct histogram *h, struct box *b1, struct box *b2) 565 { 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; 569 570 *b2 = *b1; 571 572 if (r > g) 573 { 574 if (b > r) set_avg(&b1->b_min, &b2->b_max); 575 else set_avg(&b1->r_min, &b2->r_max); 576 } 577 else 578 { 579 if (b > g) set_avg(&b1->b_min, &b2->b_max); 580 else set_avg(&b1->g_min, &b2->g_max); 581 } 582 583 shrink_box(h, b1); 584 shrink_box(h, b2); 585 } 586 587 /* find box suitable for split based on count */ 588 static struct box *find_box_max_count(struct box *b, int count) 589 { 590 struct box *best = NULL; 591 for (; count--; b++) 592 if (b->score && (!best || b->count > best->count)) best = b; 593 return best; 594 } 595 596 /* find box suitable for split based on score */ 597 static struct box *find_box_max_score(struct box *b, int count) 598 { 599 struct box *best = NULL; 600 for (; count--; b++) 601 if (b->score && (!best || b->score > best->score)) best = b; 602 return best; 603 } 604 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) 609 { 610 struct box boxes[256]; 611 struct histogram *h; 612 unsigned int x, y; 613 unsigned char *p; 614 struct box *b1, *b2; 615 int numboxes, i; 616 617 if (!(h = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*h)))) 618 return 0; 619 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]++; 623 624 numboxes = 1; 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]); 629 630 while (numboxes <= desired / 2) 631 { 632 if (!(b1 = find_box_max_count(boxes, numboxes))) break; 633 b2 = &boxes[numboxes++]; 634 split_box(h, b1, b2); 635 } 636 while (numboxes < desired) 637 { 638 if (!(b1 = find_box_max_score(boxes, numboxes))) break; 639 b2 = &boxes[numboxes++]; 640 split_box(h, b1, b2); 641 } 642 643 for (i = 0; i < numboxes; i++) 644 colors[i] = box_color(h, &boxes[i]); 645 646 HeapFree(GetProcessHeap(), 0, h); 647 return numboxes; 648 } 649 650 651 static HRESULT WINAPI PaletteImpl_InitializeFromBitmap(IWICPalette *palette, 652 IWICBitmapSource *source, UINT desired, BOOL add_transparent) 653 { 654 IWICImagingFactory *factory = NULL; 655 IWICBitmap *rgb24_bitmap = NULL; 656 IWICBitmapSource *rgb24_source; 657 IWICBitmapLock *lock = NULL; 658 WICPixelFormatGUID format; 659 HRESULT hr; 660 UINT width, height, stride, size, actual_number_of_colors; 661 BYTE *src; 662 WICColor colors[256]; 663 664 TRACE("(%p,%p,%u,%d)\n", palette, source, desired, add_transparent); 665 666 if (!source || desired < 2 || desired > 256) 667 return E_INVALIDARG; 668 669 hr = IWICBitmapSource_GetPixelFormat(source, &format); 670 if (hr != S_OK) return hr; 671 672 /* For interoperability with gdiplus where PixelFormat24bppRGB actully stored 673 * as BGR (and there is no a corresponding RGB format) we have to use 24bppBGR 674 * to avoid format conversions. 675 */ 676 if (!IsEqualGUID(&format, &GUID_WICPixelFormat24bppBGR)) 677 { 678 hr = WICConvertBitmapSource(&GUID_WICPixelFormat24bppBGR, source, &rgb24_source); 679 if (hr != S_OK) return hr; 680 } 681 else 682 rgb24_source = source; 683 684 hr = ImagingFactory_CreateInstance(&IID_IWICImagingFactory, (void **)&factory); 685 if (hr != S_OK) goto fail; 686 687 hr = IWICImagingFactory_CreateBitmapFromSource(factory, rgb24_source, WICBitmapCacheOnLoad, &rgb24_bitmap); 688 if (hr != S_OK) goto fail; 689 690 hr = IWICBitmap_Lock(rgb24_bitmap, NULL, WICBitmapLockRead, &lock); 691 if (hr != S_OK) goto fail; 692 693 IWICBitmapLock_GetSize(lock, &width, &height); 694 IWICBitmapLock_GetStride(lock, &stride); 695 IWICBitmapLock_GetDataPointer(lock, &size, &src); 696 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); 699 700 if (actual_number_of_colors) 701 { 702 if (add_transparent) colors[actual_number_of_colors++] = 0; 703 704 hr = IWICPalette_InitializeCustom(palette, colors, actual_number_of_colors); 705 } 706 else 707 hr = E_OUTOFMEMORY; 708 709 fail: 710 if (lock) 711 IWICBitmapLock_Release(lock); 712 713 if (rgb24_bitmap) 714 IWICBitmap_Release(rgb24_bitmap); 715 716 if (factory) 717 IWICImagingFactory_Release(factory); 718 719 if (rgb24_source != source) 720 IWICBitmapSource_Release(rgb24_source); 721 722 return hr; 723 } 724 725 static HRESULT WINAPI PaletteImpl_InitializeFromPalette(IWICPalette *iface, 726 IWICPalette *source) 727 { 728 PaletteImpl *This = impl_from_IWICPalette(iface); 729 UINT count; 730 WICColor *colors = NULL; 731 WICBitmapPaletteType type; 732 HRESULT hr; 733 734 TRACE("(%p,%p)\n", iface, source); 735 736 if (!source) return E_INVALIDARG; 737 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; 742 if (count) 743 { 744 colors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count); 745 if (!colors) return E_OUTOFMEMORY; 746 hr = IWICPalette_GetColors(source, count, colors, &count); 747 if (hr != S_OK) 748 { 749 HeapFree(GetProcessHeap(), 0, colors); 750 return hr; 751 } 752 } 753 754 EnterCriticalSection(&This->lock); 755 HeapFree(GetProcessHeap(), 0, This->colors); 756 This->colors = colors; 757 This->count = count; 758 This->type = type; 759 LeaveCriticalSection(&This->lock); 760 761 return S_OK; 762 } 763 764 static HRESULT WINAPI PaletteImpl_GetType(IWICPalette *iface, 765 WICBitmapPaletteType *pePaletteType) 766 { 767 PaletteImpl *This = impl_from_IWICPalette(iface); 768 769 TRACE("(%p,%p)\n", iface, pePaletteType); 770 771 if (!pePaletteType) return E_INVALIDARG; 772 773 EnterCriticalSection(&This->lock); 774 *pePaletteType = This->type; 775 LeaveCriticalSection(&This->lock); 776 777 return S_OK; 778 } 779 780 static HRESULT WINAPI PaletteImpl_GetColorCount(IWICPalette *iface, UINT *pcCount) 781 { 782 PaletteImpl *This = impl_from_IWICPalette(iface); 783 784 TRACE("(%p,%p)\n", iface, pcCount); 785 786 if (!pcCount) return E_INVALIDARG; 787 788 EnterCriticalSection(&This->lock); 789 *pcCount = This->count; 790 LeaveCriticalSection(&This->lock); 791 792 return S_OK; 793 } 794 795 static HRESULT WINAPI PaletteImpl_GetColors(IWICPalette *iface, UINT colorCount, 796 WICColor *pColors, UINT *pcActualColors) 797 { 798 PaletteImpl *This = impl_from_IWICPalette(iface); 799 800 TRACE("(%p,%i,%p,%p)\n", iface, colorCount, pColors, pcActualColors); 801 802 if (!pColors || !pcActualColors) return E_INVALIDARG; 803 804 EnterCriticalSection(&This->lock); 805 806 if (This->count < colorCount) colorCount = This->count; 807 808 memcpy(pColors, This->colors, sizeof(WICColor) * colorCount); 809 810 *pcActualColors = colorCount; 811 812 LeaveCriticalSection(&This->lock); 813 814 return S_OK; 815 } 816 817 static HRESULT WINAPI PaletteImpl_IsBlackWhite(IWICPalette *iface, BOOL *pfIsBlackWhite) 818 { 819 PaletteImpl *This = impl_from_IWICPalette(iface); 820 821 TRACE("(%p,%p)\n", iface, pfIsBlackWhite); 822 823 if (!pfIsBlackWhite) return E_INVALIDARG; 824 825 EnterCriticalSection(&This->lock); 826 if (This->type == WICBitmapPaletteTypeFixedBW) 827 *pfIsBlackWhite = TRUE; 828 else 829 *pfIsBlackWhite = FALSE; 830 LeaveCriticalSection(&This->lock); 831 832 return S_OK; 833 } 834 835 static HRESULT WINAPI PaletteImpl_IsGrayscale(IWICPalette *iface, BOOL *pfIsGrayscale) 836 { 837 PaletteImpl *This = impl_from_IWICPalette(iface); 838 839 TRACE("(%p,%p)\n", iface, pfIsGrayscale); 840 841 if (!pfIsGrayscale) return E_INVALIDARG; 842 843 EnterCriticalSection(&This->lock); 844 switch(This->type) 845 { 846 case WICBitmapPaletteTypeFixedBW: 847 case WICBitmapPaletteTypeFixedGray4: 848 case WICBitmapPaletteTypeFixedGray16: 849 case WICBitmapPaletteTypeFixedGray256: 850 *pfIsGrayscale = TRUE; 851 break; 852 default: 853 *pfIsGrayscale = FALSE; 854 } 855 LeaveCriticalSection(&This->lock); 856 857 return S_OK; 858 } 859 860 static HRESULT WINAPI PaletteImpl_HasAlpha(IWICPalette *iface, BOOL *pfHasAlpha) 861 { 862 PaletteImpl *This = impl_from_IWICPalette(iface); 863 UINT i; 864 865 TRACE("(%p,%p)\n", iface, pfHasAlpha); 866 867 if (!pfHasAlpha) return E_INVALIDARG; 868 869 *pfHasAlpha = FALSE; 870 871 EnterCriticalSection(&This->lock); 872 for (i=0; i<This->count; i++) 873 if ((This->colors[i]&0xff000000) != 0xff000000) 874 { 875 *pfHasAlpha = TRUE; 876 break; 877 } 878 LeaveCriticalSection(&This->lock); 879 880 return S_OK; 881 } 882 883 static const IWICPaletteVtbl PaletteImpl_Vtbl = { 884 PaletteImpl_QueryInterface, 885 PaletteImpl_AddRef, 886 PaletteImpl_Release, 887 PaletteImpl_InitializePredefined, 888 PaletteImpl_InitializeCustom, 889 PaletteImpl_InitializeFromBitmap, 890 PaletteImpl_InitializeFromPalette, 891 PaletteImpl_GetType, 892 PaletteImpl_GetColorCount, 893 PaletteImpl_GetColors, 894 PaletteImpl_IsBlackWhite, 895 PaletteImpl_IsGrayscale, 896 PaletteImpl_HasAlpha 897 }; 898 899 HRESULT PaletteImpl_Create(IWICPalette **palette) 900 { 901 PaletteImpl *This; 902 903 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PaletteImpl)); 904 if (!This) return E_OUTOFMEMORY; 905 906 This->IWICPalette_iface.lpVtbl = &PaletteImpl_Vtbl; 907 This->ref = 1; 908 This->count = 0; 909 This->colors = NULL; 910 This->type = WICBitmapPaletteTypeCustom; 911 InitializeCriticalSection(&This->lock); 912 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PaletteImpl.lock"); 913 914 *palette = &This->IWICPalette_iface; 915 916 return S_OK; 917 } 918