2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2016 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wincodecs_private.h"
24 struct bmp_pixelformat
{
25 const WICPixelFormatGUID
*guid
;
27 UINT colors
; /* palette size */
35 static const struct bmp_pixelformat formats
[] = {
36 {&GUID_WICPixelFormat24bppBGR
, 24, 0, BI_RGB
},
37 {&GUID_WICPixelFormatBlackWhite
, 1, 2, BI_RGB
},
38 {&GUID_WICPixelFormat1bppIndexed
, 1, 2, BI_RGB
},
39 {&GUID_WICPixelFormat2bppIndexed
, 2, 4, BI_RGB
},
40 {&GUID_WICPixelFormat4bppIndexed
, 4, 16, BI_RGB
},
41 {&GUID_WICPixelFormat8bppIndexed
, 8, 256, BI_RGB
},
42 {&GUID_WICPixelFormat16bppBGR555
, 16, 0, BI_RGB
},
43 {&GUID_WICPixelFormat16bppBGR565
, 16, 0, BI_BITFIELDS
, 0xf800, 0x7e0, 0x1f, 0},
44 {&GUID_WICPixelFormat32bppBGR
, 32, 0, BI_RGB
},
46 /* Windows doesn't seem to support this one. */
47 {&GUID_WICPixelFormat32bppBGRA
, 32, 0, BI_BITFIELDS
, 0xff0000, 0xff00, 0xff, 0xff000000},
52 typedef struct BmpFrameEncode
{
53 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
59 const struct bmp_pixelformat
*format
;
63 WICColor palette
[256];
68 static inline BmpFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
70 return CONTAINING_RECORD(iface
, BmpFrameEncode
, IWICBitmapFrameEncode_iface
);
73 static HRESULT WINAPI
BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
76 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
77 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
79 if (!ppv
) return E_INVALIDARG
;
81 if (IsEqualIID(&IID_IUnknown
, iid
) ||
82 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
84 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
92 IUnknown_AddRef((IUnknown
*)*ppv
);
96 static ULONG WINAPI
BmpFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
98 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
99 ULONG ref
= InterlockedIncrement(&This
->ref
);
101 TRACE("(%p) refcount=%u\n", iface
, ref
);
106 static ULONG WINAPI
BmpFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
108 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
109 ULONG ref
= InterlockedDecrement(&This
->ref
);
111 TRACE("(%p) refcount=%u\n", iface
, ref
);
115 if (This
->stream
) IStream_Release(This
->stream
);
116 HeapFree(GetProcessHeap(), 0, This
->bits
);
117 HeapFree(GetProcessHeap(), 0, This
);
123 static HRESULT WINAPI
BmpFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
124 IPropertyBag2
*pIEncoderOptions
)
126 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
127 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
129 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
131 This
->initialized
= TRUE
;
136 static HRESULT WINAPI
BmpFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
137 UINT uiWidth
, UINT uiHeight
)
139 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
140 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
142 if (!This
->initialized
|| This
->bits
) return WINCODEC_ERR_WRONGSTATE
;
144 This
->width
= uiWidth
;
145 This
->height
= uiHeight
;
150 static HRESULT WINAPI
BmpFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
151 double dpiX
, double dpiY
)
153 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
154 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
156 if (!This
->initialized
|| This
->bits
) return WINCODEC_ERR_WRONGSTATE
;
164 static HRESULT WINAPI
BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
165 WICPixelFormatGUID
*pPixelFormat
)
167 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
169 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
171 if (!This
->initialized
|| This
->bits
) return WINCODEC_ERR_WRONGSTATE
;
173 for (i
=0; formats
[i
].guid
; i
++)
175 if (IsEqualGUID(formats
[i
].guid
, pPixelFormat
))
179 if (!formats
[i
].guid
) i
= 0;
180 else if (IsEqualGUID(pPixelFormat
, &GUID_WICPixelFormatBlackWhite
))
181 i
= 2; /* GUID_WICPixelFormat1bppIndexed */
183 This
->format
= &formats
[i
];
184 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
189 static HRESULT WINAPI
BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
190 UINT cCount
, IWICColorContext
**ppIColorContext
)
192 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
196 static HRESULT WINAPI
BmpFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
197 IWICPalette
*palette
)
199 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
202 TRACE("(%p,%p)\n", iface
, palette
);
204 if (!palette
) return E_INVALIDARG
;
206 if (!This
->initialized
)
207 return WINCODEC_ERR_NOTINITIALIZED
;
209 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
213 for (i
= 0; i
< This
->colors
; i
++)
214 This
->palette
[i
] |= 0xff000000; /* BMP palette has no alpha */
219 static HRESULT WINAPI
BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
220 IWICBitmapSource
*pIThumbnail
)
222 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
223 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
226 static HRESULT
BmpFrameEncode_AllocateBits(BmpFrameEncode
*This
)
230 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
231 return WINCODEC_ERR_WRONGSTATE
;
233 This
->stride
= (((This
->width
* This
->format
->bpp
)+31)/32)*4;
234 This
->bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->stride
* This
->height
);
235 if (!This
->bits
) return E_OUTOFMEMORY
;
241 static HRESULT WINAPI
BmpFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
242 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
244 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
247 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
249 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
250 return WINCODEC_ERR_WRONGSTATE
;
252 hr
= BmpFrameEncode_AllocateBits(This
);
253 if (FAILED(hr
)) return hr
;
257 rc
.Width
= This
->width
;
258 rc
.Height
= lineCount
;
260 hr
= copy_pixels(This
->format
->bpp
, pbPixels
, This
->width
, lineCount
, cbStride
,
261 &rc
, This
->stride
, This
->stride
*(This
->height
-This
->lineswritten
),
262 This
->bits
+ This
->stride
*This
->lineswritten
);
265 This
->lineswritten
+= lineCount
;
270 static HRESULT WINAPI
BmpFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
271 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
273 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
275 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
277 if (!This
->initialized
)
278 return WINCODEC_ERR_WRONGSTATE
;
280 hr
= configure_write_source(iface
, pIBitmapSource
, prc
,
281 This
->format
? This
->format
->guid
: NULL
, This
->width
, This
->height
,
282 This
->xres
, This
->yres
);
286 hr
= write_source(iface
, pIBitmapSource
, prc
,
287 This
->format
->guid
, This
->format
->bpp
, This
->width
, This
->height
);
293 static HRESULT WINAPI
BmpFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
295 BmpFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
296 BITMAPFILEHEADER bfh
;
304 TRACE("(%p)\n", iface
);
306 if (!This
->bits
|| This
->committed
|| This
->height
!= This
->lineswritten
)
307 return WINCODEC_ERR_WRONGSTATE
;
309 bfh
.bfType
= 0x4d42; /* "BM" */
313 bih
.bV5Size
= info_size
= sizeof(BITMAPINFOHEADER
);
314 bih
.bV5Width
= This
->width
;
315 bih
.bV5Height
= This
->height
; /* bottom-top bitmap */
317 bih
.bV5BitCount
= This
->format
->bpp
;
318 bih
.bV5Compression
= This
->format
->compression
;
319 bih
.bV5SizeImage
= This
->stride
*This
->height
;
320 bih
.bV5XPelsPerMeter
= (This
->xres
+0.0127) / 0.0254;
321 bih
.bV5YPelsPerMeter
= (This
->yres
+0.0127) / 0.0254;
322 bih
.bV5ClrUsed
= (This
->format
->bpp
<= 8) ? This
->colors
: 0;
323 bih
.bV5ClrImportant
= bih
.bV5ClrUsed
;
325 if (This
->format
->compression
== BI_BITFIELDS
)
327 if (This
->format
->alphamask
)
328 bih
.bV5Size
= info_size
= sizeof(BITMAPV4HEADER
);
330 info_size
= sizeof(BITMAPINFOHEADER
)+12;
331 bih
.bV5RedMask
= This
->format
->redmask
;
332 bih
.bV5GreenMask
= This
->format
->greenmask
;
333 bih
.bV5BlueMask
= This
->format
->bluemask
;
334 bih
.bV5AlphaMask
= This
->format
->alphamask
;
335 bih
.bV5CSType
= LCS_DEVICE_RGB
;
338 bfh
.bfSize
= sizeof(BITMAPFILEHEADER
) + info_size
+ bih
.bV5SizeImage
;
339 bfh
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + info_size
;
340 bfh
.bfOffBits
+= bih
.bV5ClrUsed
* sizeof(WICColor
);
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 /* write the palette */
355 if (This
->format
->colors
)
357 hr
= IStream_Write(This
->stream
, This
->palette
, This
->colors
* sizeof(WICColor
), &byteswritten
);
358 if (FAILED(hr
)) return hr
;
359 if (byteswritten
!= This
->colors
* sizeof(WICColor
)) return E_FAIL
;
362 /* write the image bits as a bottom-top array */
363 bits
= This
->bits
+ bih
.bV5SizeImage
;
364 for (i
= 0; i
< This
->height
; i
++)
366 bits
-= This
->stride
;
367 hr
= IStream_Write(This
->stream
, bits
, This
->stride
, &byteswritten
);
368 if (FAILED(hr
)) return hr
;
369 if (byteswritten
!= This
->stride
) return E_FAIL
;
372 This
->committed
= TRUE
;
377 static HRESULT WINAPI
BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
378 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
380 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
384 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl
= {
385 BmpFrameEncode_QueryInterface
,
386 BmpFrameEncode_AddRef
,
387 BmpFrameEncode_Release
,
388 BmpFrameEncode_Initialize
,
389 BmpFrameEncode_SetSize
,
390 BmpFrameEncode_SetResolution
,
391 BmpFrameEncode_SetPixelFormat
,
392 BmpFrameEncode_SetColorContexts
,
393 BmpFrameEncode_SetPalette
,
394 BmpFrameEncode_SetThumbnail
,
395 BmpFrameEncode_WritePixels
,
396 BmpFrameEncode_WriteSource
,
397 BmpFrameEncode_Commit
,
398 BmpFrameEncode_GetMetadataQueryWriter
401 typedef struct BmpEncoder
{
402 IWICBitmapEncoder IWICBitmapEncoder_iface
;
405 BmpFrameEncode
*frame
;
408 static inline BmpEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
410 return CONTAINING_RECORD(iface
, BmpEncoder
, IWICBitmapEncoder_iface
);
413 static HRESULT WINAPI
BmpEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
416 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
417 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
419 if (!ppv
) return E_INVALIDARG
;
421 if (IsEqualIID(&IID_IUnknown
, iid
) ||
422 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
424 *ppv
= &This
->IWICBitmapEncoder_iface
;
429 return E_NOINTERFACE
;
432 IUnknown_AddRef((IUnknown
*)*ppv
);
436 static ULONG WINAPI
BmpEncoder_AddRef(IWICBitmapEncoder
*iface
)
438 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
439 ULONG ref
= InterlockedIncrement(&This
->ref
);
441 TRACE("(%p) refcount=%u\n", iface
, ref
);
446 static ULONG WINAPI
BmpEncoder_Release(IWICBitmapEncoder
*iface
)
448 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
449 ULONG ref
= InterlockedDecrement(&This
->ref
);
451 TRACE("(%p) refcount=%u\n", iface
, ref
);
455 if (This
->stream
) IStream_Release(This
->stream
);
456 if (This
->frame
) IWICBitmapFrameEncode_Release(&This
->frame
->IWICBitmapFrameEncode_iface
);
457 HeapFree(GetProcessHeap(), 0, This
);
463 static HRESULT WINAPI
BmpEncoder_Initialize(IWICBitmapEncoder
*iface
,
464 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
466 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
468 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
470 IStream_AddRef(pIStream
);
471 This
->stream
= pIStream
;
476 static HRESULT WINAPI
BmpEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
477 GUID
*pguidContainerFormat
)
479 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
483 static HRESULT WINAPI
BmpEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
, IWICBitmapEncoderInfo
**info
)
485 IWICComponentInfo
*comp_info
;
488 TRACE("%p,%p\n", iface
, info
);
490 if (!info
) return E_INVALIDARG
;
492 hr
= CreateComponentInfo(&CLSID_WICBmpEncoder
, &comp_info
);
495 hr
= IWICComponentInfo_QueryInterface(comp_info
, &IID_IWICBitmapEncoderInfo
, (void **)info
);
496 IWICComponentInfo_Release(comp_info
);
501 static HRESULT WINAPI
BmpEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
502 UINT cCount
, IWICColorContext
**ppIColorContext
)
504 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
508 static HRESULT WINAPI
BmpEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*palette
)
510 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
512 TRACE("(%p,%p)\n", iface
, palette
);
513 return This
->stream
? WINCODEC_ERR_UNSUPPORTEDOPERATION
: WINCODEC_ERR_NOTINITIALIZED
;
516 static HRESULT WINAPI
BmpEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
518 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
519 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
522 static HRESULT WINAPI
BmpEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
524 TRACE("(%p,%p)\n", iface
, pIPreview
);
525 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
528 static HRESULT WINAPI
BmpEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
529 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
531 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
532 BmpFrameEncode
*encode
;
535 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
537 if (This
->frame
) return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
539 if (!This
->stream
) return WINCODEC_ERR_NOTINITIALIZED
;
541 hr
= CreatePropertyBag2(NULL
, 0, ppIEncoderOptions
);
542 if (FAILED(hr
)) return hr
;
544 encode
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode
));
547 IPropertyBag2_Release(*ppIEncoderOptions
);
548 *ppIEncoderOptions
= NULL
;
549 return E_OUTOFMEMORY
;
551 encode
->IWICBitmapFrameEncode_iface
.lpVtbl
= &BmpFrameEncode_Vtbl
;
553 IStream_AddRef(This
->stream
);
554 encode
->stream
= This
->stream
;
555 encode
->initialized
= FALSE
;
559 encode
->format
= NULL
;
562 encode
->lineswritten
= 0;
564 encode
->committed
= FALSE
;
566 *ppIFrameEncode
= &encode
->IWICBitmapFrameEncode_iface
;
567 This
->frame
= encode
;
572 static HRESULT WINAPI
BmpEncoder_Commit(IWICBitmapEncoder
*iface
)
574 BmpEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
575 TRACE("(%p)\n", iface
);
577 if (!This
->frame
|| !This
->frame
->committed
) return WINCODEC_ERR_WRONGSTATE
;
582 static HRESULT WINAPI
BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
583 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
585 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
589 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl
= {
590 BmpEncoder_QueryInterface
,
593 BmpEncoder_Initialize
,
594 BmpEncoder_GetContainerFormat
,
595 BmpEncoder_GetEncoderInfo
,
596 BmpEncoder_SetColorContexts
,
597 BmpEncoder_SetPalette
,
598 BmpEncoder_SetThumbnail
,
599 BmpEncoder_SetPreview
,
600 BmpEncoder_CreateNewFrame
,
602 BmpEncoder_GetMetadataQueryWriter
605 HRESULT
BmpEncoder_CreateInstance(REFIID iid
, void** ppv
)
610 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
614 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder
));
615 if (!This
) return E_OUTOFMEMORY
;
617 This
->IWICBitmapEncoder_iface
.lpVtbl
= &BmpEncoder_Vtbl
;
622 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
623 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);