wined3d: Explicitly calculate the sub-resource level in surface_load_texture().
[wine.git] / dlls / windowscodecs / bmpencode.c
blobafd0baf12d828a2bc767aed9a21de2d1671a8e3a
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 HRESULT hr;
248 WICRect rc;
249 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
251 if (!This->initialized || !This->width || !This->height || !This->format)
252 return WINCODEC_ERR_WRONGSTATE;
254 hr = BmpFrameEncode_AllocateBits(This);
255 if (FAILED(hr)) return hr;
257 rc.X = 0;
258 rc.Y = 0;
259 rc.Width = This->width;
260 rc.Height = lineCount;
262 hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
263 &rc, This->stride, This->stride*(This->height-This->lineswritten),
264 This->bits + This->stride*This->lineswritten);
266 if (SUCCEEDED(hr))
267 This->lineswritten += lineCount;
269 return hr;
272 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
273 IWICBitmapSource *pIBitmapSource, WICRect *prc)
275 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
276 HRESULT hr;
277 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
279 if (!This->initialized)
280 return WINCODEC_ERR_WRONGSTATE;
282 hr = configure_write_source(iface, pIBitmapSource, prc,
283 This->format ? This->format->guid : NULL, This->width, This->height,
284 This->xres, This->yres);
286 if (SUCCEEDED(hr))
288 hr = write_source(iface, pIBitmapSource, prc,
289 This->format->guid, This->format->bpp, This->width, This->height);
292 return hr;
295 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
297 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
298 BITMAPFILEHEADER bfh;
299 BITMAPV5HEADER bih;
300 UINT info_size;
301 LARGE_INTEGER pos;
302 ULONG byteswritten;
303 HRESULT hr;
305 TRACE("(%p)\n", iface);
307 if (!This->bits || This->committed || This->height != This->lineswritten)
308 return WINCODEC_ERR_WRONGSTATE;
310 bfh.bfType = 0x4d42; /* "BM" */
311 bfh.bfReserved1 = 0;
312 bfh.bfReserved2 = 0;
314 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
315 bih.bV5Width = This->width;
316 bih.bV5Height = -This->height; /* top-down bitmap */
317 bih.bV5Planes = 1;
318 bih.bV5BitCount = This->format->bpp;
319 bih.bV5Compression = This->format->compression;
320 bih.bV5SizeImage = This->stride*This->height;
321 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
322 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
323 bih.bV5ClrUsed = 0;
324 bih.bV5ClrImportant = 0;
326 if (This->format->compression == BI_BITFIELDS)
328 if (This->format->alphamask)
329 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER);
330 else
331 info_size = sizeof(BITMAPINFOHEADER)+12;
332 bih.bV5RedMask = This->format->redmask;
333 bih.bV5GreenMask = This->format->greenmask;
334 bih.bV5BlueMask = This->format->bluemask;
335 bih.bV5AlphaMask = This->format->alphamask;
336 bih.bV5CSType = LCS_DEVICE_RGB;
339 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
340 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
342 pos.QuadPart = 0;
343 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
344 if (FAILED(hr)) return hr;
346 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
347 if (FAILED(hr)) return hr;
348 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
350 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
351 if (FAILED(hr)) return hr;
352 if (byteswritten != info_size) return E_FAIL;
354 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
355 if (FAILED(hr)) return hr;
356 if (byteswritten != bih.bV5SizeImage) return E_FAIL;
358 This->committed = TRUE;
360 return S_OK;
363 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
364 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
366 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
367 return E_NOTIMPL;
370 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
371 BmpFrameEncode_QueryInterface,
372 BmpFrameEncode_AddRef,
373 BmpFrameEncode_Release,
374 BmpFrameEncode_Initialize,
375 BmpFrameEncode_SetSize,
376 BmpFrameEncode_SetResolution,
377 BmpFrameEncode_SetPixelFormat,
378 BmpFrameEncode_SetColorContexts,
379 BmpFrameEncode_SetPalette,
380 BmpFrameEncode_SetThumbnail,
381 BmpFrameEncode_WritePixels,
382 BmpFrameEncode_WriteSource,
383 BmpFrameEncode_Commit,
384 BmpFrameEncode_GetMetadataQueryWriter
387 typedef struct BmpEncoder {
388 IWICBitmapEncoder IWICBitmapEncoder_iface;
389 LONG ref;
390 IStream *stream;
391 BmpFrameEncode *frame;
392 } BmpEncoder;
394 static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
396 return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface);
399 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
400 void **ppv)
402 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
403 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
405 if (!ppv) return E_INVALIDARG;
407 if (IsEqualIID(&IID_IUnknown, iid) ||
408 IsEqualIID(&IID_IWICBitmapEncoder, iid))
410 *ppv = &This->IWICBitmapEncoder_iface;
412 else
414 *ppv = NULL;
415 return E_NOINTERFACE;
418 IUnknown_AddRef((IUnknown*)*ppv);
419 return S_OK;
422 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
424 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
425 ULONG ref = InterlockedIncrement(&This->ref);
427 TRACE("(%p) refcount=%u\n", iface, ref);
429 return ref;
432 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
434 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
435 ULONG ref = InterlockedDecrement(&This->ref);
437 TRACE("(%p) refcount=%u\n", iface, ref);
439 if (ref == 0)
441 if (This->stream) IStream_Release(This->stream);
442 if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
443 HeapFree(GetProcessHeap(), 0, This);
446 return ref;
449 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
450 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
452 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
454 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
456 IStream_AddRef(pIStream);
457 This->stream = pIStream;
459 return S_OK;
462 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
463 GUID *pguidContainerFormat)
465 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
466 return S_OK;
469 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
470 IWICBitmapEncoderInfo **ppIEncoderInfo)
472 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
473 return E_NOTIMPL;
476 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
477 UINT cCount, IWICColorContext **ppIColorContext)
479 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
480 return E_NOTIMPL;
483 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
485 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
487 TRACE("(%p,%p)\n", iface, palette);
488 return This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
491 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
493 TRACE("(%p,%p)\n", iface, pIThumbnail);
494 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
497 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
499 TRACE("(%p,%p)\n", iface, pIPreview);
500 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
503 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
504 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
506 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
507 BmpFrameEncode *encode;
508 HRESULT hr;
509 static const PROPBAG2 opts[1] =
511 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszEnableV5Header32bppBGRA },
514 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
516 if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
518 if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
520 if (ppIEncoderOptions)
522 hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions);
523 if (FAILED(hr)) return hr;
526 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
527 if (!encode)
529 IPropertyBag2_Release(*ppIEncoderOptions);
530 *ppIEncoderOptions = NULL;
531 return E_OUTOFMEMORY;
533 encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
534 encode->ref = 2;
535 IStream_AddRef(This->stream);
536 encode->stream = This->stream;
537 encode->initialized = FALSE;
538 encode->width = 0;
539 encode->height = 0;
540 encode->bits = NULL;
541 encode->format = NULL;
542 encode->xres = 0.0;
543 encode->yres = 0.0;
544 encode->lineswritten = 0;
545 encode->colors = 0;
546 encode->committed = FALSE;
548 *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
549 This->frame = encode;
551 return S_OK;
554 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
556 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
557 TRACE("(%p)\n", iface);
559 if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
561 return S_OK;
564 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
565 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
567 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
568 return E_NOTIMPL;
571 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
572 BmpEncoder_QueryInterface,
573 BmpEncoder_AddRef,
574 BmpEncoder_Release,
575 BmpEncoder_Initialize,
576 BmpEncoder_GetContainerFormat,
577 BmpEncoder_GetEncoderInfo,
578 BmpEncoder_SetColorContexts,
579 BmpEncoder_SetPalette,
580 BmpEncoder_SetThumbnail,
581 BmpEncoder_SetPreview,
582 BmpEncoder_CreateNewFrame,
583 BmpEncoder_Commit,
584 BmpEncoder_GetMetadataQueryWriter
587 HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv)
589 BmpEncoder *This;
590 HRESULT ret;
592 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
594 *ppv = NULL;
596 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
597 if (!This) return E_OUTOFMEMORY;
599 This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl;
600 This->ref = 1;
601 This->stream = NULL;
602 This->frame = NULL;
604 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
605 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
607 return ret;