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
31 #include "wincodecs_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
37 struct bmp_pixelformat
{
38 const WICPixelFormatGUID
*guid
;
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
},
53 /* Windows doesn't seem to support this one. */
54 {&GUID_WICPixelFormat32bppBGRA
, 32, BI_BITFIELDS
, 0xff0000, 0xff00, 0xff, 0xff000000},
59 typedef struct BmpFrameEncode
{
60 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
66 const struct bmp_pixelformat
*format
;
70 WICColor palette
[256];
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
,
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
;
101 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
124 if (This
->stream
) IStream_Release(This
->stream
);
125 HeapFree(GetProcessHeap(), 0, This
->bits
);
126 HeapFree(GetProcessHeap(), 0, This
);
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
;
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
;
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
;
176 static HRESULT WINAPI
BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
177 WICPixelFormatGUID
*pPixelFormat
)
179 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
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)
191 if (!formats
[i
].guid
) i
= 0;
193 This
->format
= &formats
[i
];
194 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
199 static HRESULT WINAPI
BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
200 UINT cCount
, IWICColorContext
**ppIColorContext
)
202 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
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
)
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
;
243 static HRESULT WINAPI
BmpFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
244 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
246 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
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
;
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
);
267 This
->lineswritten
+= lineCount
;
272 static HRESULT WINAPI
BmpFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
273 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
275 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
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
);
288 hr
= write_source(iface
, pIBitmapSource
, prc
,
289 This
->format
->guid
, This
->format
->bpp
, This
->width
, This
->height
);
295 static HRESULT WINAPI
BmpFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
297 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
298 BITMAPFILEHEADER bfh
;
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" */
314 bih
.bV5Size
= info_size
= sizeof(BITMAPINFOHEADER
);
315 bih
.bV5Width
= This
->width
;
316 bih
.bV5Height
= -This
->height
; /* top-down bitmap */
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;
324 bih
.bV5ClrImportant
= 0;
326 if (This
->format
->compression
== BI_BITFIELDS
)
328 if (This
->format
->alphamask
)
329 bih
.bV5Size
= info_size
= sizeof(BITMAPV4HEADER
);
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
;
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
;
363 static HRESULT WINAPI
BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
364 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
366 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
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
;
391 BmpFrameEncode
*frame
;
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
,
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
;
415 return E_NOINTERFACE
;
418 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
441 if (This
->stream
) IStream_Release(This
->stream
);
442 if (This
->frame
) IWICBitmapFrameEncode_Release(&This
->frame
->IWICBitmapFrameEncode_iface
);
443 HeapFree(GetProcessHeap(), 0, This
);
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
;
462 static HRESULT WINAPI
BmpEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
463 GUID
*pguidContainerFormat
)
465 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
469 static HRESULT WINAPI
BmpEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
470 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
472 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
476 static HRESULT WINAPI
BmpEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
477 UINT cCount
, IWICColorContext
**ppIColorContext
)
479 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
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
;
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
));
529 IPropertyBag2_Release(*ppIEncoderOptions
);
530 *ppIEncoderOptions
= NULL
;
531 return E_OUTOFMEMORY
;
533 encode
->IWICBitmapFrameEncode_iface
.lpVtbl
= &BmpFrameEncode_Vtbl
;
535 IStream_AddRef(This
->stream
);
536 encode
->stream
= This
->stream
;
537 encode
->initialized
= FALSE
;
541 encode
->format
= NULL
;
544 encode
->lineswritten
= 0;
546 encode
->committed
= FALSE
;
548 *ppIFrameEncode
= &encode
->IWICBitmapFrameEncode_iface
;
549 This
->frame
= encode
;
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
;
564 static HRESULT WINAPI
BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
565 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
567 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
571 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl
= {
572 BmpEncoder_QueryInterface
,
575 BmpEncoder_Initialize
,
576 BmpEncoder_GetContainerFormat
,
577 BmpEncoder_GetEncoderInfo
,
578 BmpEncoder_SetColorContexts
,
579 BmpEncoder_SetPalette
,
580 BmpEncoder_SetThumbnail
,
581 BmpEncoder_SetPreview
,
582 BmpEncoder_CreateNewFrame
,
584 BmpEncoder_GetMetadataQueryWriter
587 HRESULT
BmpEncoder_CreateInstance(REFIID iid
, void** ppv
)
592 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
596 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder
));
597 if (!This
) return E_OUTOFMEMORY
;
599 This
->IWICBitmapEncoder_iface
.lpVtbl
= &BmpEncoder_Vtbl
;
604 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
605 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);