makefiles: Generate the config.status dependency as part of the makefile dependencies.
[wine/multimedia.git] / dlls / windowscodecs / bmpencode.c
blobb79a19ba61b2c844637988e3f0bbdf4ecc56f877
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"
30 #include "wincodec.h"
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 struct bmp_pixelformat {
39 const WICPixelFormatGUID *guid;
40 UINT bpp;
41 DWORD compression;
42 DWORD redmask;
43 DWORD greenmask;
44 DWORD bluemask;
45 DWORD alphamask;
48 static const struct bmp_pixelformat formats[] = {
49 {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
50 {&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB},
51 {&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
52 {&GUID_WICPixelFormat32bppBGR, 32, BI_RGB},
53 #if 0
54 /* Windows doesn't seem to support this one. */
55 {&GUID_WICPixelFormat32bppBGRA, 32, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
56 #endif
57 {NULL}
60 typedef struct BmpFrameEncode {
61 const IWICBitmapFrameEncodeVtbl *lpVtbl;
62 LONG ref;
63 IStream *stream;
64 BOOL initialized;
65 UINT width, height;
66 BYTE *bits;
67 const struct bmp_pixelformat *format;
68 double xres, yres;
69 UINT lineswritten;
70 UINT stride;
71 BOOL committed;
72 } BmpFrameEncode;
74 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
75 void **ppv)
77 BmpFrameEncode *This = (BmpFrameEncode*)iface;
78 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
80 if (!ppv) return E_INVALIDARG;
82 if (IsEqualIID(&IID_IUnknown, iid) ||
83 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
85 *ppv = This;
87 else
89 *ppv = NULL;
90 return E_NOINTERFACE;
93 IUnknown_AddRef((IUnknown*)*ppv);
94 return S_OK;
97 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
99 BmpFrameEncode *This = (BmpFrameEncode*)iface;
100 ULONG ref = InterlockedIncrement(&This->ref);
102 TRACE("(%p) refcount=%u\n", iface, ref);
104 return ref;
107 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
109 BmpFrameEncode *This = (BmpFrameEncode*)iface;
110 ULONG ref = InterlockedDecrement(&This->ref);
112 TRACE("(%p) refcount=%u\n", iface, ref);
114 if (ref == 0)
116 if (This->stream) IStream_Release(This->stream);
117 HeapFree(GetProcessHeap(), 0, This->bits);
118 HeapFree(GetProcessHeap(), 0, This);
121 return ref;
124 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
125 IPropertyBag2 *pIEncoderOptions)
127 BmpFrameEncode *This = (BmpFrameEncode*)iface;
128 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
130 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
132 This->initialized = TRUE;
134 return S_OK;
137 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
138 UINT uiWidth, UINT uiHeight)
140 BmpFrameEncode *This = (BmpFrameEncode*)iface;
141 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
143 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
145 This->width = uiWidth;
146 This->height = uiHeight;
148 return S_OK;
151 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
152 double dpiX, double dpiY)
154 BmpFrameEncode *This = (BmpFrameEncode*)iface;
155 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
157 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
159 This->xres = dpiX;
160 This->yres = dpiY;
162 return S_OK;
165 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
166 WICPixelFormatGUID *pPixelFormat)
168 BmpFrameEncode *This = (BmpFrameEncode*)iface;
169 int i;
170 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
172 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
174 for (i=0; formats[i].guid; i++)
176 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
177 break;
180 if (!formats[i].guid) i = 0;
182 This->format = &formats[i];
183 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
185 return S_OK;
188 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
189 UINT cCount, IWICColorContext **ppIColorContext)
191 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
192 return E_NOTIMPL;
195 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
196 IWICPalette *pIPalette)
198 FIXME("(%p,%p): stub\n", iface, pIPalette);
199 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
202 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
203 IWICBitmapSource *pIThumbnail)
205 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
206 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
209 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
211 if (!This->bits)
213 if (!This->initialized || !This->width || !This->height || !This->format)
214 return WINCODEC_ERR_WRONGSTATE;
216 This->stride = (((This->width * This->format->bpp)+31)/32)*4;
217 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
218 if (!This->bits) return E_OUTOFMEMORY;
221 return S_OK;
224 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
225 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
227 BmpFrameEncode *This = (BmpFrameEncode*)iface;
228 HRESULT hr;
229 WICRect rc;
230 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
232 if (!This->initialized || !This->width || !This->height || !This->format)
233 return WINCODEC_ERR_WRONGSTATE;
235 hr = BmpFrameEncode_AllocateBits(This);
236 if (FAILED(hr)) return hr;
238 rc.X = 0;
239 rc.Y = 0;
240 rc.Width = This->width;
241 rc.Height = lineCount;
243 hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
244 &rc, This->stride, This->stride*(This->height-This->lineswritten),
245 This->bits + This->stride*This->lineswritten);
247 if (SUCCEEDED(hr))
248 This->lineswritten += lineCount;
250 return hr;
253 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
254 IWICBitmapSource *pIBitmapSource, WICRect *prc)
256 BmpFrameEncode *This = (BmpFrameEncode*)iface;
257 HRESULT hr;
258 WICRect rc;
259 WICPixelFormatGUID guid;
260 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
262 if (!This->initialized || !This->width || !This->height)
263 return WINCODEC_ERR_WRONGSTATE;
265 if (!This->format)
267 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
268 if (FAILED(hr)) return hr;
269 hr = BmpFrameEncode_SetPixelFormat(iface, &guid);
270 if (FAILED(hr)) return hr;
273 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
274 if (FAILED(hr)) return hr;
275 if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
277 /* should use WICConvertBitmapSource to convert, but that's unimplemented */
278 ERR("format %s unsupported\n", debugstr_guid(&guid));
279 return E_FAIL;
282 if (This->xres == 0.0 || This->yres == 0.0)
284 double xres, yres;
285 hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
286 if (FAILED(hr)) return hr;
287 hr = BmpFrameEncode_SetResolution(iface, xres, yres);
288 if (FAILED(hr)) return hr;
291 if (!prc)
293 UINT width, height;
294 hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
295 if (FAILED(hr)) return hr;
296 rc.X = 0;
297 rc.Y = 0;
298 rc.Width = width;
299 rc.Height = height;
300 prc = &rc;
303 if (prc->Width != This->width) return E_INVALIDARG;
305 hr = BmpFrameEncode_AllocateBits(This);
306 if (FAILED(hr)) return hr;
308 hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, This->stride,
309 This->stride*(This->height-This->lineswritten),
310 This->bits + This->stride*This->lineswritten);
312 This->lineswritten += rc.Height;
314 return S_OK;
317 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
319 BmpFrameEncode *This = (BmpFrameEncode*)iface;
320 BITMAPFILEHEADER bfh;
321 BITMAPV5HEADER bih;
322 UINT info_size;
323 LARGE_INTEGER pos;
324 ULONG byteswritten;
325 HRESULT hr;
327 TRACE("(%p)\n", iface);
329 if (!This->bits || This->committed || This->height != This->lineswritten)
330 return WINCODEC_ERR_WRONGSTATE;
332 bfh.bfType = 0x4d42; /* "BM" */
333 bfh.bfReserved1 = 0;
334 bfh.bfReserved2 = 0;
336 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
337 bih.bV5Width = This->width;
338 bih.bV5Height = -This->height; /* top-down bitmap */
339 bih.bV5Planes = 1;
340 bih.bV5BitCount = This->format->bpp;
341 bih.bV5Compression = This->format->compression;
342 bih.bV5SizeImage = This->stride*This->height;
343 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
344 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
345 bih.bV5ClrUsed = 0;
346 bih.bV5ClrImportant = 0;
348 if (This->format->compression == BI_BITFIELDS)
350 if (This->format->alphamask)
351 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER);
352 else
353 info_size = sizeof(BITMAPINFOHEADER)+12;
354 bih.bV5RedMask = This->format->redmask;
355 bih.bV5GreenMask = This->format->greenmask;
356 bih.bV5BlueMask = This->format->bluemask;
357 bih.bV5AlphaMask = This->format->alphamask;
358 bih.bV5AlphaMask = LCS_DEVICE_RGB;
361 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
362 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
364 pos.QuadPart = 0;
365 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
366 if (FAILED(hr)) return hr;
368 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
369 if (FAILED(hr)) return hr;
370 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
372 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
373 if (FAILED(hr)) return hr;
374 if (byteswritten != info_size) return E_FAIL;
376 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
377 if (FAILED(hr)) return hr;
378 if (byteswritten != bih.bV5SizeImage) return E_FAIL;
380 This->committed = TRUE;
382 return S_OK;
385 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
386 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
388 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
389 return E_NOTIMPL;
392 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
393 BmpFrameEncode_QueryInterface,
394 BmpFrameEncode_AddRef,
395 BmpFrameEncode_Release,
396 BmpFrameEncode_Initialize,
397 BmpFrameEncode_SetSize,
398 BmpFrameEncode_SetResolution,
399 BmpFrameEncode_SetPixelFormat,
400 BmpFrameEncode_SetColorContexts,
401 BmpFrameEncode_SetPalette,
402 BmpFrameEncode_SetThumbnail,
403 BmpFrameEncode_WritePixels,
404 BmpFrameEncode_WriteSource,
405 BmpFrameEncode_Commit,
406 BmpFrameEncode_GetMetadataQueryWriter
409 typedef struct BmpEncoder {
410 const IWICBitmapEncoderVtbl *lpVtbl;
411 LONG ref;
412 IStream *stream;
413 IWICBitmapFrameEncode *frame;
414 } BmpEncoder;
416 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
417 void **ppv)
419 BmpEncoder *This = (BmpEncoder*)iface;
420 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
422 if (!ppv) return E_INVALIDARG;
424 if (IsEqualIID(&IID_IUnknown, iid) ||
425 IsEqualIID(&IID_IWICBitmapEncoder, iid))
427 *ppv = This;
429 else
431 *ppv = NULL;
432 return E_NOINTERFACE;
435 IUnknown_AddRef((IUnknown*)*ppv);
436 return S_OK;
439 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
441 BmpEncoder *This = (BmpEncoder*)iface;
442 ULONG ref = InterlockedIncrement(&This->ref);
444 TRACE("(%p) refcount=%u\n", iface, ref);
446 return ref;
449 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
451 BmpEncoder *This = (BmpEncoder*)iface;
452 ULONG ref = InterlockedDecrement(&This->ref);
454 TRACE("(%p) refcount=%u\n", iface, ref);
456 if (ref == 0)
458 if (This->stream) IStream_Release(This->stream);
459 if (This->frame) IWICBitmapFrameEncode_Release(This->frame);
460 HeapFree(GetProcessHeap(), 0, This);
463 return ref;
466 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
467 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
469 BmpEncoder *This = (BmpEncoder*)iface;
471 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
473 IStream_AddRef(pIStream);
474 This->stream = pIStream;
476 return S_OK;
479 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
480 GUID *pguidContainerFormat)
482 FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
483 return E_NOTIMPL;
486 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
487 IWICBitmapEncoderInfo **ppIEncoderInfo)
489 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
490 return E_NOTIMPL;
493 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
494 UINT cCount, IWICColorContext **ppIColorContext)
496 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
497 return E_NOTIMPL;
500 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
502 TRACE("(%p,%p)\n", iface, pIPalette);
503 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
506 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
508 TRACE("(%p,%p)\n", iface, pIThumbnail);
509 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
512 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
514 TRACE("(%p,%p)\n", iface, pIPreview);
515 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
518 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
519 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
521 BmpEncoder *This = (BmpEncoder*)iface;
522 BmpFrameEncode *encode;
523 HRESULT hr;
525 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
527 if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
529 if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
531 hr = CreatePropertyBag2(ppIEncoderOptions);
532 if (FAILED(hr)) return hr;
534 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
535 if (!encode)
537 IPropertyBag2_Release(*ppIEncoderOptions);
538 *ppIEncoderOptions = NULL;
539 return E_OUTOFMEMORY;
541 encode->lpVtbl = &BmpFrameEncode_Vtbl;
542 encode->ref = 2;
543 IStream_AddRef(This->stream);
544 encode->stream = This->stream;
545 encode->initialized = FALSE;
546 encode->width = 0;
547 encode->height = 0;
548 encode->bits = NULL;
549 encode->format = NULL;
550 encode->xres = 0.0;
551 encode->yres = 0.0;
552 encode->lineswritten = 0;
553 encode->committed = FALSE;
555 *ppIFrameEncode = (IWICBitmapFrameEncode*)encode;
556 This->frame = (IWICBitmapFrameEncode*)encode;
558 return S_OK;
561 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
563 BmpEncoder *This = (BmpEncoder*)iface;
564 BmpFrameEncode *frame = (BmpFrameEncode*)This->frame;
565 TRACE("(%p)\n", iface);
567 if (!frame || !frame->committed) return WINCODEC_ERR_WRONGSTATE;
569 return S_OK;
572 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
573 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
575 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
576 return E_NOTIMPL;
579 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
580 BmpEncoder_QueryInterface,
581 BmpEncoder_AddRef,
582 BmpEncoder_Release,
583 BmpEncoder_Initialize,
584 BmpEncoder_GetContainerFormat,
585 BmpEncoder_GetEncoderInfo,
586 BmpEncoder_SetColorContexts,
587 BmpEncoder_SetPalette,
588 BmpEncoder_SetThumbnail,
589 BmpEncoder_SetPreview,
590 BmpEncoder_CreateNewFrame,
591 BmpEncoder_Commit,
592 BmpEncoder_GetMetadataQueryWriter
595 HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
597 BmpEncoder *This;
598 HRESULT ret;
600 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
602 *ppv = NULL;
604 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
606 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
607 if (!This) return E_OUTOFMEMORY;
609 This->lpVtbl = &BmpEncoder_Vtbl;
610 This->ref = 1;
611 This->stream = NULL;
612 This->frame = NULL;
614 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
615 IUnknown_Release((IUnknown*)This);
617 return ret;