msvcrtd: Fix _CrtDbgReport calling convention.
[wine.git] / dlls / windowscodecs / bmpencode.c
blob97f30d7197dd61917faa4a7ea83968888bef858b
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 WICColor palette[256];
71 UINT colors;
72 BOOL committed;
73 } BmpFrameEncode;
75 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};
77 static inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
79 return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface);
82 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
83 void **ppv)
85 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
86 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
88 if (!ppv) return E_INVALIDARG;
90 if (IsEqualIID(&IID_IUnknown, iid) ||
91 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
93 *ppv = &This->IWICBitmapFrameEncode_iface;
95 else
97 *ppv = NULL;
98 return E_NOINTERFACE;
101 IUnknown_AddRef((IUnknown*)*ppv);
102 return S_OK;
105 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
107 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
108 ULONG ref = InterlockedIncrement(&This->ref);
110 TRACE("(%p) refcount=%u\n", iface, ref);
112 return ref;
115 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
117 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
118 ULONG ref = InterlockedDecrement(&This->ref);
120 TRACE("(%p) refcount=%u\n", iface, ref);
122 if (ref == 0)
124 if (This->stream) IStream_Release(This->stream);
125 HeapFree(GetProcessHeap(), 0, This->bits);
126 HeapFree(GetProcessHeap(), 0, This);
129 return ref;
132 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
133 IPropertyBag2 *pIEncoderOptions)
135 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
136 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
138 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
140 if (pIEncoderOptions)
141 WARN("ignoring encoder options.\n");
143 This->initialized = TRUE;
145 return S_OK;
148 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
149 UINT uiWidth, UINT uiHeight)
151 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
152 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
154 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
156 This->width = uiWidth;
157 This->height = uiHeight;
159 return S_OK;
162 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
163 double dpiX, double dpiY)
165 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
166 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
168 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
170 This->xres = dpiX;
171 This->yres = dpiY;
173 return S_OK;
176 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
177 WICPixelFormatGUID *pPixelFormat)
179 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
180 int i;
181 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
183 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
185 for (i=0; formats[i].guid; i++)
187 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
188 break;
191 if (!formats[i].guid) i = 0;
193 This->format = &formats[i];
194 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
196 return S_OK;
199 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
200 UINT cCount, IWICColorContext **ppIColorContext)
202 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
203 return E_NOTIMPL;
206 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
207 IWICPalette *palette)
209 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
211 TRACE("(%p,%p)\n", iface, palette);
213 if (!palette) return E_INVALIDARG;
215 if (!This->initialized)
216 return WINCODEC_ERR_NOTINITIALIZED;
218 return IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
221 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
222 IWICBitmapSource *pIThumbnail)
224 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
225 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
228 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
230 if (!This->bits)
232 if (!This->initialized || !This->width || !This->height || !This->format)
233 return WINCODEC_ERR_WRONGSTATE;
235 This->stride = (((This->width * This->format->bpp)+31)/32)*4;
236 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
237 if (!This->bits) return E_OUTOFMEMORY;
240 return S_OK;
243 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
244 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
246 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
247 UINT dstbuffersize, bytesperrow, row;
248 BYTE *dst, *src;
249 HRESULT hr;
251 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
253 if (!This->initialized || !This->width || !This->height || !This->format)
254 return WINCODEC_ERR_WRONGSTATE;
256 hr = BmpFrameEncode_AllocateBits(This);
257 if (FAILED(hr)) return hr;
259 bytesperrow = ((This->format->bpp * This->width) + 7) / 8;
261 if (This->stride < bytesperrow)
262 return E_INVALIDARG;
264 dstbuffersize = This->stride * (This->height - This->lineswritten);
265 if ((This->stride * (lineCount - 1)) + bytesperrow > dstbuffersize)
266 return E_INVALIDARG;
268 src = pbPixels;
269 dst = This->bits + This->stride * (This->height - This->lineswritten - 1);
270 for (row = 0; row < lineCount; row++)
272 memcpy(dst, src, bytesperrow);
273 src += cbStride;
274 dst -= This->stride;
277 This->lineswritten += lineCount;
279 return S_OK;
282 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
283 IWICBitmapSource *pIBitmapSource, WICRect *prc)
285 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
286 HRESULT hr;
287 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
289 if (!This->initialized)
290 return WINCODEC_ERR_WRONGSTATE;
292 hr = configure_write_source(iface, pIBitmapSource, prc,
293 This->format ? This->format->guid : NULL, This->width, This->height,
294 This->xres, This->yres);
296 if (SUCCEEDED(hr))
298 hr = write_source(iface, pIBitmapSource, prc,
299 This->format->guid, This->format->bpp, This->width, This->height);
302 return hr;
305 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
307 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
308 BITMAPFILEHEADER bfh;
309 BITMAPV5HEADER bih;
310 UINT info_size;
311 LARGE_INTEGER pos;
312 ULONG byteswritten;
313 HRESULT hr;
315 TRACE("(%p)\n", iface);
317 if (!This->bits || This->committed || This->height != This->lineswritten)
318 return WINCODEC_ERR_WRONGSTATE;
320 bfh.bfType = 0x4d42; /* "BM" */
321 bfh.bfReserved1 = 0;
322 bfh.bfReserved2 = 0;
324 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
325 bih.bV5Width = This->width;
326 bih.bV5Height = This->height;
327 bih.bV5Planes = 1;
328 bih.bV5BitCount = This->format->bpp;
329 bih.bV5Compression = This->format->compression;
330 bih.bV5SizeImage = This->stride*This->height;
331 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
332 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
333 bih.bV5ClrUsed = 0;
334 bih.bV5ClrImportant = 0;
336 if (This->format->compression == BI_BITFIELDS)
338 if (This->format->alphamask)
339 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER);
340 else
341 info_size = sizeof(BITMAPINFOHEADER)+12;
342 bih.bV5RedMask = This->format->redmask;
343 bih.bV5GreenMask = This->format->greenmask;
344 bih.bV5BlueMask = This->format->bluemask;
345 bih.bV5AlphaMask = This->format->alphamask;
346 bih.bV5CSType = LCS_DEVICE_RGB;
349 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
350 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
352 pos.QuadPart = 0;
353 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
354 if (FAILED(hr)) return hr;
356 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
357 if (FAILED(hr)) return hr;
358 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
360 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
361 if (FAILED(hr)) return hr;
362 if (byteswritten != info_size) return E_FAIL;
364 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
365 if (FAILED(hr)) return hr;
366 if (byteswritten != bih.bV5SizeImage) return E_FAIL;
368 This->committed = TRUE;
370 return S_OK;
373 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
374 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
376 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
377 return E_NOTIMPL;
380 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
381 BmpFrameEncode_QueryInterface,
382 BmpFrameEncode_AddRef,
383 BmpFrameEncode_Release,
384 BmpFrameEncode_Initialize,
385 BmpFrameEncode_SetSize,
386 BmpFrameEncode_SetResolution,
387 BmpFrameEncode_SetPixelFormat,
388 BmpFrameEncode_SetColorContexts,
389 BmpFrameEncode_SetPalette,
390 BmpFrameEncode_SetThumbnail,
391 BmpFrameEncode_WritePixels,
392 BmpFrameEncode_WriteSource,
393 BmpFrameEncode_Commit,
394 BmpFrameEncode_GetMetadataQueryWriter
397 typedef struct BmpEncoder {
398 IWICBitmapEncoder IWICBitmapEncoder_iface;
399 LONG ref;
400 IStream *stream;
401 BmpFrameEncode *frame;
402 } BmpEncoder;
404 static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
406 return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface);
409 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
410 void **ppv)
412 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
413 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
415 if (!ppv) return E_INVALIDARG;
417 if (IsEqualIID(&IID_IUnknown, iid) ||
418 IsEqualIID(&IID_IWICBitmapEncoder, iid))
420 *ppv = &This->IWICBitmapEncoder_iface;
422 else
424 *ppv = NULL;
425 return E_NOINTERFACE;
428 IUnknown_AddRef((IUnknown*)*ppv);
429 return S_OK;
432 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
434 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
435 ULONG ref = InterlockedIncrement(&This->ref);
437 TRACE("(%p) refcount=%u\n", iface, ref);
439 return ref;
442 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
444 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
445 ULONG ref = InterlockedDecrement(&This->ref);
447 TRACE("(%p) refcount=%u\n", iface, ref);
449 if (ref == 0)
451 if (This->stream) IStream_Release(This->stream);
452 if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
453 HeapFree(GetProcessHeap(), 0, This);
456 return ref;
459 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
460 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
462 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
464 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
466 IStream_AddRef(pIStream);
467 This->stream = pIStream;
469 return S_OK;
472 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
473 GUID *pguidContainerFormat)
475 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
476 return S_OK;
479 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
480 IWICBitmapEncoderInfo **ppIEncoderInfo)
482 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
483 return E_NOTIMPL;
486 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
487 UINT cCount, IWICColorContext **ppIColorContext)
489 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
490 return E_NOTIMPL;
493 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
495 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
497 TRACE("(%p,%p)\n", iface, palette);
498 return This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
501 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
503 TRACE("(%p,%p)\n", iface, pIThumbnail);
504 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
507 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
509 TRACE("(%p,%p)\n", iface, pIPreview);
510 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
513 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
514 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
516 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
517 BmpFrameEncode *encode;
518 HRESULT hr;
519 static const PROPBAG2 opts[1] =
521 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszEnableV5Header32bppBGRA },
524 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
526 if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
528 if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
530 if (ppIEncoderOptions)
532 hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions);
533 if (FAILED(hr)) return hr;
536 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
537 if (!encode)
539 IPropertyBag2_Release(*ppIEncoderOptions);
540 *ppIEncoderOptions = NULL;
541 return E_OUTOFMEMORY;
543 encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
544 encode->ref = 2;
545 IStream_AddRef(This->stream);
546 encode->stream = This->stream;
547 encode->initialized = FALSE;
548 encode->width = 0;
549 encode->height = 0;
550 encode->bits = NULL;
551 encode->format = NULL;
552 encode->xres = 0.0;
553 encode->yres = 0.0;
554 encode->lineswritten = 0;
555 encode->colors = 0;
556 encode->committed = FALSE;
558 *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
559 This->frame = encode;
561 return S_OK;
564 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
566 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
567 TRACE("(%p)\n", iface);
569 if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
571 return S_OK;
574 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
575 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
577 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
578 return E_NOTIMPL;
581 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
582 BmpEncoder_QueryInterface,
583 BmpEncoder_AddRef,
584 BmpEncoder_Release,
585 BmpEncoder_Initialize,
586 BmpEncoder_GetContainerFormat,
587 BmpEncoder_GetEncoderInfo,
588 BmpEncoder_SetColorContexts,
589 BmpEncoder_SetPalette,
590 BmpEncoder_SetThumbnail,
591 BmpEncoder_SetPreview,
592 BmpEncoder_CreateNewFrame,
593 BmpEncoder_Commit,
594 BmpEncoder_GetMetadataQueryWriter
597 HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv)
599 BmpEncoder *This;
600 HRESULT ret;
602 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
604 *ppv = NULL;
606 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
607 if (!This) return E_OUTOFMEMORY;
609 This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl;
610 This->ref = 1;
611 This->stream = NULL;
612 This->frame = NULL;
614 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
615 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
617 return ret;