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 41 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); 42 43 HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); 44 45 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24) 46 #define WMF_PLACEABLE_KEY 0x9ac6cdd7 47 48 static const struct 49 { 50 const WICPixelFormatGUID *wic_format; 51 PixelFormat gdip_format; 52 /* predefined palette type to use for pixel format conversions */ 53 WICBitmapPaletteType palette_type; 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 74 static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteType palette_type) 75 { 76 HRESULT hr; 77 IWICImagingFactory *factory; 78 IWICPalette *wic_palette; 79 ColorPalette *palette = NULL; 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 { 87 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 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 { 97 WICBitmapPaletteType type; 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) { 107 case WICBitmapPaletteTypeFixedGray4: 108 case WICBitmapPaletteTypeFixedGray16: 109 case WICBitmapPaletteTypeFixedGray256: 110 palette->Flags = PaletteFlagsGrayScale; 111 break; 112 case WICBitmapPaletteTypeFixedHalftone8: 113 case WICBitmapPaletteTypeFixedHalftone27: 114 case WICBitmapPaletteTypeFixedHalftone64: 115 case WICBitmapPaletteTypeFixedHalftone125: 116 case WICBitmapPaletteTypeFixedHalftone216: 117 case WICBitmapPaletteTypeFixedHalftone252: 118 case WICBitmapPaletteTypeFixedHalftone256: 119 palette->Flags = PaletteFlagsHalftone; 120 break; 121 default: 122 palette->Flags = 0; 123 } 124 IWICPalette_HasAlpha(wic_palette, &alpha); 125 if(alpha) 126 palette->Flags |= PaletteFlagsHasAlpha; 127 } 128 IWICPalette_Release(wic_palette); 129 } 130 IWICImagingFactory_Release(factory); 131 return palette; 132 } 133 134 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect, 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 145 GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps, 146 INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect, 147 GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize) 148 { 149 FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize); 150 /* 151 * Note: According to Jose Roca's GDI+ docs, this function is not 152 * implemented in Windows's GDI+. 153 */ 154 return NotImplemented; 155 } 156 157 static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x) 158 { 159 *index = (row[x/8]>>(7-x%8)) & 1; 160 } 161 162 static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x) 163 { 164 if (x & 1) 165 *index = row[x/2]&0xf; 166 else 167 *index = row[x/2]>>4; 168 } 169 170 static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x) 171 { 172 *index = row[x]; 173 } 174 175 static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 176 const BYTE *row, UINT x) 177 { 178 *r = *g = *b = row[x*2+1]; 179 *a = 255; 180 } 181 182 static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 183 const BYTE *row, UINT x) 184 { 185 WORD pixel = *((const WORD*)(row)+x); 186 *r = (pixel>>7&0xf8)|(pixel>>12&0x7); 187 *g = (pixel>>2&0xf8)|(pixel>>6&0x7); 188 *b = (pixel<<3&0xf8)|(pixel>>2&0x7); 189 *a = 255; 190 } 191 192 static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 193 const BYTE *row, UINT x) 194 { 195 WORD pixel = *((const WORD*)(row)+x); 196 *r = (pixel>>8&0xf8)|(pixel>>13&0x7); 197 *g = (pixel>>3&0xfc)|(pixel>>9&0x3); 198 *b = (pixel<<3&0xf8)|(pixel>>2&0x7); 199 *a = 255; 200 } 201 202 static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 203 const BYTE *row, UINT x) 204 { 205 WORD pixel = *((const WORD*)(row)+x); 206 *r = (pixel>>7&0xf8)|(pixel>>12&0x7); 207 *g = (pixel>>2&0xf8)|(pixel>>6&0x7); 208 *b = (pixel<<3&0xf8)|(pixel>>2&0x7); 209 if ((pixel&0x8000) == 0x8000) 210 *a = 255; 211 else 212 *a = 0; 213 } 214 215 static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 216 const BYTE *row, UINT x) 217 { 218 *r = row[x*3+2]; 219 *g = row[x*3+1]; 220 *b = row[x*3]; 221 *a = 255; 222 } 223 224 static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 225 const BYTE *row, UINT x) 226 { 227 *r = row[x*4+2]; 228 *g = row[x*4+1]; 229 *b = row[x*4]; 230 *a = 255; 231 } 232 233 static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 234 const BYTE *row, UINT x) 235 { 236 *r = row[x*4+2]; 237 *g = row[x*4+1]; 238 *b = row[x*4]; 239 *a = row[x*4+3]; 240 } 241 242 static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 243 const BYTE *row, UINT x) 244 { 245 *a = row[x*4+3]; 246 if (*a == 0) 247 *r = *g = *b = 0; 248 else 249 { 250 *r = row[x*4+2] * 255 / *a; 251 *g = row[x*4+1] * 255 / *a; 252 *b = row[x*4] * 255 / *a; 253 } 254 } 255 256 static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 257 const BYTE *row, UINT x) 258 { 259 *r = row[x*6+5]; 260 *g = row[x*6+3]; 261 *b = row[x*6+1]; 262 *a = 255; 263 } 264 265 static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 266 const BYTE *row, UINT x) 267 { 268 *r = row[x*8+5]; 269 *g = row[x*8+3]; 270 *b = row[x*8+1]; 271 *a = row[x*8+7]; 272 } 273 274 static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, 275 const BYTE *row, UINT x) 276 { 277 *a = row[x*8+7]; 278 if (*a == 0) 279 *r = *g = *b = 0; 280 else 281 { 282 *r = row[x*8+5] * 255 / *a; 283 *g = row[x*8+3] * 255 / *a; 284 *b = row[x*8+1] * 255 / *a; 285 } 286 } 287 288 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y, 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 { 303 case PixelFormat1bppIndexed: 304 getpixel_1bppIndexed(&index,row,x); 305 break; 306 case PixelFormat4bppIndexed: 307 getpixel_4bppIndexed(&index,row,x); 308 break; 309 case PixelFormat8bppIndexed: 310 getpixel_8bppIndexed(&index,row,x); 311 break; 312 case PixelFormat16bppGrayScale: 313 getpixel_16bppGrayScale(&r,&g,&b,&a,row,x); 314 break; 315 case PixelFormat16bppRGB555: 316 getpixel_16bppRGB555(&r,&g,&b,&a,row,x); 317 break; 318 case PixelFormat16bppRGB565: 319 getpixel_16bppRGB565(&r,&g,&b,&a,row,x); 320 break; 321 case PixelFormat16bppARGB1555: 322 getpixel_16bppARGB1555(&r,&g,&b,&a,row,x); 323 break; 324 case PixelFormat24bppRGB: 325 getpixel_24bppRGB(&r,&g,&b,&a,row,x); 326 break; 327 case PixelFormat32bppRGB: 328 getpixel_32bppRGB(&r,&g,&b,&a,row,x); 329 break; 330 case PixelFormat32bppARGB: 331 getpixel_32bppARGB(&r,&g,&b,&a,row,x); 332 break; 333 case PixelFormat32bppPARGB: 334 getpixel_32bppPARGB(&r,&g,&b,&a,row,x); 335 break; 336 case PixelFormat48bppRGB: 337 getpixel_48bppRGB(&r,&g,&b,&a,row,x); 338 break; 339 case PixelFormat64bppARGB: 340 getpixel_64bppARGB(&r,&g,&b,&a,row,x); 341 break; 342 case PixelFormat64bppPARGB: 343 getpixel_64bppPARGB(&r,&g,&b,&a,row,x); 344 break; 345 default: 346 FIXME("not implemented for format 0x%x\n", bitmap->format); 347 return NotImplemented; 348 } 349 350 if (bitmap->format & PixelFormatIndexed) 351 *color = bitmap->image.palette->Entries[index]; 352 else 353 *color = a<<24|r<<16|g<<8|b; 354 355 return Ok; 356 } 357 358 static inline UINT get_palette_index(BYTE r, BYTE g, BYTE b, BYTE a, ColorPalette *palette) 359 { 360 BYTE index = 0; 361 int best_distance = 0x7fff; 362 int distance; 363 UINT i; 364 365 if (!palette) return 0; 366 /* This algorithm scans entire palette, 367 computes difference from desired color (all color components have equal weight) 368 and returns the index of color with least difference. 369 370 Note: Maybe it could be replaced with a better algorithm for better image quality 371 and performance, though better algorithm would probably need some pre-built lookup 372 tables and thus may actually be slower if this method is called only few times per 373 every image. 374 */ 375 for(i=0;i<palette->Count;i++) { 376 ARGB color=palette->Entries[i]; 377 distance=abs(b-(color & 0xff)) + abs(g-(color>>8 & 0xff)) + abs(r-(color>>16 & 0xff)) + abs(a-(color>>24 & 0xff)); 378 if (distance<best_distance) { 379 best_distance=distance; 380 index=i; 381 } 382 } 383 return index; 384 } 385 386 static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a, 387 BYTE *row, UINT x, ColorPalette *palette) 388 { 389 BYTE index = get_palette_index(r,g,b,a,palette); 390 row[x]=index; 391 } 392 393 static inline void setpixel_1bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a, 394 BYTE *row, UINT x, ColorPalette *palette) 395 { 396 row[x/8] = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,palette)<<(7-x%8)); 397 } 398 399 static inline void setpixel_4bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a, 400 BYTE *row, UINT x, ColorPalette *palette) 401 { 402 if (x & 1) 403 row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,palette); 404 else 405 row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,palette)<<4; 406 } 407 408 static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a, 409 BYTE *row, UINT x) 410 { 411 *((WORD*)(row)+x) = (r+g+b)*85; 412 } 413 414 static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a, 415 BYTE *row, UINT x) 416 { 417 *((WORD*)(row)+x) = (r<<7&0x7c00)| 418 (g<<2&0x03e0)| 419 (b>>3&0x001f); 420 } 421 422 static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a, 423 BYTE *row, UINT x) 424 { 425 *((WORD*)(row)+x) = (r<<8&0xf800)| 426 (g<<3&0x07e0)| 427 (b>>3&0x001f); 428 } 429 430 static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a, 431 BYTE *row, UINT x) 432 { 433 *((WORD*)(row)+x) = (a<<8&0x8000)| 434 (r<<7&0x7c00)| 435 (g<<2&0x03e0)| 436 (b>>3&0x001f); 437 } 438 439 static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a, 440 BYTE *row, UINT x) 441 { 442 row[x*3+2] = r; 443 row[x*3+1] = g; 444 row[x*3] = b; 445 } 446 447 static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a, 448 BYTE *row, UINT x) 449 { 450 *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b; 451 } 452 453 static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a, 454 BYTE *row, UINT x) 455 { 456 *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b; 457 } 458 459 static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a, 460 BYTE *row, UINT x) 461 { 462 r = r * a / 255; 463 g = g * a / 255; 464 b = b * a / 255; 465 *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b; 466 } 467 468 static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a, 469 BYTE *row, UINT x) 470 { 471 row[x*6+5] = row[x*6+4] = r; 472 row[x*6+3] = row[x*6+2] = g; 473 row[x*6+1] = row[x*6] = b; 474 } 475 476 static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a, 477 BYTE *row, UINT x) 478 { 479 UINT64 a64=a, r64=r, g64=g, b64=b; 480 *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64; 481 } 482 483 static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a, 484 BYTE *row, UINT x) 485 { 486 UINT64 a64, r64, g64, b64; 487 a64 = a * 257; 488 r64 = r * a / 255; 489 g64 = g * a / 255; 490 b64 = b * a / 255; 491 *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64; 492 } 493 494 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y, 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 { 512 case PixelFormat16bppGrayScale: 513 setpixel_16bppGrayScale(r,g,b,a,row,x); 514 break; 515 case PixelFormat16bppRGB555: 516 setpixel_16bppRGB555(r,g,b,a,row,x); 517 break; 518 case PixelFormat16bppRGB565: 519 setpixel_16bppRGB565(r,g,b,a,row,x); 520 break; 521 case PixelFormat16bppARGB1555: 522 setpixel_16bppARGB1555(r,g,b,a,row,x); 523 break; 524 case PixelFormat24bppRGB: 525 setpixel_24bppRGB(r,g,b,a,row,x); 526 break; 527 case PixelFormat32bppRGB: 528 setpixel_32bppRGB(r,g,b,a,row,x); 529 break; 530 case PixelFormat32bppARGB: 531 setpixel_32bppARGB(r,g,b,a,row,x); 532 break; 533 case PixelFormat32bppPARGB: 534 setpixel_32bppPARGB(r,g,b,a,row,x); 535 break; 536 case PixelFormat48bppRGB: 537 setpixel_48bppRGB(r,g,b,a,row,x); 538 break; 539 case PixelFormat64bppARGB: 540 setpixel_64bppARGB(r,g,b,a,row,x); 541 break; 542 case PixelFormat64bppPARGB: 543 setpixel_64bppPARGB(r,g,b,a,row,x); 544 break; 545 case PixelFormat8bppIndexed: 546 setpixel_8bppIndexed(r,g,b,a,row,x,bitmap->image.palette); 547 break; 548 case PixelFormat4bppIndexed: 549 setpixel_4bppIndexed(r,g,b,a,row,x,bitmap->image.palette); 550 break; 551 case PixelFormat1bppIndexed: 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 562 GpStatus convert_pixels(INT width, INT height, 563 INT dst_stride, BYTE *dst_bits, PixelFormat dst_format, 564 INT src_stride, const BYTE *src_bits, PixelFormat src_format, 565 ColorPalette *palette) 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 { 613 case PixelFormat1bppIndexed: 614 switch (dst_format) 615 { 616 case PixelFormat16bppGrayScale: 617 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppGrayScale); 618 case PixelFormat16bppRGB555: 619 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB555); 620 case PixelFormat16bppRGB565: 621 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB565); 622 case PixelFormat16bppARGB1555: 623 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppARGB1555); 624 case PixelFormat24bppRGB: 625 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_24bppRGB); 626 case PixelFormat32bppRGB: 627 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppRGB); 628 case PixelFormat32bppARGB: 629 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppARGB); 630 case PixelFormat32bppPARGB: 631 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppPARGB); 632 case PixelFormat48bppRGB: 633 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_48bppRGB); 634 case PixelFormat64bppARGB: 635 convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_64bppARGB); 636 default: 637 break; 638 } 639 break; 640 case PixelFormat4bppIndexed: 641 switch (dst_format) 642 { 643 case PixelFormat16bppGrayScale: 644 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppGrayScale); 645 case PixelFormat16bppRGB555: 646 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB555); 647 case PixelFormat16bppRGB565: 648 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB565); 649 case PixelFormat16bppARGB1555: 650 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppARGB1555); 651 case PixelFormat24bppRGB: 652 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_24bppRGB); 653 case PixelFormat32bppRGB: 654 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppRGB); 655 case PixelFormat32bppARGB: 656 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppARGB); 657 case PixelFormat32bppPARGB: 658 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppPARGB); 659 case PixelFormat48bppRGB: 660 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_48bppRGB); 661 case PixelFormat64bppARGB: 662 convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_64bppARGB); 663 default: 664 break; 665 } 666 break; 667 case PixelFormat8bppIndexed: 668 switch (dst_format) 669 { 670 case PixelFormat16bppGrayScale: 671 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppGrayScale); 672 case PixelFormat16bppRGB555: 673 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB555); 674 case PixelFormat16bppRGB565: 675 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB565); 676 case PixelFormat16bppARGB1555: 677 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppARGB1555); 678 case PixelFormat24bppRGB: 679 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_24bppRGB); 680 case PixelFormat32bppRGB: 681 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppRGB); 682 case PixelFormat32bppARGB: 683 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppARGB); 684 case PixelFormat32bppPARGB: 685 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppPARGB); 686 case PixelFormat48bppRGB: 687 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_48bppRGB); 688 case PixelFormat64bppARGB: 689 convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_64bppARGB); 690 default: 691 break; 692 } 693 break; 694 case PixelFormat16bppGrayScale: 695 switch (dst_format) 696 { 697 case PixelFormat1bppIndexed: 698 convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_1bppIndexed); 699 case PixelFormat8bppIndexed: 700 convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_8bppIndexed); 701 case PixelFormat16bppRGB555: 702 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB555); 703 case PixelFormat16bppRGB565: 704 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB565); 705 case PixelFormat16bppARGB1555: 706 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppARGB1555); 707 case PixelFormat24bppRGB: 708 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_24bppRGB); 709 case PixelFormat32bppRGB: 710 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppRGB); 711 case PixelFormat32bppARGB: 712 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppARGB); 713 case PixelFormat32bppPARGB: 714 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppPARGB); 715 case PixelFormat48bppRGB: 716 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_48bppRGB); 717 case PixelFormat64bppARGB: 718 convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_64bppARGB); 719 default: 720 break; 721 } 722 break; 723 case PixelFormat16bppRGB555: 724 switch (dst_format) 725 { 726 case PixelFormat1bppIndexed: 727 convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_1bppIndexed); 728 case PixelFormat8bppIndexed: 729 convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_8bppIndexed); 730 case PixelFormat16bppGrayScale: 731 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppGrayScale); 732 case PixelFormat16bppRGB565: 733 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppRGB565); 734 case PixelFormat16bppARGB1555: 735 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppARGB1555); 736 case PixelFormat24bppRGB: 737 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_24bppRGB); 738 case PixelFormat32bppRGB: 739 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppRGB); 740 case PixelFormat32bppARGB: 741 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppARGB); 742 case PixelFormat32bppPARGB: 743 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppPARGB); 744 case PixelFormat48bppRGB: 745 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_48bppRGB); 746 case PixelFormat64bppARGB: 747 convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_64bppARGB); 748 default: 749 break; 750 } 751 break; 752 case PixelFormat16bppRGB565: 753 switch (dst_format) 754 { 755 case PixelFormat1bppIndexed: 756 convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_1bppIndexed); 757 case PixelFormat8bppIndexed: 758 convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_8bppIndexed); 759 case PixelFormat16bppGrayScale: 760 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppGrayScale); 761 case PixelFormat16bppRGB555: 762 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppRGB555); 763 case PixelFormat16bppARGB1555: 764 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppARGB1555); 765 case PixelFormat24bppRGB: 766 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_24bppRGB); 767 case PixelFormat32bppRGB: 768 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppRGB); 769 case PixelFormat32bppARGB: 770 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppARGB); 771 case PixelFormat32bppPARGB: 772 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppPARGB); 773 case PixelFormat48bppRGB: 774 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_48bppRGB); 775 case PixelFormat64bppARGB: 776 convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_64bppARGB); 777 default: 778 break; 779 } 780 break; 781 case PixelFormat16bppARGB1555: 782 switch (dst_format) 783 { 784 case PixelFormat1bppIndexed: 785 convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_1bppIndexed); 786 case PixelFormat8bppIndexed: 787 convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_8bppIndexed); 788 case PixelFormat16bppGrayScale: 789 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppGrayScale); 790 case PixelFormat16bppRGB555: 791 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB555); 792 case PixelFormat16bppRGB565: 793 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB565); 794 case PixelFormat24bppRGB: 795 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_24bppRGB); 796 case PixelFormat32bppRGB: 797 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppRGB); 798 case PixelFormat32bppARGB: 799 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppARGB); 800 case PixelFormat32bppPARGB: 801 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppPARGB); 802 case PixelFormat48bppRGB: 803 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_48bppRGB); 804 case PixelFormat64bppARGB: 805 convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_64bppARGB); 806 default: 807 break; 808 } 809 break; 810 case PixelFormat24bppRGB: 811 switch (dst_format) 812 { 813 case PixelFormat1bppIndexed: 814 convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_1bppIndexed); 815 case PixelFormat8bppIndexed: 816 convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_8bppIndexed); 817 case PixelFormat16bppGrayScale: 818 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppGrayScale); 819 case PixelFormat16bppRGB555: 820 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB555); 821 case PixelFormat16bppRGB565: 822 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB565); 823 case PixelFormat16bppARGB1555: 824 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppARGB1555); 825 case PixelFormat32bppRGB: 826 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppRGB); 827 case PixelFormat32bppARGB: 828 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppARGB); 829 case PixelFormat32bppPARGB: 830 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppPARGB); 831 case PixelFormat48bppRGB: 832 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_48bppRGB); 833 case PixelFormat64bppARGB: 834 convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_64bppARGB); 835 default: 836 break; 837 } 838 break; 839 case PixelFormat32bppRGB: 840 switch (dst_format) 841 { 842 case PixelFormat1bppIndexed: 843 convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_1bppIndexed); 844 case PixelFormat8bppIndexed: 845 convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_8bppIndexed); 846 case PixelFormat16bppGrayScale: 847 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppGrayScale); 848 case PixelFormat16bppRGB555: 849 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB555); 850 case PixelFormat16bppRGB565: 851 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB565); 852 case PixelFormat16bppARGB1555: 853 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppARGB1555); 854 case PixelFormat24bppRGB: 855 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_24bppRGB); 856 case PixelFormat32bppARGB: 857 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppARGB); 858 case PixelFormat32bppPARGB: 859 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppPARGB); 860 case PixelFormat48bppRGB: 861 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_48bppRGB); 862 case PixelFormat64bppARGB: 863 convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_64bppARGB); 864 default: 865 break; 866 } 867 break; 868 case PixelFormat32bppARGB: 869 switch (dst_format) 870 { 871 case PixelFormat1bppIndexed: 872 convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_1bppIndexed); 873 case PixelFormat8bppIndexed: 874 convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_8bppIndexed); 875 case PixelFormat16bppGrayScale: 876 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppGrayScale); 877 case PixelFormat16bppRGB555: 878 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB555); 879 case PixelFormat16bppRGB565: 880 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB565); 881 case PixelFormat16bppARGB1555: 882 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppARGB1555); 883 case PixelFormat24bppRGB: 884 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_24bppRGB); 885 case PixelFormat32bppPARGB: 886 convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride); 887 return Ok; 888 case PixelFormat48bppRGB: 889 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_48bppRGB); 890 case PixelFormat64bppARGB: 891 convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_64bppARGB); 892 default: 893 break; 894 } 895 break; 896 case PixelFormat32bppPARGB: 897 switch (dst_format) 898 { 899 case PixelFormat1bppIndexed: 900 convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_1bppIndexed); 901 case PixelFormat8bppIndexed: 902 convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_8bppIndexed); 903 case PixelFormat16bppGrayScale: 904 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppGrayScale); 905 case PixelFormat16bppRGB555: 906 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB555); 907 case PixelFormat16bppRGB565: 908 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB565); 909 case PixelFormat16bppARGB1555: 910 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppARGB1555); 911 case PixelFormat24bppRGB: 912 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_24bppRGB); 913 case PixelFormat32bppRGB: 914 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppRGB); 915 case PixelFormat32bppARGB: 916 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppARGB); 917 case PixelFormat48bppRGB: 918 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_48bppRGB); 919 case PixelFormat64bppARGB: 920 convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_64bppARGB); 921 default: 922 break; 923 } 924 break; 925 case PixelFormat48bppRGB: 926 switch (dst_format) 927 { 928 case PixelFormat1bppIndexed: 929 convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_1bppIndexed); 930 case PixelFormat8bppIndexed: 931 convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_8bppIndexed); 932 case PixelFormat16bppGrayScale: 933 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppGrayScale); 934 case PixelFormat16bppRGB555: 935 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB555); 936 case PixelFormat16bppRGB565: 937 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB565); 938 case PixelFormat16bppARGB1555: 939 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppARGB1555); 940 case PixelFormat24bppRGB: 941 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_24bppRGB); 942 case PixelFormat32bppRGB: 943 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppRGB); 944 case PixelFormat32bppARGB: 945 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppARGB); 946 case PixelFormat32bppPARGB: 947 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppPARGB); 948 case PixelFormat64bppARGB: 949 convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_64bppARGB); 950 default: 951 break; 952 } 953 break; 954 case PixelFormat64bppARGB: 955 switch (dst_format) 956 { 957 case PixelFormat1bppIndexed: 958 convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_1bppIndexed); 959 case PixelFormat8bppIndexed: 960 convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_8bppIndexed); 961 case PixelFormat16bppGrayScale: 962 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppGrayScale); 963 case PixelFormat16bppRGB555: 964 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB555); 965 case PixelFormat16bppRGB565: 966 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB565); 967 case PixelFormat16bppARGB1555: 968 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppARGB1555); 969 case PixelFormat24bppRGB: 970 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_24bppRGB); 971 case PixelFormat32bppRGB: 972 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppRGB); 973 case PixelFormat32bppARGB: 974 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppARGB); 975 case PixelFormat32bppPARGB: 976 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppPARGB); 977 case PixelFormat48bppRGB: 978 convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_48bppRGB); 979 default: 980 break; 981 } 982 break; 983 case PixelFormat64bppPARGB: 984 switch (dst_format) 985 { 986 case PixelFormat1bppIndexed: 987 convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_1bppIndexed); 988 case PixelFormat8bppIndexed: 989 convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_8bppIndexed); 990 case PixelFormat16bppGrayScale: 991 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppGrayScale); 992 case PixelFormat16bppRGB555: 993 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB555); 994 case PixelFormat16bppRGB565: 995 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB565); 996 case PixelFormat16bppARGB1555: 997 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppARGB1555); 998 case PixelFormat24bppRGB: 999 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_24bppRGB); 1000 case PixelFormat32bppRGB: 1001 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppRGB); 1002 case PixelFormat32bppARGB: 1003 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppARGB); 1004 case PixelFormat32bppPARGB: 1005 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppPARGB); 1006 case PixelFormat48bppRGB: 1007 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_48bppRGB); 1008 case PixelFormat64bppARGB: 1009 convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_64bppARGB); 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. */ 1030 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect, 1031 UINT flags, PixelFormat format, BitmapData* lockeddata) 1032 { 1033 INT bitspp = PIXELFORMATBPP(format); 1034 GpRect act_rect; /* actual rect to be used */ 1035 GpStatus stat; 1036 BOOL unlock; 1037 1038 TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata); 1039 1040 if(!lockeddata || !bitmap) 1041 return InvalidParameter; 1042 if(!image_lock(&bitmap->image, &unlock)) 1043 return ObjectBusy; 1044 1045 if(rect){ 1046 if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) || 1047 (rect->Y + rect->Height > bitmap->height) || !flags) 1048 { 1049 image_unlock(&bitmap->image, unlock); 1050 return InvalidParameter; 1051 } 1052 1053 act_rect = *rect; 1054 } 1055 else{ 1056 act_rect.X = act_rect.Y = 0; 1057 act_rect.Width = bitmap->width; 1058 act_rect.Height = bitmap->height; 1059 } 1060 1061 if(bitmap->lockmode) 1062 { 1063 WARN("bitmap is already locked and cannot be locked again\n"); 1064 image_unlock(&bitmap->image, unlock); 1065 return WrongState; 1066 } 1067 1068 if (bitmap->bits && bitmap->format == format && !(flags & ImageLockModeUserInputBuf)) 1069 { 1070 /* no conversion is necessary; just use the bits directly */ 1071 lockeddata->Width = act_rect.Width; 1072 lockeddata->Height = act_rect.Height; 1073 lockeddata->PixelFormat = format; 1074 lockeddata->Reserved = flags; 1075 lockeddata->Stride = bitmap->stride; 1076 lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X + 1077 bitmap->stride * act_rect.Y; 1078 1079 bitmap->lockmode = flags | ImageLockModeRead; 1080 1081 image_unlock(&bitmap->image, unlock); 1082 return Ok; 1083 } 1084 1085 /* Make sure we can convert to the requested format. */ 1086 if (flags & ImageLockModeRead) 1087 { 1088 stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL); 1089 if (stat == NotImplemented) 1090 { 1091 FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format); 1092 image_unlock(&bitmap->image, unlock); 1093 return NotImplemented; 1094 } 1095 } 1096 1097 /* If we're opening for writing, make sure we'll be able to write back in 1098 * the original format. */ 1099 if (flags & ImageLockModeWrite) 1100 { 1101 stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL); 1102 if (stat == NotImplemented) 1103 { 1104 FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format); 1105 image_unlock(&bitmap->image, unlock); 1106 return NotImplemented; 1107 } 1108 } 1109 1110 lockeddata->Width = act_rect.Width; 1111 lockeddata->Height = act_rect.Height; 1112 lockeddata->PixelFormat = format; 1113 lockeddata->Reserved = flags; 1114 1115 if(!(flags & ImageLockModeUserInputBuf)) 1116 { 1117 lockeddata->Stride = (((act_rect.Width * bitspp + 7) / 8) + 3) & ~3; 1118 1119 bitmap->bitmapbits = heap_alloc_zero(lockeddata->Stride * act_rect.Height); 1120 1121 if (!bitmap->bitmapbits) 1122 { 1123 image_unlock(&bitmap->image, unlock); 1124 return OutOfMemory; 1125 } 1126 1127 lockeddata->Scan0 = bitmap->bitmapbits; 1128 } 1129 1130 if (flags & ImageLockModeRead) 1131 { 1132 static BOOL fixme = FALSE; 1133 1134 if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0) 1135 { 1136 FIXME("Cannot copy rows that don't start at a whole byte.\n"); 1137 fixme = TRUE; 1138 } 1139 1140 stat = convert_pixels(act_rect.Width, act_rect.Height, 1141 lockeddata->Stride, lockeddata->Scan0, format, 1142 bitmap->stride, 1143 bitmap->bits + bitmap->stride * act_rect.Y + PIXELFORMATBPP(bitmap->format) * act_rect.X / 8, 1144 bitmap->format, bitmap->image.palette); 1145 1146 if (stat != Ok) 1147 { 1148 heap_free(bitmap->bitmapbits); 1149 bitmap->bitmapbits = NULL; 1150 image_unlock(&bitmap->image, unlock); 1151 return stat; 1152 } 1153 } 1154 1155 bitmap->lockmode = flags | ImageLockModeRead; 1156 bitmap->lockx = act_rect.X; 1157 bitmap->locky = act_rect.Y; 1158 1159 image_unlock(&bitmap->image, unlock); 1160 return Ok; 1161 } 1162 1163 GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi) 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 1176 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap, 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 1237 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height, 1238 PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap) 1239 { 1240 Rect area; 1241 GpStatus stat; 1242 1243 TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap); 1244 1245 if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap || 1246 x < 0 || y < 0 || 1247 x + width > srcBitmap->width || y + height > srcBitmap->height) 1248 { 1249 TRACE("<-- InvalidParameter\n"); 1250 return InvalidParameter; 1251 } 1252 1253 if (format == PixelFormatDontCare) 1254 format = srcBitmap->format; 1255 1256 area.X = gdip_round(x); 1257 area.Y = gdip_round(y); 1258 area.Width = gdip_round(width); 1259 area.Height = gdip_round(height); 1260 1261 stat = GdipCreateBitmapFromScan0(area.Width, area.Height, 0, format, NULL, dstBitmap); 1262 if (stat == Ok) 1263 { 1264 stat = convert_pixels(area.Width, area.Height, (*dstBitmap)->stride, (*dstBitmap)->bits, (*dstBitmap)->format, 1265 srcBitmap->stride, 1266 srcBitmap->bits + srcBitmap->stride * area.Y + PIXELFORMATBPP(srcBitmap->format) * area.X / 8, 1267 srcBitmap->format, srcBitmap->image.palette); 1268 1269 if (stat == Ok && srcBitmap->image.palette) 1270 { 1271 ColorPalette *src_palette, *dst_palette; 1272 1273 src_palette = srcBitmap->image.palette; 1274 1275 dst_palette = heap_alloc_zero(sizeof(UINT) * 2 + sizeof(ARGB) * src_palette->Count); 1276 1277 if (dst_palette) 1278 { 1279 dst_palette->Flags = src_palette->Flags; 1280 dst_palette->Count = src_palette->Count; 1281 memcpy(dst_palette->Entries, src_palette->Entries, sizeof(ARGB) * src_palette->Count); 1282 1283 heap_free((*dstBitmap)->image.palette); 1284 (*dstBitmap)->image.palette = dst_palette; 1285 } 1286 else 1287 stat = OutOfMemory; 1288 } 1289 1290 if (stat != Ok) 1291 GdipDisposeImage(&(*dstBitmap)->image); 1292 } 1293 1294 if (stat != Ok) 1295 *dstBitmap = NULL; 1296 1297 return stat; 1298 } 1299 1300 GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height, 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 1308 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage) 1309 { 1310 TRACE("%p, %p\n", image, cloneImage); 1311 1312 if (!image || !cloneImage) 1313 return InvalidParameter; 1314 1315 if (image->type == ImageTypeBitmap) 1316 { 1317 GpBitmap *bitmap = (GpBitmap *)image; 1318 1319 return GdipCloneBitmapAreaI(0, 0, bitmap->width, bitmap->height, 1320 bitmap->format, bitmap, (GpBitmap **)cloneImage); 1321 } 1322 else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf) 1323 { 1324 GpMetafile *result, *metafile; 1325 1326 metafile = (GpMetafile*)image; 1327 1328 result = heap_alloc_zero(sizeof(*result)); 1329 if (!result) 1330 return OutOfMemory; 1331 1332 result->image.type = ImageTypeMetafile; 1333 result->image.format = image->format; 1334 result->image.flags = image->flags; 1335 result->image.frame_count = 1; 1336 result->image.xres = image->xres; 1337 result->image.yres = image->yres; 1338 result->bounds = metafile->bounds; 1339 result->unit = metafile->unit; 1340 result->metafile_type = metafile->metafile_type; 1341 result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL); 1342 list_init(&result->containers); 1343 1344 if (!result->hemf) 1345 { 1346 heap_free(result); 1347 return OutOfMemory; 1348 } 1349 1350 *cloneImage = &result->image; 1351 return Ok; 1352 } 1353 else 1354 { 1355 WARN("GpImage with no image data (metafile in wrong state?)\n"); 1356 return InvalidParameter; 1357 } 1358 } 1359 1360 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename, 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 1373 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream); 1374 1375 if(stat != Ok) 1376 return stat; 1377 1378 stat = GdipCreateBitmapFromStream(stream, bitmap); 1379 1380 IStream_Release(stream); 1381 1382 return stat; 1383 } 1384 1385 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info, 1386 VOID *bits, GpBitmap **bitmap) 1387 { 1388 DWORD height, stride; 1389 PixelFormat format; 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: 1407 format = PixelFormat1bppIndexed; 1408 break; 1409 case 4: 1410 format = PixelFormat4bppIndexed; 1411 break; 1412 case 8: 1413 format = PixelFormat8bppIndexed; 1414 break; 1415 case 16: 1416 format = PixelFormat16bppRGB555; 1417 break; 1418 case 24: 1419 format = PixelFormat24bppRGB; 1420 break; 1421 case 32: 1422 format = PixelFormat32bppRGB; 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 */ 1436 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename, 1437 GpBitmap **bitmap) 1438 { 1439 TRACE("(%s) %p\n", debugstr_w(filename), bitmap); 1440 1441 return GdipCreateBitmapFromFile(filename, bitmap); 1442 } 1443 1444 GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance, 1445 GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap) 1446 { 1447 HBITMAP hbm; 1448 GpStatus stat = InvalidParameter; 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, 1457 LR_CREATEDIBSECTION); 1458 1459 if(hbm){ 1460 stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap); 1461 DeleteObject(hbm); 1462 } 1463 1464 return stat; 1465 } 1466 1467 static inline DWORD blend_argb_no_bkgnd_alpha(DWORD src, DWORD bkgnd) 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 1479 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap, 1480 HBITMAP* hbmReturn, ARGB background) 1481 { 1482 GpStatus stat; 1483 HBITMAP result; 1484 UINT width, height; 1485 BITMAPINFOHEADER bih; 1486 LPBYTE bits; 1487 BOOL unlock; 1488 1489 TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background); 1490 1491 if (!bitmap || !hbmReturn) return InvalidParameter; 1492 if (!image_lock(&bitmap->image, &unlock)) return ObjectBusy; 1493 1494 GdipGetImageWidth(&bitmap->image, &width); 1495 GdipGetImageHeight(&bitmap->image, &height); 1496 1497 bih.biSize = sizeof(bih); 1498 bih.biWidth = width; 1499 bih.biHeight = height; 1500 bih.biPlanes = 1; 1501 bih.biBitCount = 32; 1502 bih.biCompression = BI_RGB; 1503 bih.biSizeImage = 0; 1504 bih.biXPelsPerMeter = 0; 1505 bih.biYPelsPerMeter = 0; 1506 bih.biClrUsed = 0; 1507 bih.biClrImportant = 0; 1508 1509 result = CreateDIBSection(0, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&bits, NULL, 0); 1510 if (!result) 1511 { 1512 image_unlock(&bitmap->image, unlock); 1513 return GenericError; 1514 } 1515 1516 stat = convert_pixels(width, height, -width*4, 1517 bits + (width * 4 * (height - 1)), PixelFormat32bppPARGB, 1518 bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette); 1519 if (stat != Ok) 1520 { 1521 DeleteObject(result); 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 1542 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height, 1543 GpGraphics* target, GpBitmap** bitmap) 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 1552 ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB, 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 1564 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap) 1565 { 1566 GpStatus stat; 1567 ICONINFO iinfo; 1568 BITMAP bm; 1569 int ret; 1570 UINT width, height, stride; 1571 GpRect rect; 1572 BitmapData lockeddata; 1573 HDC screendc; 1574 BOOL has_alpha; 1575 int x, y; 1576 BITMAPINFOHEADER bih; 1577 DWORD *src; 1578 BYTE *dst_row; 1579 DWORD *dst; 1580 1581 TRACE("%p, %p\n", hicon, bitmap); 1582 1583 if(!bitmap || !GetIconInfo(hicon, &iinfo)) 1584 return InvalidParameter; 1585 1586 /* get the size of the icon */ 1587 ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm); 1588 if (ret == 0) { 1589 DeleteObject(iinfo.hbmColor); 1590 DeleteObject(iinfo.hbmMask); 1591 return GenericError; 1592 } 1593 1594 width = bm.bmWidth; 1595 height = iinfo.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2; 1596 stride = width * 4; 1597 1598 stat = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat32bppARGB, NULL, bitmap); 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 1610 stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata); 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 { 1658 BYTE *bits = heap_alloc(height * stride); 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 1708 static void generate_halftone_palette(ARGB *entries, UINT count) 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 1746 static GpStatus get_screen_resolution(REAL *xres, REAL *yres) 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 1760 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride, 1761 PixelFormat format, BYTE* scan0, GpBitmap** bitmap) 1762 { 1763 HBITMAP hbitmap=NULL; 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 1790 if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0) 1791 { 1792 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)]; 1793 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf; 1794 1795 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 1796 pbmi->bmiHeader.biWidth = width; 1797 pbmi->bmiHeader.biHeight = -height; 1798 pbmi->bmiHeader.biPlanes = 1; 1799 /* FIXME: use the rest of the data from format */ 1800 pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format); 1801 pbmi->bmiHeader.biCompression = BI_RGB; 1802 pbmi->bmiHeader.biSizeImage = 0; 1803 pbmi->bmiHeader.biXPelsPerMeter = 0; 1804 pbmi->bmiHeader.biYPelsPerMeter = 0; 1805 pbmi->bmiHeader.biClrUsed = 0; 1806 pbmi->bmiHeader.biClrImportant = 0; 1807 1808 hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); 1809 1810 if (!hbitmap) return GenericError; 1811 1812 stride = dib_stride; 1813 } 1814 else 1815 { 1816 /* Not a GDI format; don't try to make an HBITMAP. */ 1817 if (scan0) 1818 bits = scan0; 1819 else 1820 { 1821 INT size = abs(stride) * height; 1822 1823 own_bits = bits = heap_alloc_zero(size); 1824 if (!own_bits) return OutOfMemory; 1825 1826 if (stride < 0) 1827 bits += stride * (1 - height); 1828 } 1829 } 1830 1831 *bitmap = heap_alloc_zero(sizeof(GpBitmap)); 1832 if(!*bitmap) 1833 { 1834 DeleteObject(hbitmap); 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 */ 1861 if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed)) 1862 (*bitmap)->image.flags |= ImageFlagsHasAlpha; 1863 1864 if (format == PixelFormat1bppIndexed || 1865 format == PixelFormat4bppIndexed || 1866 format == PixelFormat8bppIndexed) 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 1879 if (format == PixelFormat1bppIndexed) 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 { 1887 if (format == PixelFormat8bppIndexed) 1888 (*bitmap)->image.palette->Flags = PaletteFlagsHalftone; 1889 1890 generate_halftone_palette((*bitmap)->image.palette->Entries, 1891 (*bitmap)->image.palette->Count); 1892 } 1893 } 1894 1895 TRACE("<-- %p\n", *bitmap); 1896 1897 return Ok; 1898 } 1899 1900 #ifdef __REACTOS__ 1901 static HBITMAP hbitmap_from_emf(HENHMETAFILE hemf) 1902 { 1903 BITMAPINFO bmi; 1904 HBITMAP hbm; 1905 SIZE size; 1906 ENHMETAHEADER header; 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 1922 hdc = CreateCompatibleDC(NULL); 1923 hbm = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); 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 1935 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream, 1936 GpBitmap **bitmap) 1937 { 1938 GpStatus stat; 1939 1940 TRACE("%p %p\n", stream, bitmap); 1941 1942 stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap); 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 1955 GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap); 1956 DeleteObject(hbm); 1957 } 1958 else 1959 #endif 1960 if((*bitmap)->image.type != ImageTypeBitmap){ 1961 GdipDisposeImage(&(*bitmap)->image); 1962 *bitmap = NULL; 1963 return GenericError; /* FIXME: what error to return? */ 1964 } 1965 1966 return Ok; 1967 } 1968 1969 /* FIXME: no icm */ 1970 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream, 1971 GpBitmap **bitmap) 1972 { 1973 TRACE("%p %p\n", stream, bitmap); 1974 1975 return GdipCreateBitmapFromStream(stream, bitmap); 1976 } 1977 1978 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics, 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 2001 GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon) 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 2014 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, 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 2055 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp) 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 2068 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics, 2069 GpCachedBitmap *cachedbmp, INT x, INT y) 2070 { 2071 TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y); 2072 2073 if(!graphics || !cachedbmp) 2074 return InvalidParameter; 2075 2076 return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y); 2077 } 2078 2079 /* Internal utility function: Replace the image data of dst with that of src, 2080 * and free src. */ 2081 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette) 2082 { 2083 assert(src->image.type == ImageTypeBitmap); 2084 assert(dst->image.type == ImageTypeBitmap); 2085 2086 heap_free(dst->bitmapbits); 2087 heap_free(dst->own_bits); 2088 DeleteDC(dst->hdc); 2089 DeleteObject(dst->hbitmap); 2090 2091 if (clobber_palette) 2092 { 2093 heap_free(dst->image.palette); 2094 dst->image.palette = src->image.palette; 2095 } 2096 else 2097 heap_free(src->image.palette); 2098 2099 dst->image.xres = src->image.xres; 2100 dst->image.yres = src->image.yres; 2101 dst->width = src->width; 2102 dst->height = src->height; 2103 dst->format = src->format; 2104 dst->hbitmap = src->hbitmap; 2105 dst->hdc = src->hdc; 2106 dst->bits = src->bits; 2107 dst->stride = src->stride; 2108 dst->own_bits = src->own_bits; 2109 if (dst->metadata_reader) 2110 IWICMetadataReader_Release(dst->metadata_reader); 2111 dst->metadata_reader = src->metadata_reader; 2112 heap_free(dst->prop_item); 2113 dst->prop_item = src->prop_item; 2114 dst->prop_count = src->prop_count; 2115 if (dst->image.decoder) 2116 IWICBitmapDecoder_Release(dst->image.decoder); 2117 dst->image.decoder = src->image.decoder; 2118 dst->image.frame_count = src->image.frame_count; 2119 dst->image.current_frame = src->image.current_frame; 2120 dst->image.format = src->image.format; 2121 2122 src->image.type = ~0; 2123 heap_free(src); 2124 } 2125 2126 static GpStatus free_image_data(GpImage *image) 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); 2136 DeleteObject(((GpBitmap*)image)->hbitmap); 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) 2142 METAFILE_Free((GpMetafile *)image); 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 2155 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image) 2156 { 2157 GpStatus status; 2158 2159 TRACE("%p\n", image); 2160 2161 status = free_image_data(image); 2162 if (status != Ok) return status; 2163 image->type = ~0; 2164 heap_free(image); 2165 2166 return Ok; 2167 } 2168 2169 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item) 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 2184 GpStatus WINGDIPAPI GdipGetImageItemData(GpImage *image, ImageItemData *item) 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 2196 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect, 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 2224 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width, 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 2249 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image, 2250 GpGraphics **graphics) 2251 { 2252 HDC hdc; 2253 GpStatus stat; 2254 2255 TRACE("%p %p\n", image, graphics); 2256 2257 if(!image || !graphics) 2258 return InvalidParameter; 2259 2260 if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap) 2261 { 2262 hdc = ((GpBitmap*)image)->hdc; 2263 2264 if(!hdc){ 2265 hdc = CreateCompatibleDC(0); 2266 SelectObject(hdc, ((GpBitmap*)image)->hbitmap); 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) 2280 stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics); 2281 else 2282 stat = graphics_from_image(image, graphics); 2283 2284 return stat; 2285 } 2286 2287 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height) 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 2309 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res) 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 2321 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size) 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 */ 2339 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format) 2340 { 2341 TRACE("%p %p\n", image, format); 2342 2343 if(!image || !format) 2344 return InvalidParameter; 2345 2346 if(image->type != ImageTypeBitmap) 2347 *format = PixelFormat24bppRGB; 2348 else 2349 *format = ((GpBitmap*) image)->format; 2350 2351 return Ok; 2352 } 2353 2354 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format) 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 2366 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type) 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 2378 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res) 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 2390 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width) 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 2412 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num) 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 2435 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID *list) 2436 { 2437 HRESULT hr; 2438 IWICMetadataReader *reader; 2439 IWICEnumMetadataItem *enumerator; 2440 UINT prop_count, i, items_returned; 2441 2442 TRACE("(%p, %u, %p)\n", image, num, list); 2443 2444 if (!image || !list) return InvalidParameter; 2445 2446 if (image->type != ImageTypeBitmap) 2447 { 2448 FIXME("Not implemented for type %d\n", image->type); 2449 return NotImplemented; 2450 } 2451 2452 if (((GpBitmap *)image)->prop_item) 2453 { 2454 if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter; 2455 2456 for (i = 0; i < num; i++) 2457 { 2458 list[i] = ((GpBitmap *)image)->prop_item[i].id; 2459 } 2460 2461 return Ok; 2462 } 2463 2464 reader = ((GpBitmap *)image)->metadata_reader; 2465 if (!reader) 2466 { 2467 if (num != 0) return InvalidParameter; 2468 return Ok; 2469 } 2470 2471 hr = IWICMetadataReader_GetCount(reader, &prop_count); 2472 if (FAILED(hr)) return hresult_to_status(hr); 2473 2474 if (num != prop_count) return InvalidParameter; 2475 2476 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator); 2477 if (FAILED(hr)) return hresult_to_status(hr); 2478 2479 IWICEnumMetadataItem_Reset(enumerator); 2480 2481 for (i = 0; i < num; i++) 2482 { 2483 PROPVARIANT id; 2484 2485 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, NULL, &items_returned); 2486 if (hr != S_OK) break; 2487 2488 if (id.vt != VT_UI2) 2489 { 2490 FIXME("not supported propvariant type for id: %u\n", id.vt); 2491 list[i] = 0; 2492 continue; 2493 } 2494 list[i] = id.u.uiVal; 2495 } 2496 2497 IWICEnumMetadataItem_Release(enumerator); 2498 2499 return hr == S_OK ? Ok : hresult_to_status(hr); 2500 } 2501 2502 static UINT propvariant_size(PROPVARIANT *value) 2503 { 2504 switch (value->vt & ~VT_VECTOR) 2505 { 2506 case VT_EMPTY: 2507 return 0; 2508 case VT_I1: 2509 case VT_UI1: 2510 if (!(value->vt & VT_VECTOR)) return 1; 2511 return value->u.caub.cElems; 2512 case VT_I2: 2513 case VT_UI2: 2514 if (!(value->vt & VT_VECTOR)) return 2; 2515 return value->u.caui.cElems * 2; 2516 case VT_I4: 2517 case VT_UI4: 2518 case VT_R4: 2519 if (!(value->vt & VT_VECTOR)) return 4; 2520 return value->u.caul.cElems * 4; 2521 case VT_I8: 2522 case VT_UI8: 2523 case VT_R8: 2524 if (!(value->vt & VT_VECTOR)) return 8; 2525 return value->u.cauh.cElems * 8; 2526 case VT_LPSTR: 2527 return value->u.pszVal ? strlen(value->u.pszVal) + 1 : 0; 2528 case VT_BLOB: 2529 return value->u.blob.cbSize; 2530 default: 2531 FIXME("not supported variant type %d\n", value->vt); 2532 return 0; 2533 } 2534 } 2535 2536 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID propid, UINT *size) 2537 { 2538 HRESULT hr; 2539 IWICMetadataReader *reader; 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 2576 *size = propvariant_size(&value); 2577 if (*size) *size += sizeof(PropertyItem); 2578 PropVariantClear(&value); 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 2590 static UINT vt_to_itemtype(UINT vt) 2591 { 2592 static const struct 2593 { 2594 UINT vt, type; 2595 } vt2type[] = 2596 { 2597 { VT_I1, PropertyTagTypeSByte }, 2598 { VT_UI1, PropertyTagTypeByte }, 2599 { VT_I2, PropertyTagTypeSShort }, 2600 { VT_UI2, PropertyTagTypeShort }, 2601 { VT_I4, PropertyTagTypeSLONG }, 2602 { VT_UI4, PropertyTagTypeLong }, 2603 { VT_I8, PropertyTagTypeSRational }, 2604 { VT_UI8, PropertyTagTypeRational }, 2605 { VT_R4, PropertyTagTypeFloat }, 2606 { VT_R8, PropertyTagTypeDouble }, 2607 { VT_LPSTR, PropertyTagTypeASCII }, 2608 { VT_BLOB, PropertyTagTypeUndefined } 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 2619 static GpStatus propvariant_to_item(PROPVARIANT *value, PropertyItem *item, 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 2682 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID propid, UINT size, 2683 PropertyItem *buffer) 2684 { 2685 GpStatus stat; 2686 HRESULT hr; 2687 IWICMetadataReader *reader; 2688 PROPVARIANT id, value; 2689 2690 TRACE("(%p,%#x,%u,%p)\n", image, propid, size, buffer); 2691 2692 if (!image || !buffer) return InvalidParameter; 2693 2694 if (image->type != ImageTypeBitmap) 2695 { 2696 FIXME("Not implemented for type %d\n", image->type); 2697 return NotImplemented; 2698 } 2699 2700 if (((GpBitmap *)image)->prop_item) 2701 { 2702 UINT i; 2703 2704 for (i = 0; i < ((GpBitmap *)image)->prop_count; i++) 2705 { 2706 if (propid == ((GpBitmap *)image)->prop_item[i].id) 2707 { 2708 if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length) 2709 return InvalidParameter; 2710 2711 *buffer = ((GpBitmap *)image)->prop_item[i]; 2712 buffer->value = buffer + 1; 2713 memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length); 2714 return Ok; 2715 } 2716 } 2717 2718 return PropertyNotFound; 2719 } 2720 2721 reader = ((GpBitmap *)image)->metadata_reader; 2722 if (!reader) return PropertyNotFound; 2723 2724 id.vt = VT_UI2; 2725 id.u.uiVal = propid; 2726 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value); 2727 if (FAILED(hr)) return PropertyNotFound; 2728 2729 stat = propvariant_to_item(&value, buffer, size, propid); 2730 PropVariantClear(&value); 2731 2732 return stat; 2733 } 2734 2735 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT *size, UINT *count) 2736 { 2737 HRESULT hr; 2738 IWICMetadataReader *reader; 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); 2793 PropVariantClear(&value); 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 2805 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size, 2806 UINT count, PropertyItem *buf) 2807 { 2808 GpStatus status; 2809 HRESULT hr; 2810 IWICMetadataReader *reader; 2811 IWICEnumMetadataItem *enumerator; 2812 UINT prop_count, prop_size, i; 2813 PROPVARIANT id, value; 2814 char *item_value; 2815 2816 TRACE("(%p,%u,%u,%p)\n", image, size, count, buf); 2817 2818 if (!image || !buf) return InvalidParameter; 2819 2820 if (image->type != ImageTypeBitmap) 2821 { 2822 FIXME("Not implemented for type %d\n", image->type); 2823 return NotImplemented; 2824 } 2825 2826 status = GdipGetPropertySize(image, &prop_size, &prop_count); 2827 if (status != Ok) return status; 2828 2829 if (prop_count != count || prop_size != size) return InvalidParameter; 2830 2831 if (((GpBitmap *)image)->prop_item) 2832 { 2833 memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size); 2834 2835 item_value = (char *)(buf + prop_count); 2836 2837 for (i = 0; i < prop_count; i++) 2838 { 2839 buf[i].value = item_value; 2840 item_value += buf[i].length; 2841 } 2842 2843 return Ok; 2844 } 2845 2846 reader = ((GpBitmap *)image)->metadata_reader; 2847 if (!reader) return PropertyNotFound; 2848 2849 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator); 2850 if (FAILED(hr)) return hresult_to_status(hr); 2851 2852 IWICEnumMetadataItem_Reset(enumerator); 2853 2854 item_value = (char *)(buf + prop_count); 2855 2856 PropVariantInit(&id); 2857 PropVariantInit(&value); 2858 2859 for (i = 0; i < prop_count; i++) 2860 { 2861 PropertyItem *item; 2862 UINT items_returned, item_size; 2863 2864 hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned); 2865 if (hr != S_OK) break; 2866 2867 if (id.vt != VT_UI2) 2868 { 2869 FIXME("not supported propvariant type for id: %u\n", id.vt); 2870 continue; 2871 } 2872 2873 item_size = propvariant_size(&value); 2874 if (item_size) 2875 { 2876 item = heap_alloc(item_size + sizeof(*item)); 2877 2878 propvariant_to_item(&value, item, item_size + sizeof(*item), id.u.uiVal); 2879 buf[i].id = item->id; 2880 buf[i].type = item->type; 2881 buf[i].length = item_size; 2882 buf[i].value = item_value; 2883 memcpy(item_value, item->value, item_size); 2884 item_value += item_size; 2885 2886 heap_free(item); 2887 } 2888 2889 PropVariantClear(&id); 2890 PropVariantClear(&value); 2891 } 2892 2893 IWICEnumMetadataItem_Release(enumerator); 2894 2895 if (hr != S_OK) return PropertyNotFound; 2896 2897 return Ok; 2898 } 2899 2900 struct image_format_dimension 2901 { 2902 const GUID *format; 2903 const GUID *dimension; 2904 }; 2905 2906 static const struct image_format_dimension image_format_dimensions[] = 2907 { 2908 {&ImageFormatGIF, &FrameDimensionTime}, 2909 {&ImageFormatIcon, &FrameDimensionResolution}, 2910 {NULL} 2911 }; 2912 2913 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image, 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 2933 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image, 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 2948 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image, 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 2976 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename, 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 2989 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream); 2990 2991 if (stat != Ok) 2992 return stat; 2993 2994 stat = GdipLoadImageFromStream(stream, image); 2995 2996 IStream_Release(stream); 2997 2998 return stat; 2999 } 3000 3001 /* FIXME: no icm handling */ 3002 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image) 3003 { 3004 TRACE("(%s) %p\n", debugstr_w(filename), image); 3005 3006 return GdipLoadImageFromFile(filename, image); 3007 } 3008 3009 static void add_property(GpBitmap *bitmap, PropertyItem *item) 3010 { 3011 UINT prop_size, prop_count; 3012 PropertyItem *prop_item; 3013 3014 if (bitmap->prop_item == NULL) 3015 { 3016 prop_size = prop_count = 0; 3017 prop_item = heap_alloc_zero(item->length + sizeof(PropertyItem)); 3018 if (!prop_item) return; 3019 } 3020 else 3021 { 3022 UINT i; 3023 char *item_value; 3024 3025 GdipGetPropertySize(&bitmap->image, &prop_size, &prop_count); 3026 3027 prop_item = heap_alloc_zero(prop_size + item->length + sizeof(PropertyItem)); 3028 if (!prop_item) return; 3029 memcpy(prop_item, bitmap->prop_item, sizeof(PropertyItem) * bitmap->prop_count); 3030 prop_size -= sizeof(PropertyItem) * bitmap->prop_count; 3031 memcpy(prop_item + prop_count + 1, bitmap->prop_item + prop_count, prop_size); 3032 3033 item_value = (char *)(prop_item + prop_count + 1); 3034 3035 for (i = 0; i < prop_count; i++) 3036 { 3037 prop_item[i].value = item_value; 3038 item_value += prop_item[i].length; 3039 } 3040 } 3041 3042 prop_item[prop_count].id = item->id; 3043 prop_item[prop_count].type = item->type; 3044 prop_item[prop_count].length = item->length; 3045 prop_item[prop_count].value = (char *)(prop_item + prop_count + 1) + prop_size; 3046 memcpy(prop_item[prop_count].value, item->value, item->length); 3047 3048 heap_free(bitmap->prop_item); 3049 bitmap->prop_item = prop_item; 3050 bitmap->prop_count++; 3051 } 3052 3053 static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name) 3054 { 3055 HRESULT hr; 3056 GUID format; 3057 PROPVARIANT id, value; 3058 BOOL ret = FALSE; 3059 3060 hr = IWICMetadataReader_GetMetadataFormat(reader, &format); 3061 if (FAILED(hr) || !IsEqualGUID(&format, guid)) return FALSE; 3062 3063 PropVariantInit(&id); 3064 PropVariantInit(&value); 3065 3066 id.vt = VT_LPWSTR; 3067 id.u.pwszVal = CoTaskMemAlloc((lstrlenW(prop_name) + 1) * sizeof(WCHAR)); 3068 if (!id.u.pwszVal) return FALSE; 3069 lstrcpyW(id.u.pwszVal, prop_name); 3070 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value); 3071 if (hr == S_OK && value.vt == VT_BOOL) 3072 ret = value.u.boolVal; 3073 3074 PropVariantClear(&id); 3075 PropVariantClear(&value); 3076 3077 return ret; 3078 } 3079 3080 static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name) 3081 { 3082 HRESULT hr; 3083 GUID format; 3084 PROPVARIANT id, value; 3085 PropertyItem *item = NULL; 3086 3087 hr = IWICMetadataReader_GetMetadataFormat(reader, &format); 3088 if (FAILED(hr) || !IsEqualGUID(&format, guid)) return NULL; 3089 3090 PropVariantInit(&id); 3091 PropVariantInit(&value); 3092 3093 id.vt = VT_LPWSTR; 3094 id.u.pwszVal = CoTaskMemAlloc((lstrlenW(prop_name) + 1) * sizeof(WCHAR)); 3095 if (!id.u.pwszVal) return NULL; 3096 lstrcpyW(id.u.pwszVal, prop_name); 3097 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value); 3098 if (hr == S_OK) 3099 { 3100 UINT item_size = propvariant_size(&value); 3101 if (item_size) 3102 { 3103 item_size += sizeof(*item); 3104 item = heap_alloc_zero(item_size); 3105 if (propvariant_to_item(&value, item, item_size, 0) != Ok) 3106 { 3107 heap_free(item); 3108 item = NULL; 3109 } 3110 } 3111 } 3112 3113 PropVariantClear(&id); 3114 PropVariantClear(&value); 3115 3116 return item; 3117 } 3118 3119 static PropertyItem *get_gif_comment(IWICMetadataReader *reader) 3120 { 3121 static const WCHAR textentryW[] = { 'T','e','x','t','E','n','t','r','y',0 }; 3122 PropertyItem *comment; 3123 3124 comment = get_property(reader, &GUID_MetadataFormatGifComment, textentryW); 3125 if (comment) 3126 comment->id = PropertyTagExifUserComment; 3127 3128 return comment; 3129 } 3130 3131 static PropertyItem *get_gif_loopcount(IWICMetadataReader *reader) 3132 { 3133 static const WCHAR applicationW[] = { 'A','p','p','l','i','c','a','t','i','o','n',0 }; 3134 static const WCHAR dataW[] = { 'D','a','t','a',0 }; 3135 PropertyItem *appext = NULL, *appdata = NULL, *loop = NULL; 3136 3137 appext = get_property(reader, &GUID_MetadataFormatAPE, applicationW); 3138 if (appext) 3139 { 3140 if (appext->type == PropertyTagTypeByte && appext->length == 11 && 3141 (!memcmp(appext->value, "NETSCAPE2.0", 11) || !memcmp(appext->value, "ANIMEXTS1.0", 11))) 3142 { 3143 appdata = get_property(reader, &GUID_MetadataFormatAPE, dataW); 3144 if (appdata) 3145 { 3146 if (appdata->type == PropertyTagTypeByte && appdata->length == 4) 3147 { 3148 BYTE *data = appdata->value; 3149 if (data[0] == 3 && data[1] == 1) 3150 { 3151 loop = heap_alloc_zero(sizeof(*loop) + sizeof(SHORT)); 3152 if (loop) 3153 { 3154 loop->type = PropertyTagTypeShort; 3155 loop->id = PropertyTagLoopCount; 3156 loop->length = sizeof(SHORT); 3157 loop->value = loop + 1; 3158 *(SHORT *)loop->value = data[2] | (data[3] << 8); 3159 } 3160 } 3161 } 3162 } 3163 } 3164 } 3165 3166 heap_free(appext); 3167 heap_free(appdata); 3168 3169 return loop; 3170 } 3171 3172 static PropertyItem *get_gif_background(IWICMetadataReader *reader) 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 3184 static PropertyItem *get_gif_palette(IWICBitmapDecoder *decoder, IWICMetadataReader *reader) 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; 3188 IWICImagingFactory *factory; 3189 IWICPalette *palette; 3190 UINT count = 0; 3191 WICColor colors[256]; 3192 3193 if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW)) 3194 return NULL; 3195 3196 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); 3197 if (hr != S_OK) return NULL; 3198 3199 hr = IWICImagingFactory_CreatePalette(factory, &palette); 3200 if (hr == S_OK) 3201 { 3202 hr = IWICBitmapDecoder_CopyPalette(decoder, palette); 3203 if (hr == S_OK) 3204 IWICPalette_GetColors(palette, 256, colors, &count); 3205 3206 IWICPalette_Release(palette); 3207 } 3208 3209 IWICImagingFactory_Release(factory); 3210 3211 if (count) 3212 { 3213 PropertyItem *pal; 3214 UINT i; 3215 BYTE *rgb; 3216 3217 pal = heap_alloc_zero(sizeof(*pal) + count * 3); 3218 if (!pal) return NULL; 3219 pal->type = PropertyTagTypeByte; 3220 pal->id = PropertyTagGlobalPalette; 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 3239 static PropertyItem *get_gif_transparent_idx(IWICMetadataReader *reader) 3240 { 3241 static const WCHAR transparency_flagW[] = { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 }; 3242 static const WCHAR colorW[] = { 'T','r','a','n','s','p','a','r','e','n','t','C','o','l','o','r','I','n','d','e','x',0 }; 3243 PropertyItem *index = NULL; 3244 3245 if (get_bool_property(reader, &GUID_MetadataFormatGCE, transparency_flagW)) 3246 { 3247 index = get_property(reader, &GUID_MetadataFormatGCE, colorW); 3248 if (index) 3249 index->id = PropertyTagIndexTransparent; 3250 } 3251 return index; 3252 } 3253 3254 static LONG get_gif_frame_property(IWICBitmapFrameDecode *frame, const GUID *format, const WCHAR *property) 3255 { 3256 HRESULT hr; 3257 IWICMetadataBlockReader *block_reader; 3258 IWICMetadataReader *reader; 3259 UINT block_count, i; 3260 PropertyItem *prop; 3261 LONG value = 0; 3262 3263 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader); 3264 if (hr == S_OK) 3265 { 3266 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count); 3267 if (hr == S_OK) 3268 { 3269 for (i = 0; i < block_count; i++) 3270 { 3271 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader); 3272 if (hr == S_OK) 3273 { 3274 prop = get_property(reader, format, property); 3275 if (prop) 3276 { 3277 if (prop->type == PropertyTagTypeByte && prop->length == 1) 3278 value = *(BYTE *)prop->value; 3279 else if (prop->type == PropertyTagTypeShort && prop->length == 2) 3280 value = *(SHORT *)prop->value; 3281 3282 heap_free(prop); 3283 } 3284 IWICMetadataReader_Release(reader); 3285 } 3286 } 3287 } 3288 IWICMetadataBlockReader_Release(block_reader); 3289 } 3290 3291 return value; 3292 } 3293 3294 static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame) 3295 { 3296 static const WCHAR delayW[] = { 'D','e','l','a','y',0 }; 3297 HRESULT hr; 3298 IWICBitmapFrameDecode *frame; 3299 IWICMetadataBlockReader *block_reader; 3300 IWICMetadataReader *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) 3345 comment = get_gif_comment(reader); 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); 3377 if (comment) add_property(bitmap, comment); 3378 if (loop) add_property(bitmap, loop); 3379 if (palette) add_property(bitmap, palette); 3380 if (background) add_property(bitmap, background); 3381 3382 heap_free(delay); 3383 heap_free(comment); 3384 heap_free(loop); 3385 heap_free(palette); 3386 heap_free(background); 3387 3388 /* Win7 gdiplus always returns transparent color index from frame 0 */ 3389 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); 3390 if (hr != S_OK) return; 3391 3392 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader); 3393 if (hr == S_OK) 3394 { 3395 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count); 3396 if (hr == S_OK) 3397 { 3398 for (i = 0; i < block_count; i++) 3399 { 3400 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader); 3401 if (hr == S_OK) 3402 { 3403 if (!transparent_idx) 3404 transparent_idx = get_gif_transparent_idx(reader); 3405 3406 IWICMetadataReader_Release(reader); 3407 } 3408 } 3409 } 3410 IWICMetadataBlockReader_Release(block_reader); 3411 } 3412 3413 if (transparent_idx) add_property(bitmap, transparent_idx); 3414 heap_free(transparent_idx); 3415 3416 IWICBitmapFrameDecode_Release(frame); 3417 } 3418 3419 static PropertyItem* create_prop(PROPID propid, PROPVARIANT* value) 3420 { 3421 PropertyItem *item = NULL; 3422 UINT item_size = propvariant_size(value); 3423 3424 if (item_size) 3425 { 3426 item_size += sizeof(*item); 3427 item = heap_alloc_zero(item_size); 3428 if (propvariant_to_item(value, item, item_size, propid) != Ok) 3429 { 3430 heap_free(item); 3431 item = NULL; 3432 } 3433 } 3434 3435 return item; 3436 } 3437 3438 static ULONG get_ulong_by_index(IWICMetadataReader* reader, ULONG index) 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 } 3456 PropVariantClear(&value); 3457 } 3458 return result; 3459 } 3460 3461 static void png_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame) 3462 { 3463 HRESULT hr; 3464 IWICBitmapFrameDecode *frame; 3465 IWICMetadataBlockReader *block_reader; 3466 IWICMetadataReader *reader; 3467 UINT block_count, i, j; 3468 struct keyword_info { 3469 const char* name; 3470 PROPID propid; 3471 BOOL seen; 3472 } keywords[] = { 3473 { "Title", PropertyTagImageTitle }, 3474 { "Author", PropertyTagArtist }, 3475 { "Description", PropertyTagImageDescription }, 3476 { "Copyright", PropertyTagCopyright }, 3477 { "Software", PropertyTagSoftwareUsed }, 3478 { "Source", PropertyTagEquipModel }, 3479 { "Comment", PropertyTagExifUserComment }, 3480 }; 3481 BOOL seen_gamma=FALSE, seen_whitepoint=FALSE, seen_chrm=FALSE; 3482 3483 hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame); 3484 if (hr != S_OK) return; 3485 3486 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader); 3487 if (hr == S_OK) 3488 { 3489 hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count); 3490 if (hr == S_OK) 3491 { 3492 for (i = 0; i < block_count; i++) 3493 { 3494 hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader); 3495 if (hr == S_OK) 3496 { 3497 GUID format; 3498 3499 hr = IWICMetadataReader_GetMetadataFormat(reader, &format); 3500 if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunktEXt, &format)) 3501 { 3502 PROPVARIANT name, value; 3503 PropertyItem* item; 3504 3505 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &name, &value); 3506 3507 if (SUCCEEDED(hr)) 3508 { 3509 if (name.vt == VT_LPSTR) 3510 { 3511 for (j = 0; j < ARRAY_SIZE(keywords); j++) 3512 if (!strcmp(keywords[j].name, name.u.pszVal)) 3513 break; 3514 if (j < ARRAY_SIZE(keywords) && !keywords[j].seen) 3515 { 3516 keywords[j].seen = TRUE; 3517 item = create_prop(keywords[j].propid, &value); 3518 if (item) 3519 add_property(bitmap, item); 3520 heap_free(item); 3521 } 3522 } 3523 3524 PropVariantClear(&name); 3525 PropVariantClear(&value); 3526 } 3527 } 3528 else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkgAMA, &format)) 3529 { 3530 PropertyItem* item; 3531 3532 if (!seen_gamma) 3533 { 3534 item = heap_alloc_zero(sizeof(PropertyItem) + sizeof(ULONG) * 2); 3535 if (item) 3536 { 3537 ULONG *rational; 3538 item->length = sizeof(ULONG) * 2; 3539 item->type = PropertyTagTypeRational; 3540 item->id = PropertyTagGamma; 3541 rational = item->value = item + 1; 3542 rational[0] = 100000; 3543 rational[1] = get_ulong_by_index(reader, 0); 3544 add_property(bitmap, item); 3545 seen_gamma = TRUE; 3546 heap_free(item); 3547 } 3548 } 3549 } 3550 else if (SUCCEEDED(hr) && IsEqualGUID(&GUID_MetadataFormatChunkcHRM, &format)) 3551 { 3552 PropertyItem* item; 3553 3554 if (!seen_whitepoint) 3555 { 3556 item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 4); 3557 if (item) 3558 { 3559 ULONG *rational; 3560 item->length = sizeof(ULONG) * 4; 3561 item->type = PropertyTagTypeRational; 3562 item->id = PropertyTagWhitePoint; 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; 3568 add_property(bitmap, item); 3569 seen_whitepoint = TRUE; 3570 GdipFree(item); 3571 } 3572 } 3573 if (!seen_chrm) 3574 { 3575 item = GdipAlloc(sizeof(PropertyItem) + sizeof(ULONG) * 12); 3576 if (item) 3577 { 3578 ULONG *rational; 3579 item->length = sizeof(ULONG) * 12; 3580 item->type = PropertyTagTypeRational; 3581 item->id = PropertyTagPrimaryChromaticities; 3582 rational = item->value = item + 1; 3583 rational[0] = get_ulong_by_index(reader, 2); 3584 rational[1] = 100000; 3585 rational[2] = get_ulong_by_index(reader, 3); 3586 rational[3] = 100000; 3587 rational[4] = get_ulong_by_index(reader, 4); 3588 rational[5] = 100000; 3589 rational[6] = get_ulong_by_index(reader, 5); 3590 rational[7] = 100000; 3591 rational[8] = get_ulong_by_index(reader, 6); 3592 rational[9] = 100000; 3593 rational[10] = get_ulong_by_index(reader, 7); 3594 rational[11] = 100000; 3595 add_property(bitmap, item); 3596 seen_chrm = TRUE; 3597 GdipFree(item); 3598 } 3599 } 3600 } 3601 3602 IWICMetadataReader_Release(reader); 3603 } 3604 } 3605 } 3606 IWICMetadataBlockReader_Release(block_reader); 3607 } 3608 3609 IWICBitmapFrameDecode_Release(frame); 3610 } 3611 3612 static GpStatus initialize_decoder_wic(IStream *stream, REFGUID container, IWICBitmapDecoder **decoder) 3613 { 3614 IWICImagingFactory *factory; 3615 HRESULT hr; 3616 3617 TRACE("%p,%s\n", stream, wine_dbgstr_guid(container)); 3618 3619 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); 3620 if (FAILED(hr)) return hresult_to_status(hr); 3621 hr = IWICImagingFactory_CreateDecoder(factory, container, NULL, decoder); 3622 IWICImagingFactory_Release(factory); 3623 if (FAILED(hr)) return hresult_to_status(hr); 3624 3625 hr = IWICBitmapDecoder_Initialize(*decoder, stream, WICDecodeMetadataCacheOnLoad); 3626 if (FAILED(hr)) return hresult_to_status(hr); 3627 return Ok; 3628 } 3629 3630 typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame); 3631 3632 static GpStatus decode_frame_wic(IWICBitmapDecoder *decoder, BOOL force_conversion, 3633 UINT active_frame, metadata_reader_func metadata_reader, GpImage **image) 3634 { 3635 GpStatus status=Ok; 3636 GpBitmap *bitmap; 3637 HRESULT hr; 3638 IWICBitmapFrameDecode *frame; 3639 IWICBitmapSource *source=NULL; 3640 IWICMetadataBlockReader *block_reader; 3641 WICPixelFormatGUID wic_format; 3642 PixelFormat gdip_format=0; 3643 ColorPalette *palette = NULL; 3644 WICBitmapPaletteType palette_type = WICBitmapPaletteTypeFixedHalftone256; 3645 int i; 3646 UINT width, height, frame_count; 3647 BitmapData lockeddata; 3648 WICRect wrc; 3649 3650 TRACE("%p,%u,%p\n", decoder, active_frame, image); 3651 3652 IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); 3653 hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame); 3654 if (SUCCEEDED(hr)) /* got frame */ 3655 { 3656 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format); 3657 3658 if (SUCCEEDED(hr)) 3659 { 3660 if (!force_conversion) 3661 { 3662 for (i=0; pixel_formats[i].wic_format; i++) 3663 { 3664 if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format)) 3665 { 3666 source = (IWICBitmapSource*)frame; 3667 IWICBitmapSource_AddRef(source); 3668 gdip_format = pixel_formats[i].gdip_format; 3669 palette_type = pixel_formats[i].palette_type; 3670 break; 3671 } 3672 } 3673 } 3674 if (!source) 3675 { 3676 /* unknown format; fall back on 32bppARGB */ 3677 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source); 3678 gdip_format = PixelFormat32bppARGB; 3679 } 3680 TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format); 3681 } 3682 3683 if (SUCCEEDED(hr)) /* got source */ 3684 { 3685 hr = IWICBitmapSource_GetSize(source, &width, &height); 3686 3687 if (SUCCEEDED(hr)) 3688 status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format, 3689 NULL, &bitmap); 3690 3691 if (SUCCEEDED(hr) && status == Ok) /* created bitmap */ 3692 { 3693 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite, 3694 gdip_format, &lockeddata); 3695 if (status == Ok) /* locked bitmap */ 3696 { 3697 wrc.X = 0; 3698 wrc.Width = width; 3699 wrc.Height = 1; 3700 for (i=0; i<height; i++) 3701 { 3702 wrc.Y = i; 3703 hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride), 3704 abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i); 3705 if (FAILED(hr)) break; 3706 } 3707 3708 GdipBitmapUnlockBits(bitmap, &lockeddata); 3709 } 3710 3711 if (SUCCEEDED(hr) && status == Ok) 3712 *image = &bitmap->image; 3713 else 3714 { 3715 *image = NULL; 3716 GdipDisposeImage(&bitmap->image); 3717 } 3718 3719 if (SUCCEEDED(hr) && status == Ok) 3720 { 3721 double dpix, dpiy; 3722 hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy); 3723 if (SUCCEEDED(hr)) 3724 { 3725 bitmap->image.xres = dpix; 3726 bitmap->image.yres = dpiy; 3727 } 3728 hr = S_OK; 3729 } 3730 } 3731 3732 IWICBitmapSource_Release(source); 3733 } 3734 3735 if (SUCCEEDED(hr)) { 3736 bitmap->metadata_reader = NULL; 3737 3738 if (metadata_reader) 3739 metadata_reader(bitmap, decoder, active_frame); 3740 else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK) 3741 { 3742 UINT block_count = 0; 3743 if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count) 3744 IWICMetadataBlockReader_GetReaderByIndex(block_reader, 0, &bitmap->metadata_reader); 3745 IWICMetadataBlockReader_Release(block_reader); 3746 } 3747 3748 palette = get_palette(frame, palette_type); 3749 IWICBitmapFrameDecode_Release(frame); 3750 } 3751 } 3752 3753 if (FAILED(hr) && status == Ok) status = hresult_to_status(hr); 3754 3755 if (status == Ok) 3756 { 3757 /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */ 3758 bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI; 3759 if (IsEqualGUID(&wic_format, &GUID_WICPixelFormat2bppGray) || 3760 IsEqualGUID(&wic_format, &GUID_WICPixelFormat4bppGray) || 3761 IsEqualGUID(&wic_format, &GUID_WICPixelFormat8bppGray) || 3762 IsEqualGUID(&wic_format, &GUID_WICPixelFormat16bppGray)) 3763 bitmap->image.flags |= ImageFlagsColorSpaceGRAY; 3764 else 3765 bitmap->image.flags |= ImageFlagsColorSpaceRGB; 3766 bitmap->image.frame_count = frame_count; 3767 bitmap->image.current_frame = active_frame; 3768 bitmap->image.decoder = decoder; 3769 IWICBitmapDecoder_AddRef(decoder); 3770 if (palette) 3771 { 3772 heap_free(bitmap->image.palette); 3773 bitmap->image.palette = palette; 3774 } 3775 else 3776 { 3777 if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite)) 3778 bitmap->image.palette->Flags = 0; 3779 } 3780 TRACE("=> %p\n", *image); 3781 } 3782 3783 return status; 3784 } 3785 3786 static GpStatus decode_image_wic(IStream *stream, REFGUID container, 3787 metadata_reader_func metadata_reader, GpImage **image) 3788 { 3789 IWICBitmapDecoder *decoder; 3790 GpStatus status; 3791 3792 status = initialize_decoder_wic(stream, container, &decoder); 3793 if(status != Ok) 3794 return status; 3795 3796 status = decode_frame_wic(decoder, FALSE, 0, metadata_reader, image); 3797 IWICBitmapDecoder_Release(decoder); 3798 return status; 3799 } 3800 3801 static GpStatus select_frame_wic(GpImage *image, UINT active_frame) 3802 { 3803 GpImage *new_image; 3804 GpStatus status; 3805 3806 status = decode_frame_wic(image->decoder, FALSE, active_frame, NULL, &new_image); 3807 if(status != Ok) 3808 return status; 3809 3810 new_image->busy = image->busy; 3811 memcpy(&new_image->format, &image->format, sizeof(GUID)); 3812 free_image_data(image); 3813 if (image->type == ImageTypeBitmap) 3814 *(GpBitmap *)image = *(GpBitmap *)new_image; 3815 else if (image->type == ImageTypeMetafile) 3816 *(GpMetafile *)image = *(GpMetafile *)new_image; 3817 new_image->type = ~0; 3818 heap_free(new_image); 3819 return Ok; 3820 } 3821 3822 static HRESULT get_gif_frame_rect(IWICBitmapFrameDecode *frame, 3823 UINT *left, UINT *top, UINT *width, UINT *height) 3824 { 3825 static const WCHAR leftW[] = {'L','e','f','t',0}; 3826 static const WCHAR topW[] = {'T','o','p',0}; 3827 3828 *left = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, leftW); 3829 *top = get_gif_frame_property(frame, &GUID_MetadataFormatIMD, topW); 3830 3831 return IWICBitmapFrameDecode_GetSize(frame, width, height); 3832 } 3833 3834 static HRESULT blit_gif_frame(GpBitmap *bitmap, IWICBitmapFrameDecode *frame, BOOL first_frame) 3835 { 3836 UINT i, j, left, top, width, height; 3837 IWICBitmapSource *source; 3838 BYTE *new_bits; 3839 HRESULT hr; 3840 3841 hr = get_gif_frame_rect(frame, &left, &top, &width, &height); 3842 if(FAILED(hr)) 3843 return hr; 3844 3845 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source); 3846 if(FAILED(hr)) 3847 return hr; 3848 3849 new_bits = heap_alloc_zero(width*height*4); 3850 if(!new_bits) 3851 return E_OUTOFMEMORY; 3852 3853 hr = IWICBitmapSource_CopyPixels(source, NULL, width*4, width*height*4, new_bits); 3854 IWICBitmapSource_Release(source); 3855 if(FAILED(hr)) { 3856 heap_free(new_bits); 3857 return hr; 3858 } 3859 3860 for(i=0; i<height && i+top<bitmap->height; i++) { 3861 for(j=0; j<width && j+left<bitmap->width; j++) { 3862 DWORD *src = (DWORD*)(new_bits+i*width*4+j*4); 3863 DWORD *dst = (DWORD*)(bitmap->bits+(i+top)*bitmap->stride+(j+left)*4); 3864 3865 if(first_frame || *src>>24 != 0) 3866 *dst = *src; 3867 } 3868 } 3869 heap_free(new_bits); 3870 return hr; 3871 } 3872 3873 static DWORD get_gif_background_color(GpBitmap *bitmap) 3874 { 3875 BYTE bgcolor_idx = 0; 3876 UINT i; 3877 3878 for(i=0; i<bitmap->prop_count; i++) { 3879 if(bitmap->prop_item[i].id == PropertyTagIndexBackground) { 3880 bgcolor_idx = *(BYTE*)bitmap->prop_item[i].value; 3881 break; 3882 } 3883 } 3884 3885 for(i=0; i<bitmap->prop_count; i++) { 3886 if(bitmap->prop_item[i].id == PropertyTagIndexTransparent) { 3887 BYTE transparent_idx; 3888 transparent_idx = *(BYTE*)bitmap->prop_item[i].value; 3889 3890 if(transparent_idx == bgcolor_idx) 3891 return 0; 3892 } 3893 } 3894 3895 for(i=0; i<bitmap->prop_count; i++) { 3896 if(bitmap->prop_item[i].id == PropertyTagGlobalPalette) { 3897 if(bitmap->prop_item[i].length/3 > bgcolor_idx) { 3898 BYTE *color = ((BYTE*)bitmap->prop_item[i].value)+bgcolor_idx*3; 3899 return color[2] + (color[1]<<8) + (color[0]<<16) + (0xffu<<24); 3900 } 3901 break; 3902 } 3903 } 3904 3905 FIXME("can't get gif background color\n"); 3906 return 0xffffffff; 3907 } 3908 3909 static GpStatus select_frame_gif(GpImage* image, UINT active_frame) 3910 { 3911 static const WCHAR disposalW[] = {'D','i','s','p','o','s','a','l',0}; 3912 3913 GpBitmap *bitmap = (GpBitmap*)image; 3914 IWICBitmapFrameDecode *frame; 3915 int cur_frame=0, disposal; 3916 BOOL bgcolor_set = FALSE; 3917 DWORD bgcolor = 0; 3918 HRESULT hr; 3919 3920 if(active_frame > image->current_frame) { 3921 hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, image->current_frame, &frame); 3922 if(FAILED(hr)) 3923 return hresult_to_status(hr); 3924 disposal = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, disposalW); 3925 IWICBitmapFrameDecode_Release(frame); 3926 3927 if(disposal == GIF_DISPOSE_RESTORE_TO_BKGND) 3928 cur_frame = image->current_frame; 3929 else if(disposal != GIF_DISPOSE_RESTORE_TO_PREV) 3930 cur_frame = image->current_frame+1; 3931 } 3932 3933 while(cur_frame != active_frame) { 3934 hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, cur_frame, &frame); 3935 if(FAILED(hr)) 3936 return hresult_to_status(hr); 3937 disposal = get_gif_frame_property(frame, &GUID_MetadataFormatGCE, disposalW); 3938 3939 if(disposal==GIF_DISPOSE_UNSPECIFIED || disposal==GIF_DISPOSE_DO_NOT_DISPOSE) { 3940 hr = blit_gif_frame(bitmap, frame, cur_frame==0); 3941 if(FAILED(hr)) 3942 return hresult_to_status(hr); 3943 }else if(disposal == GIF_DISPOSE_RESTORE_TO_BKGND) { 3944 UINT left, top, width, height, i, j; 3945 3946 if(!bgcolor_set) { 3947 bgcolor = get_gif_background_color(bitmap); 3948 bgcolor_set = TRUE; 3949 } 3950 3951 hr = get_gif_frame_rect(frame, &left, &top, &width, &height); 3952 if(FAILED(hr)) 3953 return hresult_to_status(hr); 3954 for(i=top; i<top+height && i<bitmap->height; i++) { 3955 DWORD *bits = (DWORD*)(bitmap->bits+i*bitmap->stride); 3956 for(j=left; j<left+width && j<bitmap->width; j++) 3957 bits[j] = bgcolor; 3958 } 3959 } 3960 3961 IWICBitmapFrameDecode_Release(frame); 3962 cur_frame++; 3963 } 3964 3965 hr = IWICBitmapDecoder_GetFrame(bitmap->image.decoder, active_frame, &frame); 3966 if(FAILED(hr)) 3967 return hresult_to_status(hr); 3968 3969 hr = blit_gif_frame(bitmap, frame, cur_frame==0); 3970 IWICBitmapFrameDecode_Release(frame); 3971 if(FAILED(hr)) 3972 return hresult_to_status(hr); 3973 3974 image->current_frame = active_frame; 3975 return Ok; 3976 } 3977 3978 static GpStatus decode_image_icon(IStream* stream, GpImage **image) 3979 { 3980 return decode_image_wic(stream, &GUID_ContainerFormatIco, NULL, image); 3981 } 3982 3983 static GpStatus decode_image_bmp(IStream* stream, GpImage **image) 3984 { 3985 GpStatus status; 3986 GpBitmap* bitmap; 3987 3988 status = decode_image_wic(stream, &GUID_ContainerFormatBmp, NULL, image); 3989 3990 bitmap = (GpBitmap*)*image; 3991 3992 if (status == Ok && bitmap->format == PixelFormat32bppARGB) 3993 { 3994 /* WIC supports bmp files with alpha, but gdiplus does not */ 3995 bitmap->format = PixelFormat32bppRGB; 3996 } 3997 3998 return status; 3999 } 4000 4001 static GpStatus decode_image_jpeg(IStream* stream, GpImage **image) 4002 { 4003 return decode_image_wic(stream, &GUID_ContainerFormatJpeg, NULL, image); 4004 } 4005 4006 static BOOL has_png_transparency_chunk(IStream *pIStream) 4007 { 4008 LARGE_INTEGER seek; 4009 BOOL has_tRNS = FALSE; 4010 HRESULT hr; 4011 BYTE header[8]; 4012 4013 seek.QuadPart = 8; 4014 do 4015 { 4016 ULARGE_INTEGER chunk_start; 4017 ULONG bytesread, chunk_size; 4018 4019 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, &chunk_start); 4020 if (FAILED(hr)) break; 4021 4022 hr = IStream_Read(pIStream, header, 8, &bytesread); 4023 if (FAILED(hr) || bytesread < 8) break; 4024 4025 chunk_size = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3]; 4026 if (!memcmp(&header[4], "tRNS", 4)) 4027 { 4028 has_tRNS = TRUE; 4029 break; 4030 } 4031 4032 seek.QuadPart = chunk_start.QuadPart + chunk_size + 12; /* skip data and CRC */ 4033 } while (memcmp(&header[4], "IDAT", 4) && memcmp(&header[4], "IEND", 4)); 4034 4035 TRACE("has_tRNS = %d\n", has_tRNS); 4036 return has_tRNS; 4037 } 4038 4039 static GpStatus decode_image_png(IStream* stream, GpImage **image) 4040 { 4041 IWICBitmapDecoder *decoder; 4042 IWICBitmapFrameDecode *frame; 4043 GpStatus status; 4044 HRESULT hr; 4045 GUID format; 4046 BOOL force_conversion = FALSE; 4047 4048 status = initialize_decoder_wic(stream, &GUID_ContainerFormatPng, &decoder); 4049 if (status != Ok) 4050 return status; 4051 4052 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); 4053 if (hr == S_OK) 4054 { 4055 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &format); 4056 if (hr == S_OK) 4057 { 4058 if (IsEqualGUID(&format, &GUID_WICPixelFormat8bppGray)) 4059 force_conversion = TRUE; 4060 else if ((IsEqualGUID(&format, &GUID_WICPixelFormat8bppIndexed) || 4061 IsEqualGUID(&format, &GUID_WICPixelFormat4bppIndexed) || 4062 IsEqualGUID(&format, &GUID_WICPixelFormat2bppIndexed) || 4063 IsEqualGUID(&format, &GUID_WICPixelFormat1bppIndexed) || 4064 IsEqualGUID(&format, &GUID_WICPixelFormat24bppBGR)) && 4065 has_png_transparency_chunk(stream)) 4066 force_conversion = TRUE; 4067 4068 status = decode_frame_wic(decoder, force_conversion, 0, png_metadata_reader, image); 4069 } 4070 else 4071 status = hresult_to_status(hr); 4072 4073 IWICBitmapFrameDecode_Release(frame); 4074 } 4075 else 4076 status = hresult_to_status(hr); 4077 4078 IWICBitmapDecoder_Release(decoder); 4079 return status; 4080 } 4081 4082 static GpStatus decode_image_gif(IStream* stream, GpImage **image) 4083 { 4084 IWICBitmapDecoder *decoder; 4085 UINT frame_count; 4086 GpStatus status; 4087 HRESULT hr; 4088 4089 status = initialize_decoder_wic(stream, &GUID_ContainerFormatGif, &decoder); 4090 if(status != Ok) 4091 return status; 4092 4093 hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); 4094 if(FAILED(hr)) 4095 return hresult_to_status(hr); 4096 4097 status = decode_frame_wic(decoder, frame_count > 1, 0, gif_metadata_reader, image); 4098 IWICBitmapDecoder_Release(decoder); 4099 if(status != Ok) 4100 return status; 4101 4102 if(frame_count > 1) { 4103 heap_free((*image)->palette); 4104 (*image)->palette = NULL; 4105 } 4106 return Ok; 4107 } 4108 4109 static GpStatus decode_image_tiff(IStream* stream, GpImage **image) 4110 { 4111 return decode_image_wic(stream, &GUID_ContainerFormatTiff, NULL, image); 4112 } 4113 4114 static GpStatus load_wmf(IStream *stream, GpMetafile **metafile) 4115 { 4116 WmfPlaceableFileHeader pfh; 4117 BOOL is_placeable = FALSE; 4118 LARGE_INTEGER seek; 4119 GpStatus status; 4120 METAHEADER mh; 4121 HMETAFILE hmf; 4122 HRESULT hr; 4123 UINT size; 4124 void *buf; 4125 4126 hr = IStream_Read(stream, &mh, sizeof(mh), &size); 4127 if (hr != S_OK || size != sizeof(mh)) 4128 return GenericError; 4129 4130 if (((WmfPlaceableFileHeader *)&mh)->Key == WMF_PLACEABLE_KEY) 4131 { 4132 seek.QuadPart = 0; 4133 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 4134 if (FAILED(hr)) return hresult_to_status(hr); 4135 4136 hr = IStream_Read(stream, &pfh, sizeof(pfh), &size); 4137 if (hr != S_OK || size != sizeof(pfh)) 4138 return GenericError; 4139 4140 hr = IStream_Read(stream, &mh, sizeof(mh), &size); 4141 if (hr != S_OK || size != sizeof(mh)) 4142 return GenericError; 4143 4144 is_placeable = TRUE; 4145 } 4146 4147 seek.QuadPart = is_placeable ? sizeof(pfh) : 0; 4148 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 4149 if (FAILED(hr)) return hresult_to_status(hr); 4150 4151 buf = heap_alloc(mh.mtSize * 2); 4152 if (!buf) return OutOfMemory; 4153 4154 hr = IStream_Read(stream, buf, mh.mtSize * 2, &size); 4155 if (hr != S_OK || size != mh.mtSize * 2) 4156 { 4157 heap_free(buf); 4158 return GenericError; 4159 } 4160 4161 hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf); 4162 heap_free(buf); 4163 if (!hmf) 4164 return GenericError; 4165 4166 status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile); 4167 if (status != Ok) 4168 DeleteMetaFile(hmf); 4169 return status; 4170 } 4171 4172 static GpStatus decode_image_wmf(IStream *stream, GpImage **image) 4173 { 4174 GpMetafile *metafile; 4175 GpStatus status; 4176 4177 TRACE("%p %p\n", stream, image); 4178 4179 if (!stream || !image) 4180 return InvalidParameter; 4181 4182 status = load_wmf(stream, &metafile); 4183 if (status != Ok) 4184 { 4185 TRACE("Could not load metafile\n"); 4186 return status; 4187 } 4188 4189 *image = (GpImage *)metafile; 4190 TRACE("<-- %p\n", *image); 4191 4192 return Ok; 4193 } 4194 4195 static GpStatus load_emf(IStream *stream, GpMetafile **metafile) 4196 { 4197 LARGE_INTEGER seek; 4198 ENHMETAHEADER emh; 4199 HENHMETAFILE hemf; 4200 GpStatus status; 4201 HRESULT hr; 4202 UINT size; 4203 void *buf; 4204 4205 hr = IStream_Read(stream, &emh, sizeof(emh), &size); 4206 if (hr != S_OK || size != sizeof(emh) || emh.dSignature != ENHMETA_SIGNATURE) 4207 return GenericError; 4208 4209 seek.QuadPart = 0; 4210 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 4211 if (FAILED(hr)) return hresult_to_status(hr); 4212 4213 buf = heap_alloc(emh.nBytes); 4214 if (!buf) return OutOfMemory; 4215 4216 hr = IStream_Read(stream, buf, emh.nBytes, &size); 4217 if (hr != S_OK || size != emh.nBytes) 4218 { 4219 heap_free(buf); 4220 return GenericError; 4221 } 4222 4223 hemf = SetEnhMetaFileBits(emh.nBytes, buf); 4224 heap_free(buf); 4225 if (!hemf) 4226 return GenericError; 4227 4228 status = GdipCreateMetafileFromEmf(hemf, TRUE, metafile); 4229 if (status != Ok) 4230 DeleteEnhMetaFile(hemf); 4231 return status; 4232 } 4233 4234 static GpStatus decode_image_emf(IStream *stream, GpImage **image) 4235 { 4236 GpMetafile *metafile; 4237 GpStatus status; 4238 4239 TRACE("%p %p\n", stream, image); 4240 4241 if (!stream || !image) 4242 return InvalidParameter; 4243 4244 status = load_emf(stream, &metafile); 4245 if (status != Ok) 4246 { 4247 TRACE("Could not load metafile\n"); 4248 return status; 4249 } 4250 4251 *image = (GpImage *)metafile; 4252 TRACE("<-- %p\n", *image); 4253 4254 return Ok; 4255 } 4256 4257 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream, 4258 GDIPCONST EncoderParameters* params); 4259 4260 typedef GpStatus (*decode_image_func)(IStream *stream, GpImage **image); 4261 4262 typedef GpStatus (*select_image_func)(GpImage *image, UINT active_frame); 4263 4264 typedef struct image_codec { 4265 ImageCodecInfo info; 4266 encode_image_func encode_func; 4267 decode_image_func decode_func; 4268 select_image_func select_func; 4269 } image_codec; 4270 4271 typedef enum { 4272 BMP, 4273 JPEG, 4274 GIF, 4275 TIFF, 4276 EMF, 4277 WMF, 4278 PNG, 4279 ICO, 4280 NUM_CODECS 4281 } ImageFormat; 4282 4283 static const struct image_codec codecs[NUM_CODECS]; 4284 4285 static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result) 4286 { 4287 BYTE signature[8]; 4288 const BYTE *pattern, *mask; 4289 LARGE_INTEGER seek; 4290 HRESULT hr; 4291 UINT bytesread; 4292 int i; 4293 DWORD j, sig; 4294 4295 /* seek to the start of the stream */ 4296 seek.QuadPart = 0; 4297 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 4298 if (FAILED(hr)) return hresult_to_status(hr); 4299 4300 /* read the first 8 bytes */ 4301 /* FIXME: This assumes all codecs have signatures <= 8 bytes in length */ 4302 hr = IStream_Read(stream, signature, 8, &bytesread); 4303 if (FAILED(hr)) return hresult_to_status(hr); 4304 if (hr == S_FALSE || bytesread == 0) return GenericError; 4305 4306 for (i = 0; i < NUM_CODECS; i++) { 4307 if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) && 4308 bytesread >= codecs[i].info.SigSize) 4309 { 4310 for (sig=0; sig<codecs[i].info.SigCount; sig++) 4311 { 4312 pattern = &codecs[i].info.SigPattern[codecs[i].info.SigSize*sig]; 4313 mask = &codecs[i].info.SigMask[codecs[i].info.SigSize*sig]; 4314 for (j=0; j<codecs[i].info.SigSize; j++) 4315 if ((signature[j] & mask[j]) != pattern[j]) 4316 break; 4317 if (j == codecs[i].info.SigSize) 4318 { 4319 *result = &codecs[i]; 4320 return Ok; 4321 } 4322 } 4323 } 4324 } 4325 4326 TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread, 4327 signature[0],signature[1],signature[2],signature[3], 4328 signature[4],signature[5],signature[6],signature[7]); 4329 4330 return GenericError; 4331 } 4332 4333 static GpStatus get_decoder_info_from_image(GpImage *image, const struct image_codec **result) 4334 { 4335 int i; 4336 4337 for (i = 0; i < NUM_CODECS; i++) { 4338 if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) && 4339 IsEqualIID(&codecs[i].info.FormatID, &image->format)) 4340 { 4341 *result = &codecs[i]; 4342 return Ok; 4343 } 4344 } 4345 4346 TRACE("no match for format: %s\n", wine_dbgstr_guid(&image->format)); 4347 return GenericError; 4348 } 4349 4350 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *dimensionID, 4351 UINT frame) 4352 { 4353 GpStatus stat; 4354 const struct image_codec *codec = NULL; 4355 BOOL unlock; 4356 4357 TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame); 4358 4359 if (!image || !dimensionID) 4360 return InvalidParameter; 4361 if(!image_lock(image, &unlock)) 4362 return ObjectBusy; 4363 4364 if (frame >= image->frame_count) 4365 { 4366 WARN("requested frame %u, but image has only %u\n", frame, image->frame_count); 4367 image_unlock(image, unlock); 4368 return InvalidParameter; 4369 } 4370 4371 if (image->type != ImageTypeBitmap && image->type != ImageTypeMetafile) 4372 { 4373 WARN("invalid image type %d\n", image->type); 4374 image_unlock(image, unlock); 4375 return InvalidParameter; 4376 } 4377 4378 if (image->current_frame == frame) 4379 { 4380 image_unlock(image, unlock); 4381 return Ok; 4382 } 4383 4384 if (!image->decoder) 4385 { 4386 TRACE("image doesn't have an associated decoder\n"); 4387 image_unlock(image, unlock); 4388 return Ok; 4389 } 4390 4391 /* choose an appropriate image decoder */ 4392 stat = get_decoder_info_from_image(image, &codec); 4393 if (stat != Ok) 4394 { 4395 WARN("can't find decoder info\n"); 4396 image_unlock(image, unlock); 4397 return stat; 4398 } 4399 4400 stat = codec->select_func(image, frame); 4401 image_unlock(image, unlock); 4402 return stat; 4403 } 4404 4405 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image) 4406 { 4407 GpStatus stat; 4408 LARGE_INTEGER seek; 4409 HRESULT hr; 4410 const struct image_codec *codec=NULL; 4411 4412 TRACE("%p %p\n", stream, image); 4413 4414 if (!stream || !image) 4415 return InvalidParameter; 4416 4417 /* choose an appropriate image decoder */ 4418 stat = get_decoder_info(stream, &codec); 4419 if (stat != Ok) return stat; 4420 4421 /* seek to the start of the stream */ 4422 seek.QuadPart = 0; 4423 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 4424 if (FAILED(hr)) return hresult_to_status(hr); 4425 4426 /* call on the image decoder to do the real work */ 4427 stat = codec->decode_func(stream, image); 4428 4429 /* take note of the original data format */ 4430 if (stat == Ok) 4431 { 4432 memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID)); 4433 return Ok; 4434 } 4435 4436 return stat; 4437 } 4438 4439 /* FIXME: no ICM */ 4440 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image) 4441 { 4442 TRACE("%p %p\n", stream, image); 4443 4444 return GdipLoadImageFromStream(stream, image); 4445 } 4446 4447 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId) 4448 { 4449 static int calls; 4450 4451 TRACE("(%p,%u)\n", image, propId); 4452 4453 if(!image) 4454 return InvalidParameter; 4455 4456 if(!(calls++)) 4457 FIXME("not implemented\n"); 4458 4459 return NotImplemented; 4460 } 4461 4462 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item) 4463 { 4464 static int calls; 4465 4466 if (!image || !item) return InvalidParameter; 4467 4468 TRACE("(%p,%p:%#x,%u,%u,%p)\n", image, item, item->id, item->type, item->length, item->value); 4469 4470 if(!(calls++)) 4471 FIXME("not implemented\n"); 4472 4473 return Ok; 4474 } 4475 4476 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename, 4477 GDIPCONST CLSID *clsidEncoder, 4478 GDIPCONST EncoderParameters *encoderParams) 4479 { 4480 GpStatus stat; 4481 IStream *stream; 4482 4483 TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams); 4484 4485 if (!image || !filename|| !clsidEncoder) 4486 return InvalidParameter; 4487 4488 stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream); 4489 if (stat != Ok) 4490 return GenericError; 4491 4492 stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams); 4493 4494 IStream_Release(stream); 4495 return stat; 4496 } 4497 4498 /************************************************************************* 4499 * Encoding functions - 4500 * These functions encode an image in different image file formats. 4501 */ 4502 4503 static GpStatus encode_image_wic(GpImage *image, IStream* stream, 4504 REFGUID container, GDIPCONST EncoderParameters* params) 4505 { 4506 GpStatus stat; 4507 GpBitmap *bitmap; 4508 IWICImagingFactory *factory; 4509 IWICBitmapEncoder *encoder; 4510 IWICBitmapFrameEncode *frameencode; 4511 IPropertyBag2 *encoderoptions; 4512 HRESULT hr; 4513 UINT width, height; 4514 PixelFormat gdipformat=0; 4515 const WICPixelFormatGUID *desired_wicformat; 4516 WICPixelFormatGUID wicformat; 4517 GpRect rc; 4518 BitmapData lockeddata; 4519 UINT i; 4520 4521 if (image->type != ImageTypeBitmap) 4522 return GenericError; 4523 4524 bitmap = (GpBitmap*)image; 4525 4526 GdipGetImageWidth(image, &width); 4527 GdipGetImageHeight(image, &height); 4528 4529 rc.X = 0; 4530 rc.Y = 0; 4531 rc.Width = width; 4532 rc.Height = height; 4533 4534 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); 4535 if (FAILED(hr)) 4536 return hresult_to_status(hr); 4537 hr = IWICImagingFactory_CreateEncoder(factory, container, NULL, &encoder); 4538 IWICImagingFactory_Release(factory); 4539 if (FAILED(hr)) 4540 return hresult_to_status(hr); 4541 4542 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); 4543 4544 if (SUCCEEDED(hr)) 4545 { 4546 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions); 4547 } 4548 4549 if (SUCCEEDED(hr)) /* created frame */ 4550 { 4551 hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions); 4552 4553 if (SUCCEEDED(hr)) 4554 hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height); 4555 4556 if (SUCCEEDED(hr)) 4557 hr = IWICBitmapFrameEncode_SetResolution(frameencode, image->xres, image->yres); 4558 4559 if (SUCCEEDED(hr)) 4560 { 4561 for (i=0; pixel_formats[i].wic_format; i++) 4562 { 4563 if (pixel_formats[i].gdip_format == bitmap->format) 4564 { 4565 desired_wicformat = pixel_formats[i].wic_format; 4566 gdipformat = bitmap->format; 4567 break; 4568 } 4569 } 4570 if (!gdipformat) 4571 { 4572 desired_wicformat = &GUID_WICPixelFormat32bppBGRA; 4573 gdipformat = PixelFormat32bppARGB; 4574 } 4575 4576 memcpy(&wicformat, desired_wicformat, sizeof(GUID)); 4577 hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat); 4578 } 4579 4580 if (SUCCEEDED(hr) && !IsEqualGUID(desired_wicformat, &wicformat)) 4581 { 4582 /* Encoder doesn't support this bitmap's format. */ 4583 gdipformat = 0; 4584 for (i=0; pixel_formats[i].wic_format; i++) 4585 { 4586 if (IsEqualGUID(&wicformat, pixel_formats[i].wic_format)) 4587 { 4588 gdipformat = pixel_formats[i].gdip_format; 4589 break; 4590 } 4591 } 4592 if (!gdipformat) 4593 { 4594 ERR("Cannot support encoder format %s\n", debugstr_guid(&wicformat)); 4595 hr = E_FAIL; 4596 } 4597 } 4598 4599 if (SUCCEEDED(hr)) 4600 { 4601 stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat, 4602 &lockeddata); 4603 4604 if (stat == Ok) 4605 { 4606 UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8; 4607 BYTE *row; 4608 4609 /* write one row at a time in case stride is negative */ 4610 row = lockeddata.Scan0; 4611 for (i=0; i<lockeddata.Height; i++) 4612 { 4613 hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row); 4614 if (FAILED(hr)) break; 4615 row += lockeddata.Stride; 4616 } 4617 4618 GdipBitmapUnlockBits(bitmap, &lockeddata); 4619 } 4620 else 4621 hr = E_FAIL; 4622 } 4623 4624 if (SUCCEEDED(hr)) 4625 hr = IWICBitmapFrameEncode_Commit(frameencode); 4626 4627 IWICBitmapFrameEncode_Release(frameencode); 4628 IPropertyBag2_Release(encoderoptions); 4629 } 4630 4631 if (SUCCEEDED(hr)) 4632 hr = IWICBitmapEncoder_Commit(encoder); 4633 4634 IWICBitmapEncoder_Release(encoder); 4635 return hresult_to_status(hr); 4636 } 4637 4638 static GpStatus encode_image_BMP(GpImage *image, IStream* stream, 4639 GDIPCONST EncoderParameters* params) 4640 { 4641 return encode_image_wic(image, stream, &GUID_ContainerFormatBmp, params); 4642 } 4643 4644 static GpStatus encode_image_tiff(GpImage *image, IStream* stream, 4645 GDIPCONST EncoderParameters* params) 4646 { 4647 return encode_image_wic(image, stream, &GUID_ContainerFormatTiff, params); 4648 } 4649 4650 GpStatus encode_image_png(GpImage *image, IStream* stream, 4651 GDIPCONST EncoderParameters* params) 4652 { 4653 return encode_image_wic(image, stream, &GUID_ContainerFormatPng, params); 4654 } 4655 4656 static GpStatus encode_image_jpeg(GpImage *image, IStream* stream, 4657 GDIPCONST EncoderParameters* params) 4658 { 4659 return encode_image_wic(image, stream, &GUID_ContainerFormatJpeg, params); 4660 } 4661 4662 static GpStatus encode_image_gif(GpImage *image, IStream* stream, 4663 GDIPCONST EncoderParameters* params) 4664 { 4665 return encode_image_wic(image, stream, &GUID_ContainerFormatGif, params); 4666 } 4667 4668 /***************************************************************************** 4669 * GdipSaveImageToStream [GDIPLUS.@] 4670 */ 4671 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream, 4672 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params) 4673 { 4674 GpStatus stat; 4675 encode_image_func encode_image; 4676 int i; 4677 4678 TRACE("%p, %p, %s, %p\n", image, stream, wine_dbgstr_guid(clsid), params); 4679 4680 if(!image || !stream) 4681 return InvalidParameter; 4682 4683 /* select correct encoder */ 4684 encode_image = NULL; 4685 for (i = 0; i < NUM_CODECS; i++) { 4686 if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) && 4687 IsEqualCLSID(clsid, &codecs[i].info.Clsid)) 4688 encode_image = codecs[i].encode_func; 4689 } 4690 if (encode_image == NULL) 4691 return UnknownImageFormat; 4692 4693 stat = encode_image(image, stream, params); 4694 4695 return stat; 4696 } 4697 4698 /***************************************************************************** 4699 * GdipSaveAdd [GDIPLUS.@] 4700 */ 4701 GpStatus WINGDIPAPI GdipSaveAdd(GpImage *image, GDIPCONST EncoderParameters *params) 4702 { 4703 FIXME("(%p,%p): stub\n", image, params); 4704 return Ok; 4705 } 4706 4707 /***************************************************************************** 4708 * GdipGetImagePalette [GDIPLUS.@] 4709 */ 4710 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size) 4711 { 4712 INT count; 4713 4714 TRACE("(%p,%p,%i)\n", image, palette, size); 4715 4716 if (!image || !palette) 4717 return InvalidParameter; 4718 4719 count = image->palette ? image->palette->Count : 0; 4720 4721 if (size < (sizeof(UINT)*2+sizeof(ARGB)*count)) 4722 { 4723 TRACE("<-- InsufficientBuffer\n"); 4724 return InsufficientBuffer; 4725 } 4726 4727 if (image->palette) 4728 { 4729 palette->Flags = image->palette->Flags; 4730 palette->Count = image->palette->Count; 4731 memcpy(palette->Entries, image->palette->Entries, sizeof(ARGB)*image->palette->Count); 4732 } 4733 else 4734 { 4735 palette->Flags = 0; 4736 palette->Count = 0; 4737 } 4738 return Ok; 4739 } 4740 4741 /***************************************************************************** 4742 * GdipSetImagePalette [GDIPLUS.@] 4743 */ 4744 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image, 4745 GDIPCONST ColorPalette *palette) 4746 { 4747 ColorPalette *new_palette; 4748 4749 TRACE("(%p,%p)\n", image, palette); 4750 4751 if(!image || !palette || palette->Count > 256) 4752 return InvalidParameter; 4753 4754 new_palette = heap_alloc_zero(2 * sizeof(UINT) + palette->Count * sizeof(ARGB)); 4755 if (!new_palette) return OutOfMemory; 4756 4757 heap_free(image->palette); 4758 image->palette = new_palette; 4759 image->palette->Flags = palette->Flags; 4760 image->palette->Count = palette->Count; 4761 memcpy(image->palette->Entries, palette->Entries, sizeof(ARGB)*palette->Count); 4762 4763 return Ok; 4764 } 4765 4766 /************************************************************************* 4767 * Encoders - 4768 * Structures that represent which formats we support for encoding. 4769 */ 4770 4771 /* ImageCodecInfo creation routines taken from libgdiplus */ 4772 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */ 4773 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */ 4774 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */ 4775 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */ 4776 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D }; 4777 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF }; 4778 4779 static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0}; 4780 static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0}; 4781 static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0}; 4782 static const WCHAR jpeg_format[] = {'J','P','E','G',0}; 4783 static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 }; 4784 static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF }; 4785 4786 static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0}; 4787 static const WCHAR gif_extension[] = {'*','.','G','I','F',0}; 4788 static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0}; 4789 static const WCHAR gif_format[] = {'G','I','F',0}; 4790 static const BYTE gif_sig_pattern[12] = "GIF87aGIF89a"; 4791 static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 4792 4793 static const WCHAR tiff_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'T','I','F','F', 0}; 4794 static const WCHAR tiff_extension[] = {'*','.','T','I','F','F',';','*','.','T','I','F',0}; 4795 static const WCHAR tiff_mimetype[] = {'i','m','a','g','e','/','t','i','f','f', 0}; 4796 static const WCHAR tiff_format[] = {'T','I','F','F',0}; 4797 static const BYTE tiff_sig_pattern[] = {0x49,0x49,42,0,0x4d,0x4d,0,42}; 4798 static const BYTE tiff_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 4799 4800 static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0}; 4801 static const WCHAR emf_extension[] = {'*','.','E','M','F',0}; 4802 static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0}; 4803 static const WCHAR emf_format[] = {'E','M','F',0}; 4804 static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 }; 4805 static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF }; 4806 4807 static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0}; 4808 static const WCHAR wmf_extension[] = {'*','.','W','M','F',0}; 4809 static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0}; 4810 static const WCHAR wmf_format[] = {'W','M','F',0}; 4811 static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd }; 4812 static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF }; 4813 4814 static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0}; 4815 static const WCHAR png_extension[] = {'*','.','P','N','G',0}; 4816 static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0}; 4817 static const WCHAR png_format[] = {'P','N','G',0}; 4818 static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, }; 4819 static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 4820 4821 static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0}; 4822 static const WCHAR ico_extension[] = {'*','.','I','C','O',0}; 4823 static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0}; 4824 static const WCHAR ico_format[] = {'I','C','O',0}; 4825 static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 }; 4826 static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF }; 4827 4828 static const struct image_codec codecs[NUM_CODECS] = { 4829 { 4830 { /* BMP */ 4831 /* Clsid */ { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4832 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4833 /* CodecName */ bmp_codecname, 4834 /* DllName */ NULL, 4835 /* FormatDescription */ bmp_format, 4836 /* FilenameExtension */ bmp_extension, 4837 /* MimeType */ bmp_mimetype, 4838 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, 4839 /* Version */ 1, 4840 /* SigCount */ 1, 4841 /* SigSize */ 2, 4842 /* SigPattern */ bmp_sig_pattern, 4843 /* SigMask */ bmp_sig_mask, 4844 }, 4845 encode_image_BMP, 4846 decode_image_bmp, 4847 select_frame_wic 4848 }, 4849 { 4850 { /* JPEG */ 4851 /* Clsid */ { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4852 /* FormatID */ { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4853 /* CodecName */ jpeg_codecname, 4854 /* DllName */ NULL, 4855 /* FormatDescription */ jpeg_format, 4856 /* FilenameExtension */ jpeg_extension, 4857 /* MimeType */ jpeg_mimetype, 4858 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, 4859 /* Version */ 1, 4860 /* SigCount */ 1, 4861 /* SigSize */ 2, 4862 /* SigPattern */ jpeg_sig_pattern, 4863 /* SigMask */ jpeg_sig_mask, 4864 }, 4865 encode_image_jpeg, 4866 decode_image_jpeg, 4867 select_frame_wic 4868 }, 4869 { 4870 { /* GIF */ 4871 /* Clsid */ { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4872 /* FormatID */ { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4873 /* CodecName */ gif_codecname, 4874 /* DllName */ NULL, 4875 /* FormatDescription */ gif_format, 4876 /* FilenameExtension */ gif_extension, 4877 /* MimeType */ gif_mimetype, 4878 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsEncoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, 4879 /* Version */ 1, 4880 /* SigCount */ 2, 4881 /* SigSize */ 6, 4882 /* SigPattern */ gif_sig_pattern, 4883 /* SigMask */ gif_sig_mask, 4884 }, 4885 encode_image_gif, 4886 decode_image_gif, 4887 select_frame_gif 4888 }, 4889 { 4890 { /* TIFF */ 4891 /* Clsid */ { 0x557cf405, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4892 /* FormatID */ { 0xb96b3cb1U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4893 /* CodecName */ tiff_codecname, 4894 /* DllName */ NULL, 4895 /* FormatDescription */ tiff_format, 4896 /* FilenameExtension */ tiff_extension, 4897 /* MimeType */ tiff_mimetype, 4898 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsEncoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, 4899 /* Version */ 1, 4900 /* SigCount */ 2, 4901 /* SigSize */ 4, 4902 /* SigPattern */ tiff_sig_pattern, 4903 /* SigMask */ tiff_sig_mask, 4904 }, 4905 encode_image_tiff, 4906 decode_image_tiff, 4907 select_frame_wic 4908 }, 4909 { 4910 { /* EMF */ 4911 /* Clsid */ { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4912 /* FormatID */ { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4913 /* CodecName */ emf_codecname, 4914 /* DllName */ NULL, 4915 /* FormatDescription */ emf_format, 4916 /* FilenameExtension */ emf_extension, 4917 /* MimeType */ emf_mimetype, 4918 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin, 4919 /* Version */ 1, 4920 /* SigCount */ 1, 4921 /* SigSize */ 4, 4922 /* SigPattern */ emf_sig_pattern, 4923 /* SigMask */ emf_sig_mask, 4924 }, 4925 NULL, 4926 decode_image_emf, 4927 NULL 4928 }, 4929 { 4930 { /* WMF */ 4931 /* Clsid */ { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4932 /* FormatID */ { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4933 /* CodecName */ wmf_codecname, 4934 /* DllName */ NULL, 4935 /* FormatDescription */ wmf_format, 4936 /* FilenameExtension */ wmf_extension, 4937 /* MimeType */ wmf_mimetype, 4938 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin, 4939 /* Version */ 1, 4940 /* SigCount */ 1, 4941 /* SigSize */ 2, 4942 /* SigPattern */ wmf_sig_pattern, 4943 /* SigMask */ wmf_sig_mask, 4944 }, 4945 NULL, 4946 decode_image_wmf, 4947 NULL 4948 }, 4949 { 4950 { /* PNG */ 4951 /* Clsid */ { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4952 /* FormatID */ { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4953 /* CodecName */ png_codecname, 4954 /* DllName */ NULL, 4955 /* FormatDescription */ png_format, 4956 /* FilenameExtension */ png_extension, 4957 /* MimeType */ png_mimetype, 4958 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, 4959 /* Version */ 1, 4960 /* SigCount */ 1, 4961 /* SigSize */ 8, 4962 /* SigPattern */ png_sig_pattern, 4963 /* SigMask */ png_sig_mask, 4964 }, 4965 encode_image_png, 4966 decode_image_png, 4967 select_frame_wic 4968 }, 4969 { 4970 { /* ICO */ 4971 /* Clsid */ { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } }, 4972 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} }, 4973 /* CodecName */ ico_codecname, 4974 /* DllName */ NULL, 4975 /* FormatDescription */ ico_format, 4976 /* FilenameExtension */ ico_extension, 4977 /* MimeType */ ico_mimetype, 4978 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, 4979 /* Version */ 1, 4980 /* SigCount */ 1, 4981 /* SigSize */ 4, 4982 /* SigPattern */ ico_sig_pattern, 4983 /* SigMask */ ico_sig_mask, 4984 }, 4985 NULL, 4986 decode_image_icon, 4987 select_frame_wic 4988 }, 4989 }; 4990 4991 /***************************************************************************** 4992 * GdipGetImageDecodersSize [GDIPLUS.@] 4993 */ 4994 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size) 4995 { 4996 int decoder_count=0; 4997 int i; 4998 TRACE("%p %p\n", numDecoders, size); 4999 5000 if (!numDecoders || !size) 5001 return InvalidParameter; 5002 5003 for (i=0; i<NUM_CODECS; i++) 5004 { 5005 if (codecs[i].info.Flags & ImageCodecFlagsDecoder) 5006 decoder_count++; 5007 } 5008 5009 *numDecoders = decoder_count; 5010 *size = decoder_count * sizeof(ImageCodecInfo); 5011 5012 return Ok; 5013 } 5014 5015 /***************************************************************************** 5016 * GdipGetImageDecoders [GDIPLUS.@] 5017 */ 5018 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders) 5019 { 5020 int i, decoder_count=0; 5021 TRACE("%u %u %p\n", numDecoders, size, decoders); 5022 5023 if (!decoders || 5024 size != numDecoders * sizeof(ImageCodecInfo)) 5025 return GenericError; 5026 5027 for (i=0; i<NUM_CODECS; i++) 5028 { 5029 if (codecs[i].info.Flags & ImageCodecFlagsDecoder) 5030 { 5031 if (decoder_count == numDecoders) return GenericError; 5032 memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo)); 5033 decoder_count++; 5034 } 5035 } 5036 5037 if (decoder_count < numDecoders) return GenericError; 5038 5039 return Ok; 5040 } 5041 5042 /***************************************************************************** 5043 * GdipGetImageEncodersSize [GDIPLUS.@] 5044 */ 5045 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size) 5046 { 5047 int encoder_count=0; 5048 int i; 5049 TRACE("%p %p\n", numEncoders, size); 5050 5051 if (!numEncoders || !size) 5052 return InvalidParameter; 5053 5054 for (i=0; i<NUM_CODECS; i++) 5055 { 5056 if (codecs[i].info.Flags & ImageCodecFlagsEncoder) 5057 encoder_count++; 5058 } 5059 5060 *numEncoders = encoder_count; 5061 *size = encoder_count * sizeof(ImageCodecInfo); 5062 5063 return Ok; 5064 } 5065 5066 /***************************************************************************** 5067 * GdipGetImageEncoders [GDIPLUS.@] 5068 */ 5069 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders) 5070 { 5071 int i, encoder_count=0; 5072 TRACE("%u %u %p\n", numEncoders, size, encoders); 5073 5074 if (!encoders || 5075 size != numEncoders * sizeof(ImageCodecInfo)) 5076 return GenericError; 5077 5078 for (i=0; i<NUM_CODECS; i++) 5079 { 5080 if (codecs[i].info.Flags & ImageCodecFlagsEncoder) 5081 { 5082 if (encoder_count == numEncoders) return GenericError; 5083 memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo)); 5084 encoder_count++; 5085 } 5086 } 5087 5088 if (encoder_count < numEncoders) return GenericError; 5089 5090 return Ok; 5091 } 5092 5093 GpStatus WINGDIPAPI GdipGetEncoderParameterListSize(GpImage *image, 5094 GDIPCONST CLSID* clsidEncoder, UINT *size) 5095 { 5096 static int calls; 5097 5098 TRACE("(%p,%s,%p)\n", image, debugstr_guid(clsidEncoder), size); 5099 5100 if(!(calls++)) 5101 FIXME("not implemented\n"); 5102 5103 *size = 0; 5104 5105 return NotImplemented; 5106 } 5107 5108 static PixelFormat get_16bpp_format(HBITMAP hbm) 5109 { 5110 BITMAPV4HEADER bmh; 5111 HDC hdc; 5112 PixelFormat result; 5113 5114 hdc = CreateCompatibleDC(NULL); 5115 5116 memset(&bmh, 0, sizeof(bmh)); 5117 bmh.bV4Size = sizeof(bmh); 5118 bmh.bV4Width = 1; 5119 bmh.bV4Height = 1; 5120 bmh.bV4V4Compression = BI_BITFIELDS; 5121 bmh.bV4BitCount = 16; 5122 5123 GetDIBits(hdc, hbm, 0, 0, NULL, (BITMAPINFO*)&bmh, DIB_RGB_COLORS); 5124 5125 if (bmh.bV4RedMask == 0x7c00 && 5126 bmh.bV4GreenMask == 0x3e0 && 5127 bmh.bV4BlueMask == 0x1f) 5128 { 5129 result = PixelFormat16bppRGB555; 5130 } 5131 else if (bmh.bV4RedMask == 0xf800 && 5132 bmh.bV4GreenMask == 0x7e0 && 5133 bmh.bV4BlueMask == 0x1f) 5134 { 5135 result = PixelFormat16bppRGB565; 5136 } 5137 else 5138 { 5139 FIXME("unrecognized bitfields %x,%x,%x\n", bmh.bV4RedMask, 5140 bmh.bV4GreenMask, bmh.bV4BlueMask); 5141 result = PixelFormatUndefined; 5142 } 5143 5144 DeleteDC(hdc); 5145 5146 return result; 5147 } 5148 5149 /***************************************************************************** 5150 * GdipCreateBitmapFromHBITMAP [GDIPLUS.@] 5151 */ 5152 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap) 5153 { 5154 BITMAP bm; 5155 GpStatus retval; 5156 PixelFormat format; 5157 BitmapData lockeddata; 5158 5159 TRACE("%p %p %p\n", hbm, hpal, bitmap); 5160 5161 if(!hbm || !bitmap) 5162 return InvalidParameter; 5163 5164 if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm)) 5165 return InvalidParameter; 5166 5167 /* TODO: Figure out the correct format for 16, 32, 64 bpp */ 5168 switch(bm.bmBitsPixel) { 5169 case 1: 5170 format = PixelFormat1bppIndexed; 5171 break; 5172 case 4: 5173 format = PixelFormat4bppIndexed; 5174 break; 5175 case 8: 5176 format = PixelFormat8bppIndexed; 5177 break; 5178 case 16: 5179 format = get_16bpp_format(hbm); 5180 if (format == PixelFormatUndefined) 5181 return InvalidParameter; 5182 break; 5183 case 24: 5184 format = PixelFormat24bppRGB; 5185 break; 5186 case 32: 5187 format = PixelFormat32bppRGB; 5188 break; 5189 case 48: 5190 format = PixelFormat48bppRGB; 5191 break; 5192 default: 5193 FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel); 5194 return InvalidParameter; 5195 } 5196 5197 retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, 0, 5198 format, NULL, bitmap); 5199 5200 if (retval == Ok) 5201 { 5202 retval = GdipBitmapLockBits(*bitmap, NULL, ImageLockModeWrite, 5203 format, &lockeddata); 5204 if (retval == Ok) 5205 { 5206 HDC hdc; 5207 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)]; 5208 BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf; 5209 INT src_height; 5210 5211 hdc = CreateCompatibleDC(NULL); 5212 5213 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 5214 pbmi->bmiHeader.biBitCount = 0; 5215 5216 GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS); 5217 5218 src_height = abs(pbmi->bmiHeader.biHeight); 5219 pbmi->bmiHeader.biHeight = -src_height; 5220 5221 GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS); 5222 5223 DeleteDC(hdc); 5224 5225 GdipBitmapUnlockBits(*bitmap, &lockeddata); 5226 } 5227 5228 if (retval == Ok && hpal) 5229 { 5230 PALETTEENTRY entry[256]; 5231 ColorPalette *palette=NULL; 5232 int i, num_palette_entries; 5233 5234 num_palette_entries = GetPaletteEntries(hpal, 0, 256, entry); 5235 if (!num_palette_entries) 5236 retval = GenericError; 5237 5238 palette = heap_alloc_zero(sizeof(ColorPalette) + sizeof(ARGB) * (num_palette_entries-1)); 5239 if (!palette) 5240 retval = OutOfMemory; 5241 5242 if (retval == Ok) 5243 { 5244 palette->Flags = 0; 5245 palette->Count = num_palette_entries; 5246 5247 for (i=0; i<num_palette_entries; i++) 5248 { 5249 palette->Entries[i] = 0xff000000 | entry[i].peRed << 16 | 5250 entry[i].peGreen << 8 | entry[i].peBlue; 5251 } 5252 5253 retval = GdipSetImagePalette(&(*bitmap)->image, palette); 5254 } 5255 5256 heap_free(palette); 5257 } 5258 5259 if (retval != Ok) 5260 { 5261 GdipDisposeImage(&(*bitmap)->image); 5262 *bitmap = NULL; 5263 } 5264 } 5265 5266 return retval; 5267 } 5268 5269 /***************************************************************************** 5270 * GdipCreateEffect [GDIPLUS.@] 5271 */ 5272 GpStatus WINGDIPAPI GdipCreateEffect(const GUID guid, CGpEffect **effect) 5273 { 5274 FIXME("(%s, %p): stub\n", debugstr_guid(&guid), effect); 5275 5276 if(!effect) 5277 return InvalidParameter; 5278 5279 *effect = NULL; 5280 5281 return NotImplemented; 5282 } 5283 5284 /***************************************************************************** 5285 * GdipDeleteEffect [GDIPLUS.@] 5286 */ 5287 GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect) 5288 { 5289 FIXME("(%p): stub\n", effect); 5290 /* note: According to Jose Roca's GDI+ Docs, this is not implemented 5291 * in Windows's gdiplus */ 5292 return NotImplemented; 5293 } 5294 5295 /***************************************************************************** 5296 * GdipSetEffectParameters [GDIPLUS.@] 5297 */ 5298 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect, 5299 const VOID *params, const UINT size) 5300 { 5301 static int calls; 5302 5303 TRACE("(%p,%p,%u)\n", effect, params, size); 5304 5305 if(!(calls++)) 5306 FIXME("not implemented\n"); 5307 5308 return NotImplemented; 5309 } 5310 5311 /***************************************************************************** 5312 * GdipGetImageFlags [GDIPLUS.@] 5313 */ 5314 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags) 5315 { 5316 TRACE("%p %p\n", image, flags); 5317 5318 if(!image || !flags) 5319 return InvalidParameter; 5320 5321 *flags = image->flags; 5322 5323 return Ok; 5324 } 5325 5326 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param) 5327 { 5328 TRACE("(%d, %p)\n", control, param); 5329 5330 switch(control){ 5331 case TestControlForceBilinear: 5332 if(param) 5333 FIXME("TestControlForceBilinear not handled\n"); 5334 break; 5335 case TestControlNoICM: 5336 if(param) 5337 FIXME("TestControlNoICM not handled\n"); 5338 break; 5339 case TestControlGetBuildNumber: 5340 *((DWORD*)param) = 3102; 5341 break; 5342 } 5343 5344 return Ok; 5345 } 5346 5347 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image) 5348 { 5349 TRACE("%p\n", image); 5350 5351 return Ok; 5352 } 5353 5354 /***************************************************************************** 5355 * GdipGetImageThumbnail [GDIPLUS.@] 5356 */ 5357 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height, 5358 GpImage **ret_image, GetThumbnailImageAbort cb, 5359 VOID * cb_data) 5360 { 5361 GpStatus stat; 5362 GpGraphics *graphics; 5363 UINT srcwidth, srcheight; 5364 5365 TRACE("(%p %u %u %p %p %p)\n", 5366 image, width, height, ret_image, cb, cb_data); 5367 5368 if (!image || !ret_image) 5369 return InvalidParameter; 5370 5371 if (!width) width = 120; 5372 if (!height) height = 120; 5373 5374 GdipGetImageWidth(image, &srcwidth); 5375 GdipGetImageHeight(image, &srcheight); 5376 5377 stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB, 5378 NULL, (GpBitmap**)ret_image); 5379 5380 if (stat == Ok) 5381 { 5382 stat = GdipGetImageGraphicsContext(*ret_image, &graphics); 5383 5384 if (stat == Ok) 5385 { 5386 stat = GdipDrawImageRectRectI(graphics, image, 5387 0, 0, width, height, 0, 0, srcwidth, srcheight, UnitPixel, 5388 NULL, NULL, NULL); 5389 5390 GdipDeleteGraphics(graphics); 5391 } 5392 5393 if (stat != Ok) 5394 { 5395 GdipDisposeImage(*ret_image); 5396 *ret_image = NULL; 5397 } 5398 } 5399 5400 return stat; 5401 } 5402 5403 /***************************************************************************** 5404 * GdipImageRotateFlip [GDIPLUS.@] 5405 */ 5406 GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type) 5407 { 5408 GpBitmap *new_bitmap; 5409 GpBitmap *bitmap; 5410 int bpp, bytesperpixel; 5411 BOOL rotate_90, flip_x, flip_y; 5412 int src_x_offset, src_y_offset; 5413 LPBYTE src_origin; 5414 UINT x, y, width, height; 5415 BitmapData src_lock, dst_lock; 5416 GpStatus stat; 5417 BOOL unlock; 5418 5419 TRACE("(%p, %u)\n", image, type); 5420 5421 if (!image) 5422 return InvalidParameter; 5423 if (!image_lock(image, &unlock)) 5424 return ObjectBusy; 5425 5426 rotate_90 = type&1; 5427 flip_x = (type&6) == 2 || (type&6) == 4; 5428 flip_y = (type&3) == 1 || (type&3) == 2; 5429 5430 if (image->type != ImageTypeBitmap) 5431 { 5432 FIXME("Not implemented for type %i\n", image->type); 5433 image_unlock(image, unlock); 5434 return NotImplemented; 5435 } 5436 5437 bitmap = (GpBitmap*)image; 5438 bpp = PIXELFORMATBPP(bitmap->format); 5439 5440 if (bpp < 8) 5441 { 5442 FIXME("Not implemented for %i bit images\n", bpp); 5443 image_unlock(image, unlock); 5444 return NotImplemented; 5445 } 5446 5447 if (rotate_90) 5448 { 5449 width = bitmap->height; 5450 height = bitmap->width; 5451 } 5452 else 5453 { 5454 width = bitmap->width; 5455 height = bitmap->height; 5456 } 5457 5458 bytesperpixel = bpp/8; 5459 5460 stat = GdipCreateBitmapFromScan0(width, height, 0, bitmap->format, NULL, &new_bitmap); 5461 5462 if (stat != Ok) 5463 { 5464 image_unlock(image, unlock); 5465 return stat; 5466 } 5467 5468 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format, &src_lock); 5469 5470 if (stat == Ok) 5471 { 5472 stat = GdipBitmapLockBits(new_bitmap, NULL, ImageLockModeWrite, bitmap->format, &dst_lock); 5473 5474 if (stat == Ok) 5475 { 5476 LPBYTE src_row, src_pixel; 5477 LPBYTE dst_row, dst_pixel; 5478 5479 src_origin = src_lock.Scan0; 5480 if (flip_x) src_origin += bytesperpixel * (bitmap->width - 1); 5481 if (flip_y) src_origin += src_lock.Stride * (bitmap->height - 1); 5482 5483 if (rotate_90) 5484 { 5485 if (flip_y) src_x_offset = -src_lock.Stride; 5486 else src_x_offset = src_lock.Stride; 5487 if (flip_x) src_y_offset = -bytesperpixel; 5488 else src_y_offset = bytesperpixel; 5489 } 5490 else 5491 { 5492 if (flip_x) src_x_offset = -bytesperpixel; 5493 else src_x_offset = bytesperpixel; 5494 if (flip_y) src_y_offset = -src_lock.Stride; 5495 else src_y_offset = src_lock.Stride; 5496 } 5497 5498 src_row = src_origin; 5499 dst_row = dst_lock.Scan0; 5500 for (y=0; y<height; y++) 5501 { 5502 src_pixel = src_row; 5503 dst_pixel = dst_row; 5504 for (x=0; x<width; x++) 5505 { 5506 /* FIXME: This could probably be faster without memcpy. */ 5507 memcpy(dst_pixel, src_pixel, bytesperpixel); 5508 dst_pixel += bytesperpixel; 5509 src_pixel += src_x_offset; 5510 } 5511 src_row += src_y_offset; 5512 dst_row += dst_lock.Stride; 5513 } 5514 5515 GdipBitmapUnlockBits(new_bitmap, &dst_lock); 5516 } 5517 5518 GdipBitmapUnlockBits(bitmap, &src_lock); 5519 } 5520 5521 if (stat == Ok) 5522 move_bitmap(bitmap, new_bitmap, FALSE); 5523 else 5524 GdipDisposeImage(&new_bitmap->image); 5525 5526 image_unlock(image, unlock); 5527 return stat; 5528 } 5529 5530 /***************************************************************************** 5531 * GdipImageSetAbort [GDIPLUS.@] 5532 */ 5533 GpStatus WINGDIPAPI GdipImageSetAbort(GpImage *image, GdiplusAbort *pabort) 5534 { 5535 TRACE("(%p, %p)\n", image, pabort); 5536 5537 if (!image) 5538 return InvalidParameter; 5539 5540 if (pabort) 5541 FIXME("Abort callback is not supported.\n"); 5542 5543 return Ok; 5544 } 5545 5546 /***************************************************************************** 5547 * GdipBitmapConvertFormat [GDIPLUS.@] 5548 */ 5549 GpStatus WINGDIPAPI GdipBitmapConvertFormat(GpBitmap *bitmap, PixelFormat format, DitherType dithertype, 5550 PaletteType palettetype, ColorPalette *palette, REAL alphathreshold) 5551 { 5552 FIXME("(%p, 0x%08x, %d, %d, %p, %f): stub\n", bitmap, format, dithertype, palettetype, palette, alphathreshold); 5553 return NotImplemented; 5554 } 5555 5556 static void set_histogram_point_argb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5557 { 5558 ch0[ color >> 24 ]++; 5559 ch1[(color >> 16) & 0xff]++; 5560 ch2[(color >> 8) & 0xff]++; 5561 ch3[ color & 0xff]++; 5562 } 5563 5564 static void set_histogram_point_pargb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5565 { 5566 BYTE alpha = color >> 24; 5567 5568 ch0[alpha]++; 5569 ch1[(((color >> 16) & 0xff) * alpha) / 0xff]++; 5570 ch2[(((color >> 8) & 0xff) * alpha) / 0xff]++; 5571 ch3[(( color & 0xff) * alpha) / 0xff]++; 5572 } 5573 5574 static void set_histogram_point_rgb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5575 { 5576 ch0[(color >> 16) & 0xff]++; 5577 ch1[(color >> 8) & 0xff]++; 5578 ch2[ color & 0xff]++; 5579 } 5580 5581 static void set_histogram_point_gray(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5582 { 5583 ch0[(76 * ((color >> 16) & 0xff) + 150 * ((color >> 8) & 0xff) + 29 * (color & 0xff)) / 0xff]++; 5584 } 5585 5586 static void set_histogram_point_b(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5587 { 5588 ch0[color & 0xff]++; 5589 } 5590 5591 static void set_histogram_point_g(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5592 { 5593 ch0[(color >> 8) & 0xff]++; 5594 } 5595 5596 static void set_histogram_point_r(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5597 { 5598 ch0[(color >> 16) & 0xff]++; 5599 } 5600 5601 static void set_histogram_point_a(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5602 { 5603 ch0[(color >> 24) & 0xff]++; 5604 } 5605 5606 /***************************************************************************** 5607 * GdipBitmapGetHistogram [GDIPLUS.@] 5608 */ 5609 GpStatus WINGDIPAPI GdipBitmapGetHistogram(GpBitmap *bitmap, HistogramFormat format, UINT num_of_entries, 5610 UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) 5611 { 5612 static void (* const set_histogram_point[])(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) = 5613 { 5614 set_histogram_point_argb, 5615 set_histogram_point_pargb, 5616 set_histogram_point_rgb, 5617 set_histogram_point_gray, 5618 set_histogram_point_b, 5619 set_histogram_point_g, 5620 set_histogram_point_r, 5621 set_histogram_point_a, 5622 }; 5623 UINT width, height, x, y; 5624 5625 TRACE("(%p, %d, %u, %p, %p, %p, %p)\n", bitmap, format, num_of_entries, 5626 ch0, ch1, ch2, ch3); 5627 5628 if (!bitmap || num_of_entries != 256) 5629 return InvalidParameter; 5630 5631 /* Make sure passed channel pointers match requested format */ 5632 switch (format) 5633 { 5634 case HistogramFormatARGB: 5635 case HistogramFormatPARGB: 5636 if (!ch0 || !ch1 || !ch2 || !ch3) 5637 return InvalidParameter; 5638 memset(ch0, 0, num_of_entries * sizeof(UINT)); 5639 memset(ch1, 0, num_of_entries * sizeof(UINT)); 5640 memset(ch2, 0, num_of_entries * sizeof(UINT)); 5641 memset(ch3, 0, num_of_entries * sizeof(UINT)); 5642 break; 5643 case HistogramFormatRGB: 5644 if (!ch0 || !ch1 || !ch2 || ch3) 5645 return InvalidParameter; 5646 memset(ch0, 0, num_of_entries * sizeof(UINT)); 5647 memset(ch1, 0, num_of_entries * sizeof(UINT)); 5648 memset(ch2, 0, num_of_entries * sizeof(UINT)); 5649 break; 5650 case HistogramFormatGray: 5651 case HistogramFormatB: 5652 case HistogramFormatG: 5653 case HistogramFormatR: 5654 case HistogramFormatA: 5655 if (!ch0 || ch1 || ch2 || ch3) 5656 return InvalidParameter; 5657 memset(ch0, 0, num_of_entries * sizeof(UINT)); 5658 break; 5659 default: 5660 WARN("Invalid histogram format requested, %d\n", format); 5661 return InvalidParameter; 5662 } 5663 5664 GdipGetImageWidth(&bitmap->image, &width); 5665 GdipGetImageHeight(&bitmap->image, &height); 5666 5667 for (y = 0; y < height; y++) 5668 for (x = 0; x < width; x++) 5669 { 5670 ARGB color; 5671 5672 GdipBitmapGetPixel(bitmap, x, y, &color); 5673 set_histogram_point[format](color, ch0, ch1, ch2, ch3); 5674 } 5675 5676 return Ok; 5677 } 5678 5679 /***************************************************************************** 5680 * GdipBitmapGetHistogramSize [GDIPLUS.@] 5681 */ 5682 GpStatus WINGDIPAPI GdipBitmapGetHistogramSize(HistogramFormat format, UINT *num_of_entries) 5683 { 5684 TRACE("(%d, %p)\n", format, num_of_entries); 5685 5686 if (!num_of_entries) 5687 return InvalidParameter; 5688 5689 *num_of_entries = 256; 5690 return Ok; 5691 } 5692 5693 static GpStatus create_optimal_palette(ColorPalette *palette, INT desired, 5694 BOOL transparent, GpBitmap *bitmap) 5695 { 5696 GpStatus status; 5697 BitmapData data; 5698 HRESULT hr; 5699 IWICImagingFactory *factory; 5700 IWICPalette *wic_palette; 5701 5702 if (!bitmap) return InvalidParameter; 5703 if (palette->Count < desired) return GenericError; 5704 5705 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB, &data); 5706 if (status != Ok) return status; 5707 5708 hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); 5709 if (hr != S_OK) 5710 { 5711 GdipBitmapUnlockBits(bitmap, &data); 5712 return hresult_to_status(hr); 5713 } 5714 5715 hr = IWICImagingFactory_CreatePalette(factory, &wic_palette); 5716 if (hr == S_OK) 5717 { 5718 IWICBitmap *bitmap; 5719 5720 /* PixelFormat24bppRGB actually stores the bitmap bits as BGR. */ 5721 hr = IWICImagingFactory_CreateBitmapFromMemory(factory, data.Width, data.Height, 5722 &GUID_WICPixelFormat24bppBGR, data.Stride, data.Stride * data.Width, data.Scan0, &bitmap); 5723 if (hr == S_OK) 5724 { 5725 hr = IWICPalette_InitializeFromBitmap(wic_palette, (IWICBitmapSource *)bitmap, desired, transparent); 5726 if (hr == S_OK) 5727 { 5728 palette->Flags = 0; 5729 IWICPalette_GetColorCount(wic_palette, &palette->Count); 5730 IWICPalette_GetColors(wic_palette, palette->Count, palette->Entries, &palette->Count); 5731 } 5732 5733 IWICBitmap_Release(bitmap); 5734 } 5735 5736 IWICPalette_Release(wic_palette); 5737 } 5738 5739 IWICImagingFactory_Release(factory); 5740 GdipBitmapUnlockBits(bitmap, &data); 5741 5742 return hresult_to_status(hr); 5743 } 5744 5745 /***************************************************************************** 5746 * GdipInitializePalette [GDIPLUS.@] 5747 */ 5748 GpStatus WINGDIPAPI GdipInitializePalette(ColorPalette *palette, 5749 PaletteType type, INT desired, BOOL transparent, GpBitmap *bitmap) 5750 { 5751 TRACE("(%p,%d,%d,%d,%p)\n", palette, type, desired, transparent, bitmap); 5752 5753 if (!palette) return InvalidParameter; 5754 5755 switch (type) 5756 { 5757 case PaletteTypeCustom: 5758 return Ok; 5759 5760 case PaletteTypeOptimal: 5761 return create_optimal_palette(palette, desired, transparent, bitmap); 5762 5763 /* WIC palette type enumeration matches these gdiplus enums */ 5764 case PaletteTypeFixedBW: 5765 case PaletteTypeFixedHalftone8: 5766 case PaletteTypeFixedHalftone27: 5767 case PaletteTypeFixedHalftone64: 5768 case PaletteTypeFixedHalftone125: 5769 case PaletteTypeFixedHalftone216: 5770 case PaletteTypeFixedHalftone252: 5771 case PaletteTypeFixedHalftone256: 5772 { 5773 ColorPalette *wic_palette; 5774 GpStatus status = Ok; 5775 5776 wic_palette = get_palette(NULL, type); 5777 if (!wic_palette) return OutOfMemory; 5778 5779 if (palette->Count >= wic_palette->Count) 5780 { 5781 palette->Flags = wic_palette->Flags; 5782 palette->Count = wic_palette->Count; 5783 memcpy(palette->Entries, wic_palette->Entries, wic_palette->Count * sizeof(wic_palette->Entries[0])); 5784 } 5785 else 5786 status = GenericError; 5787 5788 heap_free(wic_palette); 5789 5790 return status; 5791 } 5792 5793 default: 5794 FIXME("unknown palette type %d\n", type); 5795 break; 5796 } 5797 5798 return InvalidParameter; 5799 } 5800