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
);
60 const IWICBitmapDecoderVtbl
*lpVtbl
;
65 CRITICAL_SECTION lock
; /* must be held when accessing stream */
69 const IWICBitmapFrameDecodeVtbl
*lpVtbl
;
75 static HRESULT WINAPI
IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
78 IcoFrameDecode
*This
= (IcoFrameDecode
*)iface
;
79 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
81 if (!ppv
) return E_INVALIDARG
;
83 if (IsEqualIID(&IID_IUnknown
, iid
) ||
84 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
85 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
95 IUnknown_AddRef((IUnknown
*)*ppv
);
99 static ULONG WINAPI
IcoFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
101 IcoFrameDecode
*This
= (IcoFrameDecode
*)iface
;
102 ULONG ref
= InterlockedIncrement(&This
->ref
);
104 TRACE("(%p) refcount=%u\n", iface
, ref
);
109 static ULONG WINAPI
IcoFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
111 IcoFrameDecode
*This
= (IcoFrameDecode
*)iface
;
112 ULONG ref
= InterlockedDecrement(&This
->ref
);
114 TRACE("(%p) refcount=%u\n", iface
, ref
);
118 HeapFree(GetProcessHeap(), 0, This
->bits
);
119 HeapFree(GetProcessHeap(), 0, This
);
125 static HRESULT WINAPI
IcoFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
126 UINT
*puiWidth
, UINT
*puiHeight
)
128 IcoFrameDecode
*This
= (IcoFrameDecode
*)iface
;
130 *puiWidth
= This
->width
;
131 *puiHeight
= This
->height
;
133 TRACE("(%p) -> (%i,%i)\n", iface
, *puiWidth
, *puiHeight
);
138 static HRESULT WINAPI
IcoFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
139 WICPixelFormatGUID
*pPixelFormat
)
141 memcpy(pPixelFormat
, &GUID_WICPixelFormat32bppBGRA
, sizeof(GUID
));
145 static HRESULT WINAPI
IcoFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
146 double *pDpiX
, double *pDpiY
)
148 FIXME("(%p,%p,%p): stub\n", iface
, pDpiX
, pDpiY
);
152 static HRESULT WINAPI
IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
153 IWICPalette
*pIPalette
)
155 TRACE("(%p,%p)\n", iface
, pIPalette
);
156 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
159 static HRESULT WINAPI
IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
160 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
162 IcoFrameDecode
*This
= (IcoFrameDecode
*)iface
;
163 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
165 return copy_pixels(32, This
->bits
, This
->width
, This
->height
, This
->width
* 4,
166 prc
, cbStride
, cbBufferSize
, pbBuffer
);
169 static HRESULT WINAPI
IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
170 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
172 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
173 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
176 static HRESULT WINAPI
IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
177 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
179 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
180 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
183 static HRESULT WINAPI
IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
184 IWICBitmapSource
**ppIThumbnail
)
186 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
187 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
190 static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl
= {
191 IcoFrameDecode_QueryInterface
,
192 IcoFrameDecode_AddRef
,
193 IcoFrameDecode_Release
,
194 IcoFrameDecode_GetSize
,
195 IcoFrameDecode_GetPixelFormat
,
196 IcoFrameDecode_GetResolution
,
197 IcoFrameDecode_CopyPalette
,
198 IcoFrameDecode_CopyPixels
,
199 IcoFrameDecode_GetMetadataQueryReader
,
200 IcoFrameDecode_GetColorContexts
,
201 IcoFrameDecode_GetThumbnail
204 static inline void pixel_set_trans(DWORD
* pixel
, BOOL transparent
)
206 if (transparent
) *pixel
= 0;
207 else *pixel
|= 0xff000000;
210 static HRESULT
ReadIcoDib(IStream
*stream
, IcoFrameDecode
*result
)
213 IWICBitmapDecoder
*decoder
;
214 IWICBitmapFrameDecode
*framedecode
;
215 WICPixelFormatGUID pixelformat
;
216 IWICBitmapSource
*source
;
217 int has_alpha
=FALSE
; /* if TRUE, alpha data might be in the image data */
220 hr
= IcoDibDecoder_CreateInstance(NULL
, &IID_IWICBitmapDecoder
, (void**)&decoder
);
223 hr
= IWICBitmapDecoder_Initialize(decoder
, stream
, WICDecodeMetadataCacheOnLoad
);
226 hr
= IWICBitmapDecoder_GetFrame(decoder
, 0, &framedecode
);
230 hr
= IWICBitmapFrameDecode_GetSize(framedecode
, &result
->width
, &result
->height
);
234 result
->bits
= HeapAlloc(GetProcessHeap(), 0, result
->width
* result
->height
* 4);
235 if (!result
->bits
) hr
= E_OUTOFMEMORY
;
239 hr
= IWICBitmapFrameDecode_GetPixelFormat(framedecode
, &pixelformat
);
241 if (IsEqualGUID(&pixelformat
, &GUID_WICPixelFormat32bppBGR
) ||
242 IsEqualGUID(&pixelformat
, &GUID_WICPixelFormat32bppBGRA
))
244 source
= (IWICBitmapSource
*)framedecode
;
245 IWICBitmapSource_AddRef(source
);
250 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA
,
251 (IWICBitmapSource
*)framedecode
, &source
);
259 rc
.Width
= result
->width
;
260 rc
.Height
= result
->height
;
261 hr
= IWICBitmapSource_CopyPixels(source
, &rc
, result
->width
* 4,
262 result
->width
* result
->height
* 4, result
->bits
);
264 IWICBitmapSource_Release(source
);
267 IWICBitmapFrameDecode_Release(framedecode
);
270 if (SUCCEEDED(hr
) && !has_alpha
)
272 /* set alpha data based on the AND mask */
273 UINT andBytesPerRow
= (result
->width
+31)/32*4;
274 UINT andBytes
= andBytesPerRow
* result
->height
;
279 UINT bitsStride
= result
->width
* 4;
286 BmpDecoder_FindIconMask(decoder
, &offset
, &topdown
);
290 seek
.QuadPart
= offset
;
292 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, 0);
296 tempdata
= HeapAlloc(GetProcessHeap(), 0, andBytes
);
297 if (!tempdata
) hr
= E_OUTOFMEMORY
;
301 hr
= IStream_Read(stream
, tempdata
, andBytes
, &bytesread
);
303 if (SUCCEEDED(hr
) && bytesread
== andBytes
)
307 andStride
= andBytesPerRow
;
312 andStride
= -andBytesPerRow
;
313 andRow
= tempdata
+ (result
->height
-1)*andBytesPerRow
;
316 bitsRow
= result
->bits
;
317 for (y
=0; y
<result
->height
; y
++) {
318 BYTE
*andByte
=andRow
;
319 DWORD
*bitsPixel
=(DWORD
*)bitsRow
;
320 for (x
=0; x
<result
->width
; x
+=8) {
321 BYTE andVal
=*andByte
++;
322 pixel_set_trans(bitsPixel
++, andVal
>>7&1);
323 if (x
+1 < result
->width
) pixel_set_trans(bitsPixel
++, andVal
>>6&1);
324 if (x
+2 < result
->width
) pixel_set_trans(bitsPixel
++, andVal
>>5&1);
325 if (x
+3 < result
->width
) pixel_set_trans(bitsPixel
++, andVal
>>4&1);
326 if (x
+4 < result
->width
) pixel_set_trans(bitsPixel
++, andVal
>>3&1);
327 if (x
+5 < result
->width
) pixel_set_trans(bitsPixel
++, andVal
>>2&1);
328 if (x
+6 < result
->width
) pixel_set_trans(bitsPixel
++, andVal
>>1&1);
329 if (x
+7 < result
->width
) pixel_set_trans(bitsPixel
++, andVal
&1);
332 bitsRow
+= bitsStride
;
336 HeapFree(GetProcessHeap(), 0, tempdata
);
340 IWICBitmapDecoder_Release(decoder
);
346 static HRESULT
ReadIcoPng(IStream
*stream
, IcoFrameDecode
*result
)
348 IWICBitmapDecoder
*decoder
= NULL
;
349 IWICBitmapFrameDecode
*sourceFrame
= NULL
;
350 IWICBitmapSource
*sourceBitmap
= NULL
;
354 hr
= PngDecoder_CreateInstance(NULL
, &IID_IWICBitmapDecoder
, (void**)&decoder
);
357 hr
= IWICBitmapDecoder_Initialize(decoder
, stream
, WICDecodeMetadataCacheOnLoad
);
360 hr
= IWICBitmapDecoder_GetFrame(decoder
, 0, &sourceFrame
);
363 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA
, (IWICBitmapSource
*)sourceFrame
, &sourceBitmap
);
366 hr
= IWICBitmapFrameDecode_GetSize(sourceFrame
, &result
->width
, &result
->height
);
369 result
->bits
= HeapAlloc(GetProcessHeap(), 0, 4 * result
->width
* result
->height
);
370 if (result
->bits
== NULL
)
377 rect
.Width
= result
->width
;
378 rect
.Height
= result
->height
;
379 hr
= IWICBitmapSource_CopyPixels(sourceBitmap
, &rect
, 4*result
->width
,
380 4*result
->width
*result
->height
, result
->bits
);
384 IWICBitmapDecoder_Release(decoder
);
385 if (sourceFrame
!= NULL
)
386 IWICBitmapFrameDecode_Release(sourceFrame
);
387 if (sourceBitmap
!= NULL
)
388 IWICBitmapSource_Release(sourceBitmap
);
392 static HRESULT WINAPI
IcoDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
395 IcoDecoder
*This
= (IcoDecoder
*)iface
;
396 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
398 if (!ppv
) return E_INVALIDARG
;
400 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
407 return E_NOINTERFACE
;
410 IUnknown_AddRef((IUnknown
*)*ppv
);
414 static ULONG WINAPI
IcoDecoder_AddRef(IWICBitmapDecoder
*iface
)
416 IcoDecoder
*This
= (IcoDecoder
*)iface
;
417 ULONG ref
= InterlockedIncrement(&This
->ref
);
419 TRACE("(%p) refcount=%u\n", iface
, ref
);
424 static ULONG WINAPI
IcoDecoder_Release(IWICBitmapDecoder
*iface
)
426 IcoDecoder
*This
= (IcoDecoder
*)iface
;
427 ULONG ref
= InterlockedDecrement(&This
->ref
);
429 TRACE("(%p) refcount=%u\n", iface
, ref
);
433 This
->lock
.DebugInfo
->Spare
[0] = 0;
434 DeleteCriticalSection(&This
->lock
);
435 if (This
->stream
) IStream_Release(This
->stream
);
436 HeapFree(GetProcessHeap(), 0, This
);
442 static HRESULT WINAPI
IcoDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
443 DWORD
*pdwCapability
)
445 FIXME("(%p,%p,%p): stub\n", iface
, pIStream
, pdwCapability
);
449 static HRESULT WINAPI
IcoDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
450 WICDecodeOptions cacheOptions
)
452 IcoDecoder
*This
= (IcoDecoder
*)iface
;
456 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
458 EnterCriticalSection(&This
->lock
);
460 if (This
->initialized
)
462 hr
= WINCODEC_ERR_WRONGSTATE
;
467 hr
= IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
468 if (FAILED(hr
)) goto end
;
470 hr
= IStream_Read(pIStream
, &This
->header
, sizeof(ICONHEADER
), &bytesread
);
471 if (FAILED(hr
)) goto end
;
472 if (bytesread
!= sizeof(ICONHEADER
) ||
473 This
->header
.idReserved
!= 0 ||
474 This
->header
.idType
!= 1)
480 This
->initialized
= TRUE
;
481 This
->stream
= pIStream
;
482 IStream_AddRef(pIStream
);
486 LeaveCriticalSection(&This
->lock
);
491 static HRESULT WINAPI
IcoDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
492 GUID
*pguidContainerFormat
)
494 FIXME("(%p,%p): stub\n", iface
, pguidContainerFormat
);
498 static HRESULT WINAPI
IcoDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
499 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
501 FIXME("(%p,%p): stub\n", iface
, ppIDecoderInfo
);
505 static HRESULT WINAPI
IcoDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
506 IWICPalette
*pIPalette
)
508 TRACE("(%p,%p)\n", iface
, pIPalette
);
509 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
512 static HRESULT WINAPI
IcoDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
513 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
515 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
516 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
519 static HRESULT WINAPI
IcoDecoder_GetPreview(IWICBitmapDecoder
*iface
,
520 IWICBitmapSource
**ppIBitmapSource
)
522 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
523 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
526 static HRESULT WINAPI
IcoDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
527 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
529 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
530 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
533 static HRESULT WINAPI
IcoDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
534 IWICBitmapSource
**ppIThumbnail
)
536 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
537 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
540 static HRESULT WINAPI
IcoDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
543 IcoDecoder
*This
= (IcoDecoder
*)iface
;
544 TRACE("(%p,%p)\n", iface
, pCount
);
546 if (!This
->initialized
) return WINCODEC_ERR_NOTINITIALIZED
;
548 *pCount
= This
->header
.idCount
;
549 TRACE("<-- %u\n", *pCount
);
554 static HRESULT WINAPI
IcoDecoder_GetFrame(IWICBitmapDecoder
*iface
,
555 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
557 IcoDecoder
*This
= (IcoDecoder
*)iface
;
558 IcoFrameDecode
*result
=NULL
;
560 ULARGE_INTEGER offset
, length
;
564 IWICStream
*substream
=NULL
;
566 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
568 EnterCriticalSection(&This
->lock
);
570 if (!This
->initialized
)
572 hr
= WINCODEC_ERR_NOTINITIALIZED
;
576 if (This
->header
.idCount
< index
)
582 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcoFrameDecode
));
589 result
->lpVtbl
= &IcoFrameDecode_Vtbl
;
593 /* read the icon entry */
594 seek
.QuadPart
= sizeof(ICONHEADER
) + sizeof(ICONDIRENTRY
) * index
;
595 hr
= IStream_Seek(This
->stream
, seek
, STREAM_SEEK_SET
, 0);
596 if (FAILED(hr
)) goto fail
;
598 hr
= IStream_Read(This
->stream
, &entry
, sizeof(ICONDIRENTRY
), &bytesread
);
599 if (FAILED(hr
) || bytesread
!= sizeof(ICONDIRENTRY
)) goto fail
;
601 /* create a stream object for this icon */
602 hr
= StreamImpl_Create(&substream
);
603 if (FAILED(hr
)) goto fail
;
605 offset
.QuadPart
= entry
.dwDIBOffset
;
606 length
.QuadPart
= entry
.dwDIBSize
;
607 hr
= IWICStream_InitializeFromIStreamRegion(substream
, This
->stream
, offset
, length
);
608 if (FAILED(hr
)) goto fail
;
610 /* read the bitmapinfo size or magic number */
611 hr
= IWICStream_Read(substream
, &magic
, sizeof(magic
), &bytesread
);
612 if (FAILED(hr
) || bytesread
!= sizeof(magic
)) goto fail
;
614 /* forward to the appropriate decoding function based on the magic number */
617 case sizeof(BITMAPCOREHEADER
):
618 case 64: /* sizeof(BITMAPCOREHEADER2) */
619 case sizeof(BITMAPINFOHEADER
):
620 case sizeof(BITMAPV4HEADER
):
621 case sizeof(BITMAPV5HEADER
):
622 hr
= ReadIcoDib((IStream
*)substream
, result
);
625 hr
= ReadIcoPng((IStream
*)substream
, result
);
628 FIXME("Unrecognized ICO frame magic: %x\n", magic
);
632 if (FAILED(hr
)) goto fail
;
634 *ppIBitmapFrame
= (IWICBitmapFrameDecode
*)result
;
636 LeaveCriticalSection(&This
->lock
);
641 LeaveCriticalSection(&This
->lock
);
642 HeapFree(GetProcessHeap(), 0, result
);
643 if (substream
) IStream_Release(substream
);
644 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
645 TRACE("<-- %x\n", hr
);
649 static const IWICBitmapDecoderVtbl IcoDecoder_Vtbl
= {
650 IcoDecoder_QueryInterface
,
653 IcoDecoder_QueryCapability
,
654 IcoDecoder_Initialize
,
655 IcoDecoder_GetContainerFormat
,
656 IcoDecoder_GetDecoderInfo
,
657 IcoDecoder_CopyPalette
,
658 IcoDecoder_GetMetadataQueryReader
,
659 IcoDecoder_GetPreview
,
660 IcoDecoder_GetColorContexts
,
661 IcoDecoder_GetThumbnail
,
662 IcoDecoder_GetFrameCount
,
666 HRESULT
IcoDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
671 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
675 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
677 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder
));
678 if (!This
) return E_OUTOFMEMORY
;
680 This
->lpVtbl
= &IcoDecoder_Vtbl
;
683 This
->initialized
= FALSE
;
684 InitializeCriticalSection(&This
->lock
);
685 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IcoDecoder.lock");
687 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
688 IUnknown_Release((IUnknown
*)This
);