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
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 struct bmp_pixelformat {
39 const WICPixelFormatGUID *guid;
48 static const struct bmp_pixelformat formats[] = {
49 {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
53 typedef struct BmpFrameEncode {
54 const IWICBitmapFrameEncodeVtbl *lpVtbl;
60 const struct bmp_pixelformat *format;
67 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
70 BmpFrameEncode *This = (BmpFrameEncode*)iface;
71 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
73 if (!ppv) return E_INVALIDARG;
75 if (IsEqualIID(&IID_IUnknown, iid) ||
76 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
86 IUnknown_AddRef((IUnknown*)*ppv);
90 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
92 BmpFrameEncode *This = (BmpFrameEncode*)iface;
93 ULONG ref = InterlockedIncrement(&This->ref);
95 TRACE("(%p) refcount=%u\n", iface, ref);
100 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
102 BmpFrameEncode *This = (BmpFrameEncode*)iface;
103 ULONG ref = InterlockedDecrement(&This->ref);
105 TRACE("(%p) refcount=%u\n", iface, ref);
109 if (This->stream) IStream_Release(This->stream);
110 HeapFree(GetProcessHeap(), 0, This->bits);
111 HeapFree(GetProcessHeap(), 0, This);
117 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
118 IPropertyBag2 *pIEncoderOptions)
120 BmpFrameEncode *This = (BmpFrameEncode*)iface;
121 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
123 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
125 This->initialized = TRUE;
130 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
131 UINT uiWidth, UINT uiHeight)
133 BmpFrameEncode *This = (BmpFrameEncode*)iface;
134 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
136 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
138 This->width = uiWidth;
139 This->height = uiHeight;
144 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
145 double dpiX, double dpiY)
147 BmpFrameEncode *This = (BmpFrameEncode*)iface;
148 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
150 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
158 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
159 WICPixelFormatGUID *pPixelFormat)
161 BmpFrameEncode *This = (BmpFrameEncode*)iface;
163 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
165 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
167 for (i=0; formats[i].guid; i++)
169 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
173 if (!formats[i].guid) i = 0;
175 This->format = &formats[i];
176 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
181 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
182 UINT cCount, IWICColorContext **ppIColorContext)
184 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
188 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
189 IWICPalette *pIPalette)
191 FIXME("(%p,%p): stub\n", iface, pIPalette);
192 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
195 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
196 IWICBitmapSource *pIThumbnail)
198 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
199 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
202 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
206 if (!This->initialized || !This->width || !This->height || !This->format)
207 return WINCODEC_ERR_WRONGSTATE;
209 This->stride = (((This->width * This->format->bpp)+31)/32)*4;
210 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
211 if (!This->bits) return E_OUTOFMEMORY;
217 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
218 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
220 BmpFrameEncode *This = (BmpFrameEncode*)iface;
223 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
225 if (!This->initialized || !This->width || !This->height || !This->format)
226 return WINCODEC_ERR_WRONGSTATE;
228 hr = BmpFrameEncode_AllocateBits(This);
229 if (FAILED(hr)) return hr;
233 rc.Width = This->width;
234 rc.Height = lineCount;
236 hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
237 &rc, This->stride, This->stride*(This->height-This->lineswritten),
238 This->bits + This->stride*This->lineswritten);
241 This->lineswritten += lineCount;
246 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
247 IWICBitmapSource *pIBitmapSource, WICRect *prc)
249 BmpFrameEncode *This = (BmpFrameEncode*)iface;
252 WICPixelFormatGUID guid;
253 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
255 if (!This->initialized || !This->width || !This->height)
256 return WINCODEC_ERR_WRONGSTATE;
260 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
261 if (FAILED(hr)) return hr;
262 hr = BmpFrameEncode_SetPixelFormat(iface, &guid);
263 if (FAILED(hr)) return hr;
266 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
267 if (FAILED(hr)) return hr;
268 if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
270 /* should use WICConvertBitmapSource to convert, but that's unimplemented */
271 ERR("format %s unsupported\n", debugstr_guid(&guid));
275 if (This->xres == 0.0 || This->yres == 0.0)
278 hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
279 if (FAILED(hr)) return hr;
280 hr = BmpFrameEncode_SetResolution(iface, xres, yres);
281 if (FAILED(hr)) return hr;
287 hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
288 if (FAILED(hr)) return hr;
296 if (prc->Width != This->width) return E_INVALIDARG;
298 hr = BmpFrameEncode_AllocateBits(This);
299 if (FAILED(hr)) return hr;
301 hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, This->stride,
302 This->stride*(This->height-This->lineswritten),
303 This->bits + This->stride*This->lineswritten);
305 This->lineswritten += rc.Height;
310 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
312 BmpFrameEncode *This = (BmpFrameEncode*)iface;
313 BITMAPFILEHEADER bfh;
320 TRACE("(%p)\n", iface);
322 if (!This->bits || This->committed || This->height != This->lineswritten)
323 return WINCODEC_ERR_WRONGSTATE;
325 bfh.bfType = 0x4d42; /* "BM" */
329 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
330 bih.bV5Width = This->width;
331 bih.bV5Height = -This->height; /* top-down bitmap */
333 bih.bV5BitCount = This->format->bpp;
334 bih.bV5Compression = This->format->compression;
335 bih.bV5SizeImage = This->stride*This->height;
336 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
337 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
339 bih.bV5ClrImportant = 0;
341 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
342 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
345 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
346 if (FAILED(hr)) return hr;
348 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
349 if (FAILED(hr)) return hr;
350 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
352 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
353 if (FAILED(hr)) return hr;
354 if (byteswritten != info_size) return E_FAIL;
356 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
357 if (FAILED(hr)) return hr;
358 if (byteswritten != bih.bV5SizeImage) return E_FAIL;
360 This->committed = TRUE;
365 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
366 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
368 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
372 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
373 BmpFrameEncode_QueryInterface,
374 BmpFrameEncode_AddRef,
375 BmpFrameEncode_Release,
376 BmpFrameEncode_Initialize,
377 BmpFrameEncode_SetSize,
378 BmpFrameEncode_SetResolution,
379 BmpFrameEncode_SetPixelFormat,
380 BmpFrameEncode_SetColorContexts,
381 BmpFrameEncode_SetPalette,
382 BmpFrameEncode_SetThumbnail,
383 BmpFrameEncode_WritePixels,
384 BmpFrameEncode_WriteSource,
385 BmpFrameEncode_Commit,
386 BmpFrameEncode_GetMetadataQueryWriter
389 typedef struct BmpEncoder {
390 const IWICBitmapEncoderVtbl *lpVtbl;
393 IWICBitmapFrameEncode *frame;
396 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
399 BmpEncoder *This = (BmpEncoder*)iface;
400 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
402 if (!ppv) return E_INVALIDARG;
404 if (IsEqualIID(&IID_IUnknown, iid) ||
405 IsEqualIID(&IID_IWICBitmapEncoder, iid))
412 return E_NOINTERFACE;
415 IUnknown_AddRef((IUnknown*)*ppv);
419 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
421 BmpEncoder *This = (BmpEncoder*)iface;
422 ULONG ref = InterlockedIncrement(&This->ref);
424 TRACE("(%p) refcount=%u\n", iface, ref);
429 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
431 BmpEncoder *This = (BmpEncoder*)iface;
432 ULONG ref = InterlockedDecrement(&This->ref);
434 TRACE("(%p) refcount=%u\n", iface, ref);
438 if (This->stream) IStream_Release(This->stream);
439 if (This->frame) IWICBitmapFrameEncode_Release(This->frame);
440 HeapFree(GetProcessHeap(), 0, This);
446 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
447 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
449 BmpEncoder *This = (BmpEncoder*)iface;
451 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
453 IStream_AddRef(pIStream);
454 This->stream = pIStream;
459 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
460 GUID *pguidContainerFormat)
462 FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
466 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
467 IWICBitmapEncoderInfo **ppIEncoderInfo)
469 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
473 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
474 UINT cCount, IWICColorContext **ppIColorContext)
476 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
480 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
482 TRACE("(%p,%p)\n", iface, pIPalette);
483 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
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 = (BmpEncoder*)iface;
502 BmpFrameEncode *encode;
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(ppIEncoderOptions);
512 if (FAILED(hr)) return hr;
514 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
517 IPropertyBag2_Release(*ppIEncoderOptions);
518 *ppIEncoderOptions = NULL;
519 return E_OUTOFMEMORY;
521 encode->lpVtbl = &BmpFrameEncode_Vtbl;
523 IStream_AddRef(This->stream);
524 encode->stream = This->stream;
525 encode->initialized = FALSE;
529 encode->format = NULL;
532 encode->lineswritten = 0;
533 encode->committed = FALSE;
535 *ppIFrameEncode = (IWICBitmapFrameEncode*)encode;
536 This->frame = (IWICBitmapFrameEncode*)encode;
541 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
543 BmpEncoder *This = (BmpEncoder*)iface;
544 BmpFrameEncode *frame = (BmpFrameEncode*)This->frame;
545 TRACE("(%p)\n", iface);
547 if (!frame || !frame->committed) return WINCODEC_ERR_WRONGSTATE;
552 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
553 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
555 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
559 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
560 BmpEncoder_QueryInterface,
563 BmpEncoder_Initialize,
564 BmpEncoder_GetContainerFormat,
565 BmpEncoder_GetEncoderInfo,
566 BmpEncoder_SetColorContexts,
567 BmpEncoder_SetPalette,
568 BmpEncoder_SetThumbnail,
569 BmpEncoder_SetPreview,
570 BmpEncoder_CreateNewFrame,
572 BmpEncoder_GetMetadataQueryWriter
575 HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
580 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
584 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
586 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
587 if (!This) return E_OUTOFMEMORY;
589 This->lpVtbl = &BmpEncoder_Vtbl;
594 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
595 IUnknown_Release((IUnknown*)This);