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
);