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 if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormatBlackWhite)) 193 *pPixelFormat = GUID_WICPixelFormat1bppIndexed; 194 else if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormat2bppIndexed)) 195 *pPixelFormat = GUID_WICPixelFormat4bppIndexed; 196 197 for (i=0; formats[i].guid; i++) 198 { 199 if (IsEqualGUID(formats[i].guid, pPixelFormat)) 200 break; 201 } 202 203 if (!formats[i].guid) i = 0; 204 205 This->format = &formats[i]; 206 memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); 207 208 return S_OK; 209 } 210 211 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, 212 UINT cCount, IWICColorContext **ppIColorContext) 213 { 214 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 215 return E_NOTIMPL; 216 } 217 218 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, 219 IWICPalette *palette) 220 { 221 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 222 HRESULT hr; 223 224 TRACE("(%p,%p)\n", iface, palette); 225 226 if (!palette) return E_INVALIDARG; 227 228 if (!This->initialized) 229 return WINCODEC_ERR_NOTINITIALIZED; 230 231 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 232 if (hr == S_OK) 233 { 234 UINT i; 235 for (i = 0; i < This->colors; i++) 236 This->palette[i] |= 0xff000000; /* BMP palette has no alpha */ 237 } 238 return hr; 239 } 240 241 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, 242 IWICBitmapSource *pIThumbnail) 243 { 244 FIXME("(%p,%p): stub\n", iface, pIThumbnail); 245 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 246 } 247 248 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This) 249 { 250 if (!This->bits) 251 { 252 if (!This->initialized || !This->width || !This->height || !This->format) 253 return WINCODEC_ERR_WRONGSTATE; 254 255 This->stride = (((This->width * This->format->bpp)+31)/32)*4; 256 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height); 257 if (!This->bits) return E_OUTOFMEMORY; 258 } 259 260 return S_OK; 261 } 262 263 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, 264 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) 265 { 266 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 267 UINT dstbuffersize, bytesperrow, row; 268 BYTE *dst, *src; 269 HRESULT hr; 270 271 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); 272 273 if (!This->initialized || !This->width || !This->height || !This->format) 274 return WINCODEC_ERR_WRONGSTATE; 275 276 hr = BmpFrameEncode_AllocateBits(This); 277 if (FAILED(hr)) return hr; 278 279 bytesperrow = ((This->format->bpp * This->width) + 7) / 8; 280 281 if (This->stride < bytesperrow) 282 return E_INVALIDARG; 283 284 dstbuffersize = This->stride * (This->height - This->lineswritten); 285 if ((This->stride * (lineCount - 1)) + bytesperrow > dstbuffersize) 286 return E_INVALIDARG; 287 288 src = pbPixels; 289 dst = This->bits + This->stride * (This->height - This->lineswritten - 1); 290 for (row = 0; row < lineCount; row++) 291 { 292 memcpy(dst, src, bytesperrow); 293 src += cbStride; 294 dst -= This->stride; 295 } 296 297 This->lineswritten += lineCount; 298 299 return S_OK; 300 } 301 302 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, 303 IWICBitmapSource *pIBitmapSource, WICRect *prc) 304 { 305 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 306 HRESULT hr; 307 TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc)); 308 309 if (!This->initialized) 310 return WINCODEC_ERR_WRONGSTATE; 311 312 hr = configure_write_source(iface, pIBitmapSource, prc, 313 This->format ? This->format->guid : NULL, This->width, This->height, 314 This->xres, This->yres); 315 316 if (SUCCEEDED(hr)) 317 { 318 hr = write_source(iface, pIBitmapSource, prc, 319 This->format->guid, This->format->bpp, This->width, This->height); 320 } 321 322 return hr; 323 } 324 325 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface) 326 { 327 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 328 BITMAPFILEHEADER bfh; 329 BITMAPV5HEADER bih; 330 UINT info_size; 331 LARGE_INTEGER pos; 332 ULONG byteswritten; 333 HRESULT hr; 334 335 TRACE("(%p)\n", iface); 336 337 if (!This->bits || This->committed || This->height != This->lineswritten) 338 return WINCODEC_ERR_WRONGSTATE; 339 340 bfh.bfType = 0x4d42; /* "BM" */ 341 bfh.bfReserved1 = 0; 342 bfh.bfReserved2 = 0; 343 344 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER); 345 bih.bV5Width = This->width; 346 bih.bV5Height = This->height; 347 bih.bV5Planes = 1; 348 bih.bV5BitCount = This->format->bpp; 349 bih.bV5Compression = This->format->compression; 350 bih.bV5SizeImage = This->stride*This->height; 351 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254; 352 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254; 353 bih.bV5ClrUsed = (This->format->bpp <= 8) ? This->colors : 0; 354 bih.bV5ClrImportant = bih.bV5ClrUsed; 355 356 if (This->format->compression == BI_BITFIELDS) 357 { 358 if (This->format->alphamask) 359 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER); 360 else 361 info_size = sizeof(BITMAPINFOHEADER)+12; 362 bih.bV5RedMask = This->format->redmask; 363 bih.bV5GreenMask = This->format->greenmask; 364 bih.bV5BlueMask = This->format->bluemask; 365 bih.bV5AlphaMask = This->format->alphamask; 366 bih.bV5CSType = LCS_DEVICE_RGB; 367 } 368 369 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage; 370 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size; 371 bfh.bfOffBits += bih.bV5ClrUsed * sizeof(WICColor); 372 373 pos.QuadPart = 0; 374 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL); 375 if (FAILED(hr)) return hr; 376 377 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten); 378 if (FAILED(hr)) return hr; 379 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL; 380 381 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten); 382 if (FAILED(hr)) return hr; 383 if (byteswritten != info_size) return E_FAIL; 384 385 /* write the palette */ 386 if (This->format->colors) 387 { 388 hr = IStream_Write(This->stream, This->palette, This->colors * sizeof(WICColor), &byteswritten); 389 if (FAILED(hr)) return hr; 390 if (byteswritten != This->colors * sizeof(WICColor)) return E_FAIL; 391 } 392 393 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten); 394 if (FAILED(hr)) return hr; 395 if (byteswritten != bih.bV5SizeImage) return E_FAIL; 396 397 This->committed = TRUE; 398 399 return S_OK; 400 } 401 402 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, 403 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 404 { 405 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter); 406 return E_NOTIMPL; 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=%u\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=%u\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 HeapFree(GetProcessHeap(), 0, 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)wszEnableV5Header32bppBGRA }, 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 = HeapAlloc(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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