wineandroid: Check that Android supports the format in IsFormatSupported.
[wine.git] / dlls / windowscodecs / bmpencode.c
blob48a8e27d4be82f5552f820121a95bae13242289b
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 inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
77 return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface);
80 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
81 void **ppv)
83 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
84 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
86 if (!ppv) return E_INVALIDARG;
88 if (IsEqualIID(&IID_IUnknown, iid) ||
89 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
91 *ppv = &This->IWICBitmapFrameEncode_iface;
93 else
95 *ppv = NULL;
96 return E_NOINTERFACE;
99 IUnknown_AddRef((IUnknown*)*ppv);
100 return S_OK;
103 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
105 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
106 ULONG ref = InterlockedIncrement(&This->ref);
108 TRACE("(%p) refcount=%u\n", iface, ref);
110 return ref;
113 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
115 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
116 ULONG ref = InterlockedDecrement(&This->ref);
118 TRACE("(%p) refcount=%u\n", iface, ref);
120 if (ref == 0)
122 if (This->stream) IStream_Release(This->stream);
123 HeapFree(GetProcessHeap(), 0, This->bits);
124 HeapFree(GetProcessHeap(), 0, This);
127 return ref;
130 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
131 IPropertyBag2 *pIEncoderOptions)
133 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
134 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
136 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
138 This->initialized = TRUE;
140 return S_OK;
143 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
144 UINT uiWidth, UINT uiHeight)
146 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
147 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
149 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
151 This->width = uiWidth;
152 This->height = uiHeight;
154 return S_OK;
157 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
158 double dpiX, double dpiY)
160 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
161 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
163 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
165 This->xres = dpiX;
166 This->yres = dpiY;
168 return S_OK;
171 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
172 WICPixelFormatGUID *pPixelFormat)
174 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
175 int i;
176 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
178 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
180 for (i=0; formats[i].guid; i++)
182 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
183 break;
186 if (!formats[i].guid) i = 0;
188 This->format = &formats[i];
189 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
191 return S_OK;
194 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
195 UINT cCount, IWICColorContext **ppIColorContext)
197 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
198 return E_NOTIMPL;
201 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
202 IWICPalette *palette)
204 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
206 TRACE("(%p,%p)\n", iface, palette);
208 if (!palette) return E_INVALIDARG;
210 if (!This->initialized)
211 return WINCODEC_ERR_NOTINITIALIZED;
213 return IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
216 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
217 IWICBitmapSource *pIThumbnail)
219 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
220 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
223 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
225 if (!This->bits)
227 if (!This->initialized || !This->width || !This->height || !This->format)
228 return WINCODEC_ERR_WRONGSTATE;
230 This->stride = (((This->width * This->format->bpp)+31)/32)*4;
231 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
232 if (!This->bits) return E_OUTOFMEMORY;
235 return S_OK;
238 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
239 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
241 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
242 HRESULT hr;
243 WICRect rc;
244 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
246 if (!This->initialized || !This->width || !This->height || !This->format)
247 return WINCODEC_ERR_WRONGSTATE;
249 hr = BmpFrameEncode_AllocateBits(This);
250 if (FAILED(hr)) return hr;
252 rc.X = 0;
253 rc.Y = 0;
254 rc.Width = This->width;
255 rc.Height = lineCount;
257 hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
258 &rc, This->stride, This->stride*(This->height-This->lineswritten),
259 This->bits + This->stride*This->lineswritten);
261 if (SUCCEEDED(hr))
262 This->lineswritten += lineCount;
264 return hr;
267 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
268 IWICBitmapSource *pIBitmapSource, WICRect *prc)
270 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
271 HRESULT hr;
272 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
274 if (!This->initialized)
275 return WINCODEC_ERR_WRONGSTATE;
277 hr = configure_write_source(iface, pIBitmapSource, prc,
278 This->format ? This->format->guid : NULL, This->width, This->height,
279 This->xres, This->yres);
281 if (SUCCEEDED(hr))
283 hr = write_source(iface, pIBitmapSource, prc,
284 This->format->guid, This->format->bpp, This->width, This->height);
287 return hr;
290 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
292 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
293 BITMAPFILEHEADER bfh;
294 BITMAPV5HEADER bih;
295 UINT info_size;
296 LARGE_INTEGER pos;
297 ULONG byteswritten;
298 HRESULT hr;
300 TRACE("(%p)\n", iface);
302 if (!This->bits || This->committed || This->height != This->lineswritten)
303 return WINCODEC_ERR_WRONGSTATE;
305 bfh.bfType = 0x4d42; /* "BM" */
306 bfh.bfReserved1 = 0;
307 bfh.bfReserved2 = 0;
309 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
310 bih.bV5Width = This->width;
311 bih.bV5Height = -This->height; /* top-down bitmap */
312 bih.bV5Planes = 1;
313 bih.bV5BitCount = This->format->bpp;
314 bih.bV5Compression = This->format->compression;
315 bih.bV5SizeImage = This->stride*This->height;
316 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
317 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
318 bih.bV5ClrUsed = 0;
319 bih.bV5ClrImportant = 0;
321 if (This->format->compression == BI_BITFIELDS)
323 if (This->format->alphamask)
324 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER);
325 else
326 info_size = sizeof(BITMAPINFOHEADER)+12;
327 bih.bV5RedMask = This->format->redmask;
328 bih.bV5GreenMask = This->format->greenmask;
329 bih.bV5BlueMask = This->format->bluemask;
330 bih.bV5AlphaMask = This->format->alphamask;
331 bih.bV5CSType = LCS_DEVICE_RGB;
334 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
335 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
337 pos.QuadPart = 0;
338 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
339 if (FAILED(hr)) return hr;
341 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
342 if (FAILED(hr)) return hr;
343 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
345 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
346 if (FAILED(hr)) return hr;
347 if (byteswritten != info_size) return E_FAIL;
349 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
350 if (FAILED(hr)) return hr;
351 if (byteswritten != bih.bV5SizeImage) return E_FAIL;
353 This->committed = TRUE;
355 return S_OK;
358 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
359 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
361 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
362 return E_NOTIMPL;
365 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
366 BmpFrameEncode_QueryInterface,
367 BmpFrameEncode_AddRef,
368 BmpFrameEncode_Release,
369 BmpFrameEncode_Initialize,
370 BmpFrameEncode_SetSize,
371 BmpFrameEncode_SetResolution,
372 BmpFrameEncode_SetPixelFormat,
373 BmpFrameEncode_SetColorContexts,
374 BmpFrameEncode_SetPalette,
375 BmpFrameEncode_SetThumbnail,
376 BmpFrameEncode_WritePixels,
377 BmpFrameEncode_WriteSource,
378 BmpFrameEncode_Commit,
379 BmpFrameEncode_GetMetadataQueryWriter
382 typedef struct BmpEncoder {
383 IWICBitmapEncoder IWICBitmapEncoder_iface;
384 LONG ref;
385 IStream *stream;
386 BmpFrameEncode *frame;
387 } BmpEncoder;
389 static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
391 return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface);
394 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
395 void **ppv)
397 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
398 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
400 if (!ppv) return E_INVALIDARG;
402 if (IsEqualIID(&IID_IUnknown, iid) ||
403 IsEqualIID(&IID_IWICBitmapEncoder, iid))
405 *ppv = &This->IWICBitmapEncoder_iface;
407 else
409 *ppv = NULL;
410 return E_NOINTERFACE;
413 IUnknown_AddRef((IUnknown*)*ppv);
414 return S_OK;
417 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
419 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
420 ULONG ref = InterlockedIncrement(&This->ref);
422 TRACE("(%p) refcount=%u\n", iface, ref);
424 return ref;
427 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
429 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
430 ULONG ref = InterlockedDecrement(&This->ref);
432 TRACE("(%p) refcount=%u\n", iface, ref);
434 if (ref == 0)
436 if (This->stream) IStream_Release(This->stream);
437 if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
438 HeapFree(GetProcessHeap(), 0, This);
441 return ref;
444 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
445 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
447 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
449 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
451 IStream_AddRef(pIStream);
452 This->stream = pIStream;
454 return S_OK;
457 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
458 GUID *pguidContainerFormat)
460 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
461 return S_OK;
464 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
465 IWICBitmapEncoderInfo **ppIEncoderInfo)
467 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
468 return E_NOTIMPL;
471 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
472 UINT cCount, IWICColorContext **ppIColorContext)
474 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
475 return E_NOTIMPL;
478 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
480 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
482 TRACE("(%p,%p)\n", iface, palette);
483 return This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
486 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
488 TRACE("(%p,%p)\n", iface, pIThumbnail);
489 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
492 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
494 TRACE("(%p,%p)\n", iface, pIPreview);
495 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
498 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
499 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
501 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
502 BmpFrameEncode *encode;
503 HRESULT hr;
505 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
507 if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
509 if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
511 hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions);
512 if (FAILED(hr)) return hr;
514 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
515 if (!encode)
517 IPropertyBag2_Release(*ppIEncoderOptions);
518 *ppIEncoderOptions = NULL;
519 return E_OUTOFMEMORY;
521 encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
522 encode->ref = 2;
523 IStream_AddRef(This->stream);
524 encode->stream = This->stream;
525 encode->initialized = FALSE;
526 encode->width = 0;
527 encode->height = 0;
528 encode->bits = NULL;
529 encode->format = NULL;
530 encode->xres = 0.0;
531 encode->yres = 0.0;
532 encode->lineswritten = 0;
533 encode->colors = 0;
534 encode->committed = FALSE;
536 *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
537 This->frame = encode;
539 return S_OK;
542 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
544 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
545 TRACE("(%p)\n", iface);
547 if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
549 return S_OK;
552 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
553 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
555 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
556 return E_NOTIMPL;
559 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
560 BmpEncoder_QueryInterface,
561 BmpEncoder_AddRef,
562 BmpEncoder_Release,
563 BmpEncoder_Initialize,
564 BmpEncoder_GetContainerFormat,
565 BmpEncoder_GetEncoderInfo,
566 BmpEncoder_SetColorContexts,
567 BmpEncoder_SetPalette,
568 BmpEncoder_SetThumbnail,
569 BmpEncoder_SetPreview,
570 BmpEncoder_CreateNewFrame,
571 BmpEncoder_Commit,
572 BmpEncoder_GetMetadataQueryWriter
575 HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv)
577 BmpEncoder *This;
578 HRESULT ret;
580 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
582 *ppv = NULL;
584 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
585 if (!This) return E_OUTOFMEMORY;
587 This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl;
588 This->ref = 1;
589 This->stream = NULL;
590 This->frame = NULL;
592 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
593 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
595 return ret;