d3d11: Make extracting input signature more robust.
[wine.git] / dlls / windowscodecs / bmpencode.c
blob3dce8bb73665c4e642e3e86cd8a156beee0aa1fc
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "wingdi.h"
29 #include "objbase.h"
31 #include "wincodecs_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37 struct bmp_pixelformat {
38 const WICPixelFormatGUID *guid;
39 UINT bpp;
40 DWORD compression;
41 DWORD redmask;
42 DWORD greenmask;
43 DWORD bluemask;
44 DWORD alphamask;
47 static const struct bmp_pixelformat formats[] = {
48 {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
49 {&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB},
50 {&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
51 {&GUID_WICPixelFormat32bppBGR, 32, BI_RGB},
52 #if 0
53 /* Windows doesn't seem to support this one. */
54 {&GUID_WICPixelFormat32bppBGRA, 32, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
55 #endif
56 {NULL}
59 typedef struct BmpFrameEncode {
60 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
61 LONG ref;
62 IStream *stream;
63 BOOL initialized;
64 UINT width, height;
65 BYTE *bits;
66 const struct bmp_pixelformat *format;
67 double xres, yres;
68 UINT lineswritten;
69 UINT stride;
70 BOOL committed;
71 } BmpFrameEncode;
73 static inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
75 return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface);
78 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
79 void **ppv)
81 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
82 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
84 if (!ppv) return E_INVALIDARG;
86 if (IsEqualIID(&IID_IUnknown, iid) ||
87 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
89 *ppv = &This->IWICBitmapFrameEncode_iface;
91 else
93 *ppv = NULL;
94 return E_NOINTERFACE;
97 IUnknown_AddRef((IUnknown*)*ppv);
98 return S_OK;
101 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
103 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
104 ULONG ref = InterlockedIncrement(&This->ref);
106 TRACE("(%p) refcount=%u\n", iface, ref);
108 return ref;
111 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
113 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
114 ULONG ref = InterlockedDecrement(&This->ref);
116 TRACE("(%p) refcount=%u\n", iface, ref);
118 if (ref == 0)
120 if (This->stream) IStream_Release(This->stream);
121 HeapFree(GetProcessHeap(), 0, This->bits);
122 HeapFree(GetProcessHeap(), 0, This);
125 return ref;
128 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
129 IPropertyBag2 *pIEncoderOptions)
131 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
132 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
134 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
136 This->initialized = TRUE;
138 return S_OK;
141 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
142 UINT uiWidth, UINT uiHeight)
144 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
145 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
147 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
149 This->width = uiWidth;
150 This->height = uiHeight;
152 return S_OK;
155 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
156 double dpiX, double dpiY)
158 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
159 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
161 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
163 This->xres = dpiX;
164 This->yres = dpiY;
166 return S_OK;
169 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
170 WICPixelFormatGUID *pPixelFormat)
172 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
173 int i;
174 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
176 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
178 for (i=0; formats[i].guid; i++)
180 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
181 break;
184 if (!formats[i].guid) i = 0;
186 This->format = &formats[i];
187 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
189 return S_OK;
192 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
193 UINT cCount, IWICColorContext **ppIColorContext)
195 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
196 return E_NOTIMPL;
199 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
200 IWICPalette *pIPalette)
202 FIXME("(%p,%p): stub\n", iface, pIPalette);
203 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
206 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
207 IWICBitmapSource *pIThumbnail)
209 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
210 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
213 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
215 if (!This->bits)
217 if (!This->initialized || !This->width || !This->height || !This->format)
218 return WINCODEC_ERR_WRONGSTATE;
220 This->stride = (((This->width * This->format->bpp)+31)/32)*4;
221 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
222 if (!This->bits) return E_OUTOFMEMORY;
225 return S_OK;
228 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
229 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
231 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
232 HRESULT hr;
233 WICRect rc;
234 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
236 if (!This->initialized || !This->width || !This->height || !This->format)
237 return WINCODEC_ERR_WRONGSTATE;
239 hr = BmpFrameEncode_AllocateBits(This);
240 if (FAILED(hr)) return hr;
242 rc.X = 0;
243 rc.Y = 0;
244 rc.Width = This->width;
245 rc.Height = lineCount;
247 hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
248 &rc, This->stride, This->stride*(This->height-This->lineswritten),
249 This->bits + This->stride*This->lineswritten);
251 if (SUCCEEDED(hr))
252 This->lineswritten += lineCount;
254 return hr;
257 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
258 IWICBitmapSource *pIBitmapSource, WICRect *prc)
260 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
261 HRESULT hr;
262 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
264 if (!This->initialized)
265 return WINCODEC_ERR_WRONGSTATE;
267 hr = configure_write_source(iface, pIBitmapSource, prc,
268 This->format ? This->format->guid : NULL, This->width, This->height,
269 This->xres, This->yres);
271 if (SUCCEEDED(hr))
273 hr = write_source(iface, pIBitmapSource, prc,
274 This->format->guid, This->format->bpp, This->width, This->height);
277 return hr;
280 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
282 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
283 BITMAPFILEHEADER bfh;
284 BITMAPV5HEADER bih;
285 UINT info_size;
286 LARGE_INTEGER pos;
287 ULONG byteswritten;
288 HRESULT hr;
290 TRACE("(%p)\n", iface);
292 if (!This->bits || This->committed || This->height != This->lineswritten)
293 return WINCODEC_ERR_WRONGSTATE;
295 bfh.bfType = 0x4d42; /* "BM" */
296 bfh.bfReserved1 = 0;
297 bfh.bfReserved2 = 0;
299 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
300 bih.bV5Width = This->width;
301 bih.bV5Height = -This->height; /* top-down bitmap */
302 bih.bV5Planes = 1;
303 bih.bV5BitCount = This->format->bpp;
304 bih.bV5Compression = This->format->compression;
305 bih.bV5SizeImage = This->stride*This->height;
306 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
307 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
308 bih.bV5ClrUsed = 0;
309 bih.bV5ClrImportant = 0;
311 if (This->format->compression == BI_BITFIELDS)
313 if (This->format->alphamask)
314 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER);
315 else
316 info_size = sizeof(BITMAPINFOHEADER)+12;
317 bih.bV5RedMask = This->format->redmask;
318 bih.bV5GreenMask = This->format->greenmask;
319 bih.bV5BlueMask = This->format->bluemask;
320 bih.bV5AlphaMask = This->format->alphamask;
321 bih.bV5CSType = LCS_DEVICE_RGB;
324 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
325 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
327 pos.QuadPart = 0;
328 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
329 if (FAILED(hr)) return hr;
331 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
332 if (FAILED(hr)) return hr;
333 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
335 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
336 if (FAILED(hr)) return hr;
337 if (byteswritten != info_size) return E_FAIL;
339 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
340 if (FAILED(hr)) return hr;
341 if (byteswritten != bih.bV5SizeImage) return E_FAIL;
343 This->committed = TRUE;
345 return S_OK;
348 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
349 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
351 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
352 return E_NOTIMPL;
355 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
356 BmpFrameEncode_QueryInterface,
357 BmpFrameEncode_AddRef,
358 BmpFrameEncode_Release,
359 BmpFrameEncode_Initialize,
360 BmpFrameEncode_SetSize,
361 BmpFrameEncode_SetResolution,
362 BmpFrameEncode_SetPixelFormat,
363 BmpFrameEncode_SetColorContexts,
364 BmpFrameEncode_SetPalette,
365 BmpFrameEncode_SetThumbnail,
366 BmpFrameEncode_WritePixels,
367 BmpFrameEncode_WriteSource,
368 BmpFrameEncode_Commit,
369 BmpFrameEncode_GetMetadataQueryWriter
372 typedef struct BmpEncoder {
373 IWICBitmapEncoder IWICBitmapEncoder_iface;
374 LONG ref;
375 IStream *stream;
376 BmpFrameEncode *frame;
377 } BmpEncoder;
379 static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
381 return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface);
384 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
385 void **ppv)
387 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
388 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
390 if (!ppv) return E_INVALIDARG;
392 if (IsEqualIID(&IID_IUnknown, iid) ||
393 IsEqualIID(&IID_IWICBitmapEncoder, iid))
395 *ppv = &This->IWICBitmapEncoder_iface;
397 else
399 *ppv = NULL;
400 return E_NOINTERFACE;
403 IUnknown_AddRef((IUnknown*)*ppv);
404 return S_OK;
407 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
409 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
410 ULONG ref = InterlockedIncrement(&This->ref);
412 TRACE("(%p) refcount=%u\n", iface, ref);
414 return ref;
417 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
419 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
420 ULONG ref = InterlockedDecrement(&This->ref);
422 TRACE("(%p) refcount=%u\n", iface, ref);
424 if (ref == 0)
426 if (This->stream) IStream_Release(This->stream);
427 if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
428 HeapFree(GetProcessHeap(), 0, This);
431 return ref;
434 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
435 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
437 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
439 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
441 IStream_AddRef(pIStream);
442 This->stream = pIStream;
444 return S_OK;
447 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
448 GUID *pguidContainerFormat)
450 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
451 return S_OK;
454 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
455 IWICBitmapEncoderInfo **ppIEncoderInfo)
457 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
458 return E_NOTIMPL;
461 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
462 UINT cCount, IWICColorContext **ppIColorContext)
464 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
465 return E_NOTIMPL;
468 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
470 TRACE("(%p,%p)\n", iface, pIPalette);
471 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
474 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
476 TRACE("(%p,%p)\n", iface, pIThumbnail);
477 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
480 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
482 TRACE("(%p,%p)\n", iface, pIPreview);
483 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
486 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
487 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
489 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
490 BmpFrameEncode *encode;
491 HRESULT hr;
493 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
495 if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
497 if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
499 hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions);
500 if (FAILED(hr)) return hr;
502 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
503 if (!encode)
505 IPropertyBag2_Release(*ppIEncoderOptions);
506 *ppIEncoderOptions = NULL;
507 return E_OUTOFMEMORY;
509 encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
510 encode->ref = 2;
511 IStream_AddRef(This->stream);
512 encode->stream = This->stream;
513 encode->initialized = FALSE;
514 encode->width = 0;
515 encode->height = 0;
516 encode->bits = NULL;
517 encode->format = NULL;
518 encode->xres = 0.0;
519 encode->yres = 0.0;
520 encode->lineswritten = 0;
521 encode->committed = FALSE;
523 *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
524 This->frame = encode;
526 return S_OK;
529 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
531 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
532 TRACE("(%p)\n", iface);
534 if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
536 return S_OK;
539 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
540 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
542 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
543 return E_NOTIMPL;
546 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
547 BmpEncoder_QueryInterface,
548 BmpEncoder_AddRef,
549 BmpEncoder_Release,
550 BmpEncoder_Initialize,
551 BmpEncoder_GetContainerFormat,
552 BmpEncoder_GetEncoderInfo,
553 BmpEncoder_SetColorContexts,
554 BmpEncoder_SetPalette,
555 BmpEncoder_SetThumbnail,
556 BmpEncoder_SetPreview,
557 BmpEncoder_CreateNewFrame,
558 BmpEncoder_Commit,
559 BmpEncoder_GetMetadataQueryWriter
562 HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv)
564 BmpEncoder *This;
565 HRESULT ret;
567 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
569 *ppv = NULL;
571 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
572 if (!This) return E_OUTOFMEMORY;
574 This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl;
575 This->ref = 1;
576 This->stream = NULL;
577 This->frame = NULL;
579 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
580 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
582 return ret;