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 #define WIN32_NO_STATUS
21 #define COM_NO_WINDOWS_H
36 #include "wincodecs_private.h"
38 #include <wine/debug.h>
40 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
42 struct bmp_pixelformat
{
43 const WICPixelFormatGUID
*guid
;
52 static const struct bmp_pixelformat formats
[] = {
53 {&GUID_WICPixelFormat24bppBGR
, 24, BI_RGB
},
54 {&GUID_WICPixelFormat16bppBGR555
, 16, BI_RGB
},
55 {&GUID_WICPixelFormat16bppBGR565
, 16, BI_BITFIELDS
, 0xf800, 0x7e0, 0x1f, 0},
56 {&GUID_WICPixelFormat32bppBGR
, 32, BI_RGB
},
58 /* Windows doesn't seem to support this one. */
59 {&GUID_WICPixelFormat32bppBGRA
, 32, BI_BITFIELDS
, 0xff0000, 0xff00, 0xff, 0xff000000},
64 typedef struct BmpFrameEncode
{
65 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
71 const struct bmp_pixelformat
*format
;
78 static inline BmpFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
80 return CONTAINING_RECORD(iface
, BmpFrameEncode
, IWICBitmapFrameEncode_iface
);
83 static HRESULT WINAPI
BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
86 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
87 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
89 if (!ppv
) return E_INVALIDARG
;
91 if (IsEqualIID(&IID_IUnknown
, iid
) ||
92 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
94 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
102 IUnknown_AddRef((IUnknown
*)*ppv
);
106 static ULONG WINAPI
BmpFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
108 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
109 ULONG ref
= InterlockedIncrement(&This
->ref
);
111 TRACE("(%p) refcount=%u\n", iface
, ref
);
116 static ULONG WINAPI
BmpFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
118 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
119 ULONG ref
= InterlockedDecrement(&This
->ref
);
121 TRACE("(%p) refcount=%u\n", iface
, ref
);
125 if (This
->stream
) IStream_Release(This
->stream
);
126 HeapFree(GetProcessHeap(), 0, This
->bits
);
127 HeapFree(GetProcessHeap(), 0, This
);
133 static HRESULT WINAPI
BmpFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
134 IPropertyBag2
*pIEncoderOptions
)
136 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
137 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
139 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
141 This
->initialized
= TRUE
;
146 static HRESULT WINAPI
BmpFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
147 UINT uiWidth
, UINT uiHeight
)
149 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
150 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
152 if (!This
->initialized
|| This
->bits
) return WINCODEC_ERR_WRONGSTATE
;
154 This
->width
= uiWidth
;
155 This
->height
= uiHeight
;
160 static HRESULT WINAPI
BmpFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
161 double dpiX
, double dpiY
)
163 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
164 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
166 if (!This
->initialized
|| This
->bits
) return WINCODEC_ERR_WRONGSTATE
;
174 static HRESULT WINAPI
BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
175 WICPixelFormatGUID
*pPixelFormat
)
177 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
179 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
181 if (!This
->initialized
|| This
->bits
) return WINCODEC_ERR_WRONGSTATE
;
183 for (i
=0; formats
[i
].guid
; i
++)
185 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
189 if (!formats
[i
].guid
) i
= 0;
191 This
->format
= &formats
[i
];
192 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
197 static HRESULT WINAPI
BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
198 UINT cCount
, IWICColorContext
**ppIColorContext
)
200 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
204 static HRESULT WINAPI
BmpFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
205 IWICPalette
*pIPalette
)
207 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
208 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
211 static HRESULT WINAPI
BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
212 IWICBitmapSource
*pIThumbnail
)
214 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
215 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
218 static HRESULT
BmpFrameEncode_AllocateBits(BmpFrameEncode
*This
)
222 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
223 return WINCODEC_ERR_WRONGSTATE
;
225 This
->stride
= (((This
->width
* This
->format
->bpp
)+31)/32)*4;
226 This
->bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->stride
* This
->height
);
227 if (!This
->bits
) return E_OUTOFMEMORY
;
233 static HRESULT WINAPI
BmpFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
234 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
236 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
239 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
241 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
242 return WINCODEC_ERR_WRONGSTATE
;
244 hr
= BmpFrameEncode_AllocateBits(This
);
245 if (FAILED(hr
)) return hr
;
249 rc
.Width
= This
->width
;
250 rc
.Height
= lineCount
;
252 hr
= copy_pixels(This
->format
->bpp
, pbPixels
, This
->width
, lineCount
, cbStride
,
253 &rc
, This
->stride
, This
->stride
*(This
->height
-This
->lineswritten
),
254 This
->bits
+ This
->stride
*This
->lineswritten
);
257 This
->lineswritten
+= lineCount
;
262 static HRESULT WINAPI
BmpFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
263 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
265 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
268 WICPixelFormatGUID guid
;
269 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
271 if (!This
->initialized
|| !This
->width
|| !This
->height
)
272 return WINCODEC_ERR_WRONGSTATE
;
276 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
277 if (FAILED(hr
)) return hr
;
278 hr
= BmpFrameEncode_SetPixelFormat(iface
, &guid
);
279 if (FAILED(hr
)) return hr
;
282 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
283 if (FAILED(hr
)) return hr
;
284 if (memcmp(&guid
, This
->format
->guid
, sizeof(GUID
)) != 0)
286 /* should use WICConvertBitmapSource to convert, but that's unimplemented */
287 ERR("format %s unsupported\n", debugstr_guid(&guid
));
291 if (This
->xres
== 0.0 || This
->yres
== 0.0)
294 hr
= IWICBitmapSource_GetResolution(pIBitmapSource
, &xres
, &yres
);
295 if (FAILED(hr
)) return hr
;
296 hr
= BmpFrameEncode_SetResolution(iface
, xres
, yres
);
297 if (FAILED(hr
)) return hr
;
303 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
304 if (FAILED(hr
)) return hr
;
312 if (prc
->Width
!= This
->width
) return E_INVALIDARG
;
314 hr
= BmpFrameEncode_AllocateBits(This
);
315 if (FAILED(hr
)) return hr
;
317 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, This
->stride
,
318 This
->stride
*(This
->height
-This
->lineswritten
),
319 This
->bits
+ This
->stride
*This
->lineswritten
);
321 This
->lineswritten
+= prc
->Height
;
326 static HRESULT WINAPI
BmpFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
328 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
329 BITMAPFILEHEADER bfh
;
336 TRACE("(%p)\n", iface
);
338 if (!This
->bits
|| This
->committed
|| This
->height
!= This
->lineswritten
)
339 return WINCODEC_ERR_WRONGSTATE
;
341 bfh
.bfType
= 0x4d42; /* "BM" */
345 bih
.bV5Size
= info_size
= sizeof(BITMAPINFOHEADER
);
346 bih
.bV5Width
= This
->width
;
347 bih
.bV5Height
= -This
->height
; /* top-down bitmap */
349 bih
.bV5BitCount
= This
->format
->bpp
;
350 bih
.bV5Compression
= This
->format
->compression
;
351 bih
.bV5SizeImage
= This
->stride
*This
->height
;
352 bih
.bV5XPelsPerMeter
= (This
->xres
+0.0127) / 0.0254;
353 bih
.bV5YPelsPerMeter
= (This
->yres
+0.0127) / 0.0254;
355 bih
.bV5ClrImportant
= 0;
357 if (This
->format
->compression
== BI_BITFIELDS
)
359 if (This
->format
->alphamask
)
360 bih
.bV5Size
= info_size
= sizeof(BITMAPV4HEADER
);
362 info_size
= sizeof(BITMAPINFOHEADER
)+12;
363 bih
.bV5RedMask
= This
->format
->redmask
;
364 bih
.bV5GreenMask
= This
->format
->greenmask
;
365 bih
.bV5BlueMask
= This
->format
->bluemask
;
366 bih
.bV5AlphaMask
= This
->format
->alphamask
;
367 bih
.bV5AlphaMask
= LCS_DEVICE_RGB
;
370 bfh
.bfSize
= sizeof(BITMAPFILEHEADER
) + info_size
+ bih
.bV5SizeImage
;
371 bfh
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + info_size
;
374 hr
= IStream_Seek(This
->stream
, pos
, STREAM_SEEK_SET
, NULL
);
375 if (FAILED(hr
)) return hr
;
377 hr
= IStream_Write(This
->stream
, &bfh
, sizeof(BITMAPFILEHEADER
), &byteswritten
);
378 if (FAILED(hr
)) return hr
;
379 if (byteswritten
!= sizeof(BITMAPFILEHEADER
)) return E_FAIL
;
381 hr
= IStream_Write(This
->stream
, &bih
, info_size
, &byteswritten
);
382 if (FAILED(hr
)) return hr
;
383 if (byteswritten
!= info_size
) return E_FAIL
;
385 hr
= IStream_Write(This
->stream
, This
->bits
, bih
.bV5SizeImage
, &byteswritten
);
386 if (FAILED(hr
)) return hr
;
387 if (byteswritten
!= bih
.bV5SizeImage
) return E_FAIL
;
389 This
->committed
= TRUE
;
394 static HRESULT WINAPI
BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
395 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
397 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
401 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl
= {
402 BmpFrameEncode_QueryInterface
,
403 BmpFrameEncode_AddRef
,
404 BmpFrameEncode_Release
,
405 BmpFrameEncode_Initialize
,
406 BmpFrameEncode_SetSize
,
407 BmpFrameEncode_SetResolution
,
408 BmpFrameEncode_SetPixelFormat
,
409 BmpFrameEncode_SetColorContexts
,
410 BmpFrameEncode_SetPalette
,
411 BmpFrameEncode_SetThumbnail
,
412 BmpFrameEncode_WritePixels
,
413 BmpFrameEncode_WriteSource
,
414 BmpFrameEncode_Commit
,
415 BmpFrameEncode_GetMetadataQueryWriter
418 typedef struct BmpEncoder
{
419 IWICBitmapEncoder IWICBitmapEncoder_iface
;
422 BmpFrameEncode
*frame
;
425 static inline BmpEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
427 return CONTAINING_RECORD(iface
, BmpEncoder
, IWICBitmapEncoder_iface
);
430 static HRESULT WINAPI
BmpEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
433 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
434 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
436 if (!ppv
) return E_INVALIDARG
;
438 if (IsEqualIID(&IID_IUnknown
, iid
) ||
439 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
441 *ppv
= &This
->IWICBitmapEncoder_iface
;
446 return E_NOINTERFACE
;
449 IUnknown_AddRef((IUnknown
*)*ppv
);
453 static ULONG WINAPI
BmpEncoder_AddRef(IWICBitmapEncoder
*iface
)
455 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
456 ULONG ref
= InterlockedIncrement(&This
->ref
);
458 TRACE("(%p) refcount=%u\n", iface
, ref
);
463 static ULONG WINAPI
BmpEncoder_Release(IWICBitmapEncoder
*iface
)
465 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
466 ULONG ref
= InterlockedDecrement(&This
->ref
);
468 TRACE("(%p) refcount=%u\n", iface
, ref
);
472 if (This
->stream
) IStream_Release(This
->stream
);
473 if (This
->frame
) IWICBitmapFrameEncode_Release(&This
->frame
->IWICBitmapFrameEncode_iface
);
474 HeapFree(GetProcessHeap(), 0, This
);
480 static HRESULT WINAPI
BmpEncoder_Initialize(IWICBitmapEncoder
*iface
,
481 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
483 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
485 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
487 IStream_AddRef(pIStream
);
488 This
->stream
= pIStream
;
493 static HRESULT WINAPI
BmpEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
494 GUID
*pguidContainerFormat
)
496 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
500 static HRESULT WINAPI
BmpEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
501 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
503 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
507 static HRESULT WINAPI
BmpEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
508 UINT cCount
, IWICColorContext
**ppIColorContext
)
510 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
514 static HRESULT WINAPI
BmpEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
516 TRACE("(%p,%p)\n", iface
, pIPalette
);
517 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
520 static HRESULT WINAPI
BmpEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
522 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
523 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
526 static HRESULT WINAPI
BmpEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
528 TRACE("(%p,%p)\n", iface
, pIPreview
);
529 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
532 static HRESULT WINAPI
BmpEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
533 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
535 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
536 BmpFrameEncode
*encode
;
539 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
541 if (This
->frame
) return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
543 if (!This
->stream
) return WINCODEC_ERR_NOTINITIALIZED
;
545 hr
= CreatePropertyBag2(NULL
, 0, ppIEncoderOptions
);
546 if (FAILED(hr
)) return hr
;
548 encode
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode
));
551 IPropertyBag2_Release(*ppIEncoderOptions
);
552 *ppIEncoderOptions
= NULL
;
553 return E_OUTOFMEMORY
;
555 encode
->IWICBitmapFrameEncode_iface
.lpVtbl
= &BmpFrameEncode_Vtbl
;
557 IStream_AddRef(This
->stream
);
558 encode
->stream
= This
->stream
;
559 encode
->initialized
= FALSE
;
563 encode
->format
= NULL
;
566 encode
->lineswritten
= 0;
567 encode
->committed
= FALSE
;
569 *ppIFrameEncode
= &encode
->IWICBitmapFrameEncode_iface
;
570 This
->frame
= encode
;
575 static HRESULT WINAPI
BmpEncoder_Commit(IWICBitmapEncoder
*iface
)
577 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
578 TRACE("(%p)\n", iface
);
580 if (!This
->frame
|| !This
->frame
->committed
) return WINCODEC_ERR_WRONGSTATE
;
585 static HRESULT WINAPI
BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
586 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
588 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
592 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl
= {
593 BmpEncoder_QueryInterface
,
596 BmpEncoder_Initialize
,
597 BmpEncoder_GetContainerFormat
,
598 BmpEncoder_GetEncoderInfo
,
599 BmpEncoder_SetColorContexts
,
600 BmpEncoder_SetPalette
,
601 BmpEncoder_SetThumbnail
,
602 BmpEncoder_SetPreview
,
603 BmpEncoder_CreateNewFrame
,
605 BmpEncoder_GetMetadataQueryWriter
608 HRESULT
BmpEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
613 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
617 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
619 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder
));
620 if (!This
) return E_OUTOFMEMORY
;
622 This
->IWICBitmapEncoder_iface
.lpVtbl
= &BmpEncoder_Vtbl
;
627 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
628 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);