1 /* 2 * Copyright 2009 Vincent Povirk for CodeWeavers 3 * Copyright 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 "config.h" 21 22 #include <stdarg.h> 23 24 #define COBJMACROS 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winreg.h" 29 #include "wingdi.h" 30 #include "objbase.h" 31 32 #include "wincodecs_private.h" 33 34 #include "wine/debug.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 37 38 struct bmp_pixelformat { 39 const WICPixelFormatGUID *guid; 40 UINT bpp; 41 UINT colors; /* palette size */ 42 DWORD compression; 43 DWORD redmask; 44 DWORD greenmask; 45 DWORD bluemask; 46 DWORD alphamask; 47 }; 48 49 static const struct bmp_pixelformat formats[] = { 50 {&GUID_WICPixelFormat24bppBGR, 24, 0, BI_RGB}, 51 {&GUID_WICPixelFormatBlackWhite, 1, 2, BI_RGB}, 52 {&GUID_WICPixelFormat1bppIndexed, 1, 2, BI_RGB}, 53 {&GUID_WICPixelFormat2bppIndexed, 2, 4, BI_RGB}, 54 {&GUID_WICPixelFormat4bppIndexed, 4, 16, BI_RGB}, 55 {&GUID_WICPixelFormat8bppIndexed, 8, 256, BI_RGB}, 56 {&GUID_WICPixelFormat16bppBGR555, 16, 0, BI_RGB}, 57 {&GUID_WICPixelFormat16bppBGR565, 16, 0, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0}, 58 {&GUID_WICPixelFormat32bppBGR, 32, 0, BI_RGB}, 59 #if 0 60 /* Windows doesn't seem to support this one. */ 61 {&GUID_WICPixelFormat32bppBGRA, 32, 0, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000}, 62 #endif 63 {NULL} 64 }; 65 66 typedef struct BmpFrameEncode { 67 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; 68 LONG ref; 69 IStream *stream; 70 BOOL initialized; 71 UINT width, height; 72 BYTE *bits; 73 const struct bmp_pixelformat *format; 74 double xres, yres; 75 UINT lineswritten; 76 UINT stride; 77 WICColor palette[256]; 78 UINT colors; 79 BOOL committed; 80 } BmpFrameEncode; 81 82 static const WCHAR wszEnableV5Header32bppBGRA[] = {'E','n','a','b','l','e','V','5','H','e','a','d','e','r','3','2','b','p','p','B','G','R','A',0}; 83 84 static inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) 85 { 86 return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface); 87 } 88 89 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, 90 void **ppv) 91 { 92 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 93 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 94 95 if (!ppv) return E_INVALIDARG; 96 97 if (IsEqualIID(&IID_IUnknown, iid) || 98 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 99 { 100 *ppv = &This->IWICBitmapFrameEncode_iface; 101 } 102 else 103 { 104 *ppv = NULL; 105 return E_NOINTERFACE; 106 } 107 108 IUnknown_AddRef((IUnknown*)*ppv); 109 return S_OK; 110 } 111 112 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface) 113 { 114 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 115 ULONG ref = InterlockedIncrement(&This->ref); 116 117 TRACE("(%p) refcount=%u\n", iface, ref); 118 119 return ref; 120 } 121 122 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface) 123 { 124 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 125 ULONG ref = InterlockedDecrement(&This->ref); 126 127 TRACE("(%p) refcount=%u\n", iface, ref); 128 129 if (ref == 0) 130 { 131 if (This->stream) IStream_Release(This->stream); 132 HeapFree(GetProcessHeap(), 0, This->bits); 133 HeapFree(GetProcessHeap(), 0, This); 134 } 135 136 return ref; 137 } 138 139 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface, 140 IPropertyBag2 *pIEncoderOptions) 141 { 142 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 143 TRACE("(%p,%p)\n", iface, pIEncoderOptions); 144 145 if (This->initialized) return WINCODEC_ERR_WRONGSTATE; 146 147 if (pIEncoderOptions) 148 WARN("ignoring encoder options.\n"); 149 150 This->initialized = TRUE; 151 152 return S_OK; 153 } 154 155 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface, 156 UINT uiWidth, UINT uiHeight) 157 { 158 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 159 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight); 160 161 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE; 162 163 This->width = uiWidth; 164 This->height = uiHeight; 165 166 return S_OK; 167 } 168 169 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, 170 double dpiX, double dpiY) 171 { 172 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 173 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); 174 175 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE; 176 177 This->xres = dpiX; 178 This->yres = dpiY; 179 180 return S_OK; 181 } 182 183 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, 184 WICPixelFormatGUID *pPixelFormat) 185 { 186 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 187 int i; 188 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat)); 189 190 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE; 191 192 for (i=0; formats[i].guid; i++) 193 { 194 if (IsEqualGUID(formats[i].guid, pPixelFormat)) 195 break; 196 } 197 198 if (!formats[i].guid) i = 0; 199 else if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormatBlackWhite)) 200 i = 2; /* GUID_WICPixelFormat1bppIndexed */ 201 202 This->format = &formats[i]; 203 memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); 204 205 return S_OK; 206 } 207 208 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, 209 UINT cCount, IWICColorContext **ppIColorContext) 210 { 211 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 212 return E_NOTIMPL; 213 } 214 215 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, 216 IWICPalette *palette) 217 { 218 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 219 HRESULT hr; 220 221 TRACE("(%p,%p)\n", iface, palette); 222 223 if (!palette) return E_INVALIDARG; 224 225 if (!This->initialized) 226 return WINCODEC_ERR_NOTINITIALIZED; 227 228 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 229 if (hr == S_OK) 230 { 231 UINT i; 232 for (i = 0; i < This->colors; i++) 233 This->palette[i] |= 0xff000000; /* BMP palette has no alpha */ 234 } 235 return hr; 236 } 237 238 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, 239 IWICBitmapSource *pIThumbnail) 240 { 241 FIXME("(%p,%p): stub\n", iface, pIThumbnail); 242 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 243 } 244 245 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This) 246 { 247 if (!This->bits) 248 { 249 if (!This->initialized || !This->width || !This->height || !This->format) 250 return WINCODEC_ERR_WRONGSTATE; 251 252 This->stride = (((This->width * This->format->bpp)+31)/32)*4; 253 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height); 254 if (!This->bits) return E_OUTOFMEMORY; 255 } 256 257 return S_OK; 258 } 259 260 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, 261 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) 262 { 263 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 264 HRESULT hr; 265 WICRect rc; 266 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); 267 268 if (!This->initialized || !This->width || !This->height || !This->format) 269 return WINCODEC_ERR_WRONGSTATE; 270 271 hr = BmpFrameEncode_AllocateBits(This); 272 if (FAILED(hr)) return hr; 273 274 rc.X = 0; 275 rc.Y = 0; 276 rc.Width = This->width; 277 rc.Height = lineCount; 278 279 hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride, 280 &rc, This->stride, This->stride*(This->height-This->lineswritten), 281 This->bits + This->stride*This->lineswritten); 282 283 if (SUCCEEDED(hr)) 284 This->lineswritten += lineCount; 285 286 return hr; 287 } 288 289 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, 290 IWICBitmapSource *pIBitmapSource, WICRect *prc) 291 { 292 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 293 HRESULT hr; 294 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc); 295 296 if (!This->initialized) 297 return WINCODEC_ERR_WRONGSTATE; 298 299 hr = configure_write_source(iface, pIBitmapSource, prc, 300 This->format ? This->format->guid : NULL, This->width, This->height, 301 This->xres, This->yres); 302 303 if (SUCCEEDED(hr)) 304 { 305 hr = write_source(iface, pIBitmapSource, prc, 306 This->format->guid, This->format->bpp, This->width, This->height); 307 } 308 309 return hr; 310 } 311 312 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface) 313 { 314 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 315 BITMAPFILEHEADER bfh; 316 BITMAPV5HEADER bih; 317 UINT info_size, i; 318 LARGE_INTEGER pos; 319 ULONG byteswritten; 320 HRESULT hr; 321 const BYTE *bits; 322 323 TRACE("(%p)\n", iface); 324 325 if (!This->bits || This->committed || This->height != This->lineswritten) 326 return WINCODEC_ERR_WRONGSTATE; 327 328 bfh.bfType = 0x4d42; /* "BM" */ 329 bfh.bfReserved1 = 0; 330 bfh.bfReserved2 = 0; 331 332 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER); 333 bih.bV5Width = This->width; 334 bih.bV5Height = This->height; /* bottom-top bitmap */ 335 bih.bV5Planes = 1; 336 bih.bV5BitCount = This->format->bpp; 337 bih.bV5Compression = This->format->compression; 338 bih.bV5SizeImage = This->stride*This->height; 339 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254; 340 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254; 341 bih.bV5ClrUsed = (This->format->bpp <= 8) ? This->colors : 0; 342 bih.bV5ClrImportant = bih.bV5ClrUsed; 343 344 if (This->format->compression == BI_BITFIELDS) 345 { 346 if (This->format->alphamask) 347 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER); 348 else 349 info_size = sizeof(BITMAPINFOHEADER)+12; 350 bih.bV5RedMask = This->format->redmask; 351 bih.bV5GreenMask = This->format->greenmask; 352 bih.bV5BlueMask = This->format->bluemask; 353 bih.bV5AlphaMask = This->format->alphamask; 354 bih.bV5CSType = LCS_DEVICE_RGB; 355 } 356 357 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage; 358 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size; 359 bfh.bfOffBits += bih.bV5ClrUsed * sizeof(WICColor); 360 361 pos.QuadPart = 0; 362 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL); 363 if (FAILED(hr)) return hr; 364 365 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten); 366 if (FAILED(hr)) return hr; 367 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL; 368 369 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten); 370 if (FAILED(hr)) return hr; 371 if (byteswritten != info_size) return E_FAIL; 372 373 /* write the palette */ 374 if (This->format->colors) 375 { 376 hr = IStream_Write(This->stream, This->palette, This->colors * sizeof(WICColor), &byteswritten); 377 if (FAILED(hr)) return hr; 378 if (byteswritten != This->colors * sizeof(WICColor)) return E_FAIL; 379 } 380 381 /* write the image bits as a bottom-top array */ 382 bits = This->bits + bih.bV5SizeImage; 383 for (i = 0; i < This->height; i++) 384 { 385 bits -= This->stride; 386 hr = IStream_Write(This->stream, bits, This->stride, &byteswritten); 387 if (FAILED(hr)) return hr; 388 if (byteswritten != This->stride) return E_FAIL; 389 } 390 391 This->committed = TRUE; 392 393 return S_OK; 394 } 395 396 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, 397 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 398 { 399 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter); 400 return E_NOTIMPL; 401 } 402 403 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = { 404 BmpFrameEncode_QueryInterface, 405 BmpFrameEncode_AddRef, 406 BmpFrameEncode_Release, 407 BmpFrameEncode_Initialize, 408 BmpFrameEncode_SetSize, 409 BmpFrameEncode_SetResolution, 410 BmpFrameEncode_SetPixelFormat, 411 BmpFrameEncode_SetColorContexts, 412 BmpFrameEncode_SetPalette, 413 BmpFrameEncode_SetThumbnail, 414 BmpFrameEncode_WritePixels, 415 BmpFrameEncode_WriteSource, 416 BmpFrameEncode_Commit, 417 BmpFrameEncode_GetMetadataQueryWriter 418 }; 419 420 typedef struct BmpEncoder { 421 IWICBitmapEncoder IWICBitmapEncoder_iface; 422 LONG ref; 423 IStream *stream; 424 BmpFrameEncode *frame; 425 } BmpEncoder; 426 427 static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) 428 { 429 return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface); 430 } 431 432 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, 433 void **ppv) 434 { 435 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); 436 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 437 438 if (!ppv) return E_INVALIDARG; 439 440 if (IsEqualIID(&IID_IUnknown, iid) || 441 IsEqualIID(&IID_IWICBitmapEncoder, iid)) 442 { 443 *ppv = &This->IWICBitmapEncoder_iface; 444 } 445 else 446 { 447 *ppv = NULL; 448 return E_NOINTERFACE; 449 } 450 451 IUnknown_AddRef((IUnknown*)*ppv); 452 return S_OK; 453 } 454 455 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface) 456 { 457 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); 458 ULONG ref = InterlockedIncrement(&This->ref); 459 460 TRACE("(%p) refcount=%u\n", iface, ref); 461 462 return ref; 463 } 464 465 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface) 466 { 467 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); 468 ULONG ref = InterlockedDecrement(&This->ref); 469 470 TRACE("(%p) refcount=%u\n", iface, ref); 471 472 if (ref == 0) 473 { 474 if (This->stream) IStream_Release(This->stream); 475 if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface); 476 HeapFree(GetProcessHeap(), 0, This); 477 } 478 479 return ref; 480 } 481 482 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface, 483 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption) 484 { 485 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); 486 487 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption); 488 489 IStream_AddRef(pIStream); 490 This->stream = pIStream; 491 492 return S_OK; 493 } 494 495 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface, 496 GUID *pguidContainerFormat) 497 { 498 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID)); 499 return S_OK; 500 } 501 502 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) 503 { 504 IWICComponentInfo *comp_info; 505 HRESULT hr; 506 507 TRACE("%p,%p\n", iface, info); 508 509 if (!info) return E_INVALIDARG; 510 511 hr = CreateComponentInfo(&CLSID_WICBmpEncoder, &comp_info); 512 if (hr == S_OK) 513 { 514 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); 515 IWICComponentInfo_Release(comp_info); 516 } 517 return hr; 518 } 519 520 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface, 521 UINT cCount, IWICColorContext **ppIColorContext) 522 { 523 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 524 return E_NOTIMPL; 525 } 526 527 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) 528 { 529 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); 530 531 TRACE("(%p,%p)\n", iface, palette); 532 return This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED; 533 } 534 535 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail) 536 { 537 TRACE("(%p,%p)\n", iface, pIThumbnail); 538 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 539 } 540 541 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview) 542 { 543 TRACE("(%p,%p)\n", iface, pIPreview); 544 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 545 } 546 547 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface, 548 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions) 549 { 550 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); 551 BmpFrameEncode *encode; 552 HRESULT hr; 553 static const PROPBAG2 opts[1] = 554 { 555 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszEnableV5Header32bppBGRA }, 556 }; 557 558 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); 559 560 if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION; 561 562 if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED; 563 564 if (ppIEncoderOptions) 565 { 566 hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); 567 if (FAILED(hr)) return hr; 568 } 569 570 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode)); 571 if (!encode) 572 { 573 IPropertyBag2_Release(*ppIEncoderOptions); 574 *ppIEncoderOptions = NULL; 575 return E_OUTOFMEMORY; 576 } 577 encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl; 578 encode->ref = 2; 579 IStream_AddRef(This->stream); 580 encode->stream = This->stream; 581 encode->initialized = FALSE; 582 encode->width = 0; 583 encode->height = 0; 584 encode->bits = NULL; 585 encode->format = NULL; 586 encode->xres = 0.0; 587 encode->yres = 0.0; 588 encode->lineswritten = 0; 589 encode->colors = 0; 590 encode->committed = FALSE; 591 592 *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface; 593 This->frame = encode; 594 595 return S_OK; 596 } 597 598 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface) 599 { 600 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); 601 TRACE("(%p)\n", iface); 602 603 if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE; 604 605 return S_OK; 606 } 607 608 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, 609 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 610 { 611 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter); 612 return E_NOTIMPL; 613 } 614 615 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = { 616 BmpEncoder_QueryInterface, 617 BmpEncoder_AddRef, 618 BmpEncoder_Release, 619 BmpEncoder_Initialize, 620 BmpEncoder_GetContainerFormat, 621 BmpEncoder_GetEncoderInfo, 622 BmpEncoder_SetColorContexts, 623 BmpEncoder_SetPalette, 624 BmpEncoder_SetThumbnail, 625 BmpEncoder_SetPreview, 626 BmpEncoder_CreateNewFrame, 627 BmpEncoder_Commit, 628 BmpEncoder_GetMetadataQueryWriter 629 }; 630 631 HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv) 632 { 633 BmpEncoder *This; 634 HRESULT ret; 635 636 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 637 638 *ppv = NULL; 639 640 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder)); 641 if (!This) return E_OUTOFMEMORY; 642 643 This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl; 644 This->ref = 1; 645 This->stream = NULL; 646 This->frame = NULL; 647 648 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); 649 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 650 651 return ret; 652 } 653