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