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
);
49 DWORD bc2ClrImportant
;
50 /* same as BITMAPINFOHEADER until this point */
55 DWORD bc2HalftoneSize1
;
56 DWORD bc2HalftoneSize2
;
62 typedef HRESULT (*ReadDataFunc
)(struct BmpDecoder
* This
);
64 typedef struct BmpDecoder
{
65 const IWICBitmapDecoderVtbl
*lpVtbl
;
66 const IWICBitmapFrameDecodeVtbl
*lpFrameVtbl
;
72 const WICPixelFormatGUID
*pixelformat
;
74 ReadDataFunc read_data_func
;
78 CRITICAL_SECTION lock
; /* must be held when initialized/imagedata is set or stream is accessed */
81 static inline BmpDecoder
*impl_from_frame(IWICBitmapFrameDecode
*iface
)
83 return CONTAINING_RECORD(iface
, BmpDecoder
, lpFrameVtbl
);
86 static HRESULT WINAPI
BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
89 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
91 if (!ppv
) return E_INVALIDARG
;
93 if (IsEqualIID(&IID_IUnknown
, iid
) ||
94 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
95 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
102 return E_NOINTERFACE
;
105 IUnknown_AddRef((IUnknown
*)*ppv
);
109 static ULONG WINAPI
BmpFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
111 BmpDecoder
*This
= impl_from_frame(iface
);
113 return IUnknown_AddRef((IUnknown
*)This
);
116 static ULONG WINAPI
BmpFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
118 BmpDecoder
*This
= impl_from_frame(iface
);
120 return IUnknown_Release((IUnknown
*)This
);
123 static HRESULT WINAPI
BmpFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
124 UINT
*puiWidth
, UINT
*puiHeight
)
126 BmpDecoder
*This
= impl_from_frame(iface
);
127 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
129 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
131 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
132 *puiWidth
= bch
->bcWidth
;
133 *puiHeight
= bch
->bcHeight
;
137 *puiWidth
= This
->bih
.bV5Width
;
138 *puiHeight
= abs(This
->bih
.bV5Height
);
143 static HRESULT WINAPI
BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
144 WICPixelFormatGUID
*pPixelFormat
)
146 BmpDecoder
*This
= impl_from_frame(iface
);
147 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
149 memcpy(pPixelFormat
, This
->pixelformat
, sizeof(GUID
));
154 static HRESULT
BmpHeader_GetResolution(BITMAPV5HEADER
*bih
, double *pDpiX
, double *pDpiY
)
156 switch (bih
->bV5Size
)
158 case sizeof(BITMAPCOREHEADER
):
162 case sizeof(BITMAPCOREHEADER2
):
163 case sizeof(BITMAPINFOHEADER
):
164 case sizeof(BITMAPV4HEADER
):
165 case sizeof(BITMAPV5HEADER
):
166 *pDpiX
= bih
->bV5XPelsPerMeter
* 0.0254;
167 *pDpiY
= bih
->bV5YPelsPerMeter
* 0.0254;
174 static HRESULT WINAPI
BmpFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
175 double *pDpiX
, double *pDpiY
)
177 BmpDecoder
*This
= impl_from_frame(iface
);
178 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
180 return BmpHeader_GetResolution(&This
->bih
, pDpiX
, pDpiY
);
183 static HRESULT WINAPI
BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
184 IWICPalette
*pIPalette
)
187 BmpDecoder
*This
= impl_from_frame(iface
);
189 WICColor
*wiccolors
=NULL
;
190 RGBTRIPLE
*bgrcolors
=NULL
;
192 TRACE("(%p,%p)\n", iface
, pIPalette
);
194 EnterCriticalSection(&This
->lock
);
196 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
198 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
199 if (bch
->bcBitCount
<= 8)
201 /* 2**n colors in BGR format after the header */
202 ULONG tablesize
, bytesread
;
203 LARGE_INTEGER offset
;
206 count
= 1 << bch
->bcBitCount
;
207 wiccolors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * count
);
208 tablesize
= sizeof(RGBTRIPLE
) * count
;
209 bgrcolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
210 if (!wiccolors
|| !bgrcolors
)
216 offset
.QuadPart
= sizeof(BITMAPFILEHEADER
)+sizeof(BITMAPCOREHEADER
);
217 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
218 if (FAILED(hr
)) goto end
;
220 hr
= IStream_Read(This
->stream
, bgrcolors
, tablesize
, &bytesread
);
221 if (FAILED(hr
)) goto end
;
222 if (bytesread
!= tablesize
) {
227 for (i
=0; i
<count
; i
++)
229 wiccolors
[i
] = 0xff000000|
230 (bgrcolors
[i
].rgbtRed
<<16)|
231 (bgrcolors
[i
].rgbtGreen
<<8)|
232 bgrcolors
[i
].rgbtBlue
;
237 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
243 if (This
->bih
.bV5BitCount
<= 8)
245 ULONG tablesize
, bytesread
;
246 LARGE_INTEGER offset
;
249 if (This
->bih
.bV5ClrUsed
== 0)
250 count
= 1 << This
->bih
.bV5BitCount
;
252 count
= This
->bih
.bV5ClrUsed
;
254 tablesize
= sizeof(WICColor
) * count
;
255 wiccolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
262 offset
.QuadPart
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
263 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
264 if (FAILED(hr
)) goto end
;
266 hr
= IStream_Read(This
->stream
, wiccolors
, tablesize
, &bytesread
);
267 if (FAILED(hr
)) goto end
;
268 if (bytesread
!= tablesize
) {
273 /* convert from BGR to BGRA by setting alpha to 100% */
274 for (i
=0; i
<count
; i
++)
275 wiccolors
[i
] |= 0xff000000;
279 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
286 LeaveCriticalSection(&This
->lock
);
289 hr
= IWICPalette_InitializeCustom(pIPalette
, wiccolors
, count
);
291 HeapFree(GetProcessHeap(), 0, wiccolors
);
292 HeapFree(GetProcessHeap(), 0, bgrcolors
);
296 static HRESULT WINAPI
BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
297 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
299 BmpDecoder
*This
= impl_from_frame(iface
);
302 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
304 EnterCriticalSection(&This
->lock
);
305 if (!This
->imagedata
)
307 hr
= This
->read_data_func(This
);
309 LeaveCriticalSection(&This
->lock
);
310 if (FAILED(hr
)) return hr
;
312 hr
= BmpFrameDecode_GetSize(iface
, &width
, &height
);
313 if (FAILED(hr
)) return hr
;
315 return copy_pixels(This
->bitsperpixel
, This
->imagedatastart
,
316 width
, height
, This
->stride
,
317 prc
, cbStride
, cbBufferSize
, pbBuffer
);
320 static HRESULT WINAPI
BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
321 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
323 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
324 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
327 static HRESULT WINAPI
BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
328 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
330 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
331 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
334 static HRESULT WINAPI
BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
335 IWICBitmapSource
**ppIThumbnail
)
337 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
338 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
341 static HRESULT
BmpFrameDecode_ReadUncompressed(BmpDecoder
* This
)
348 LARGE_INTEGER offbits
;
351 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
353 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
354 width
= bch
->bcWidth
;
355 height
= bch
->bcHeight
;
360 width
= This
->bih
.bV5Width
;
361 height
= abs(This
->bih
.bV5Height
);
362 bottomup
= (This
->bih
.bV5Height
> 0);
365 /* row sizes in BMP files must be divisible by 4 bytes */
366 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
367 datasize
= bytesperrow
* height
;
369 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
370 if (!This
->imagedata
) return E_OUTOFMEMORY
;
372 offbits
.QuadPart
= This
->bfh
.bfOffBits
;
373 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
374 if (FAILED(hr
)) goto fail
;
376 hr
= IStream_Read(This
->stream
, This
->imagedata
, datasize
, &bytesread
);
377 if (FAILED(hr
) || bytesread
!= datasize
) goto fail
;
381 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
382 This
->stride
= -bytesperrow
;
386 This
->imagedatastart
= This
->imagedata
;
387 This
->stride
= bytesperrow
;
392 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
393 This
->imagedata
= NULL
;
394 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
398 static HRESULT
ReadByte(IStream
*stream
, BYTE
*buffer
, ULONG buffer_size
,
399 ULONG
*cursor
, ULONG
*bytesread
, BYTE
*result
)
403 if (*bytesread
== 0 || *cursor
== *bytesread
)
405 hr
= IStream_Read(stream
, buffer
, buffer_size
, bytesread
);
411 if (*cursor
< *bytesread
)
412 *result
= buffer
[(*cursor
)++];
420 static HRESULT
BmpFrameDecode_ReadRLE8(BmpDecoder
* This
)
425 UINT datasize
, palettesize
;
430 LARGE_INTEGER offbits
;
431 ULONG cursor
=0, bytesread
=0;
433 width
= This
->bih
.bV5Width
;
434 height
= abs(This
->bih
.bV5Height
);
435 bytesperrow
= width
* 4;
436 datasize
= bytesperrow
* height
;
437 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 256)
438 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
440 palettesize
= 4 * 256;
442 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
443 if (!This
->imagedata
)
450 offbits
.QuadPart
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
451 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
452 if (FAILED(hr
)) goto fail
;
454 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
455 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
458 offbits
.QuadPart
= This
->bfh
.bfOffBits
;
459 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
460 if (FAILED(hr
)) goto fail
;
463 bgrdata
= (DWORD
*)This
->imagedata
;
471 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
475 else if (length
== 0)
479 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
484 case 0: /* end of line */
488 case 1: /* end of bitmap */
493 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
495 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
502 default: /* absolute mode */
504 while (length
-- && x
< width
)
507 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
510 bgrdata
[y
*width
+ x
++] = palette
[index
];
513 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
522 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
525 color
= palette
[index
];
526 while (length
-- && x
< width
)
527 bgrdata
[y
*width
+ x
++] = color
;
532 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
533 This
->stride
= -bytesperrow
;
538 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
539 This
->imagedata
= NULL
;
540 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
544 static HRESULT
BmpFrameDecode_ReadRLE4(BmpDecoder
* This
)
549 UINT datasize
, palettesize
;
554 LARGE_INTEGER offbits
;
555 ULONG cursor
=0, bytesread
=0;
557 width
= This
->bih
.bV5Width
;
558 height
= abs(This
->bih
.bV5Height
);
559 bytesperrow
= width
* 4;
560 datasize
= bytesperrow
* height
;
561 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 16)
562 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
564 palettesize
= 4 * 16;
566 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
567 if (!This
->imagedata
)
574 offbits
.QuadPart
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
575 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
576 if (FAILED(hr
)) goto fail
;
578 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
579 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
582 offbits
.QuadPart
= This
->bfh
.bfOffBits
;
583 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
584 if (FAILED(hr
)) goto fail
;
587 bgrdata
= (DWORD
*)This
->imagedata
;
595 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
599 else if (length
== 0)
603 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
608 case 0: /* end of line */
612 case 1: /* end of bitmap */
617 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
619 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
626 default: /* absolute mode */
630 while (length
-- && x
< width
)
633 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
637 bgrdata
[y
*width
+ x
++] = palette
[colors
>>4];
638 if (length
-- && x
< width
)
639 bgrdata
[y
*width
+ x
++] = palette
[colors
&0xf];
644 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
655 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
658 color1
= palette
[colors
>>4];
659 color2
= palette
[colors
&0xf];
660 while (length
-- && x
< width
)
662 bgrdata
[y
*width
+ x
++] = color1
;
663 if (length
-- && x
< width
)
664 bgrdata
[y
*width
+ x
++] = color2
;
672 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
673 This
->stride
= -bytesperrow
;
678 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
679 This
->imagedata
= NULL
;
680 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
684 static HRESULT
BmpFrameDecode_ReadUnsupported(BmpDecoder
* This
)
689 struct bitfields_format
{
690 WORD bitcount
; /* 0 for end of list */
695 const WICPixelFormatGUID
*pixelformat
;
696 ReadDataFunc read_data_func
;
699 static const struct bitfields_format bitfields_formats
[] = {
700 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555
,BmpFrameDecode_ReadUncompressed
},
701 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565
,BmpFrameDecode_ReadUncompressed
},
702 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadUncompressed
},
703 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA
,BmpFrameDecode_ReadUncompressed
},
707 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl
= {
708 BmpFrameDecode_QueryInterface
,
709 BmpFrameDecode_AddRef
,
710 BmpFrameDecode_Release
,
711 BmpFrameDecode_GetSize
,
712 BmpFrameDecode_GetPixelFormat
,
713 BmpFrameDecode_GetResolution
,
714 BmpFrameDecode_CopyPalette
,
715 BmpFrameDecode_CopyPixels
,
716 BmpFrameDecode_GetMetadataQueryReader
,
717 BmpFrameDecode_GetColorContexts
,
718 BmpFrameDecode_GetThumbnail
721 static HRESULT
BmpDecoder_ReadHeaders(BmpDecoder
* This
, IStream
*stream
)
724 ULONG bytestoread
, bytesread
;
727 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
730 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, NULL
);
731 if (FAILED(hr
)) return hr
;
733 hr
= IStream_Read(stream
, &This
->bfh
, sizeof(BITMAPFILEHEADER
), &bytesread
);
734 if (FAILED(hr
)) return hr
;
735 if (bytesread
!= sizeof(BITMAPFILEHEADER
) ||
736 This
->bfh
.bfType
!= 0x4d42 /* "BM" */) return E_FAIL
;
738 hr
= IStream_Read(stream
, &This
->bih
.bV5Size
, sizeof(DWORD
), &bytesread
);
739 if (FAILED(hr
)) return hr
;
740 if (bytesread
!= sizeof(DWORD
) ||
741 (This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER
) &&
742 This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER2
) &&
743 This
->bih
.bV5Size
!= sizeof(BITMAPINFOHEADER
) &&
744 This
->bih
.bV5Size
!= sizeof(BITMAPV4HEADER
) &&
745 This
->bih
.bV5Size
!= sizeof(BITMAPV5HEADER
))) return E_FAIL
;
747 bytestoread
= This
->bih
.bV5Size
-sizeof(DWORD
);
748 hr
= IStream_Read(stream
, &This
->bih
.bV5Width
, bytestoread
, &bytesread
);
749 if (FAILED(hr
)) return hr
;
750 if (bytestoread
!= bytesread
) return E_FAIL
;
752 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
753 read the extra fields */
754 if (This
->bih
.bV5Size
== sizeof(BITMAPINFOHEADER
) &&
755 This
->bih
.bV5Compression
== BI_BITFIELDS
)
757 hr
= IStream_Read(stream
, &This
->bih
.bV5RedMask
, 12, &bytesread
);
758 if (FAILED(hr
)) return hr
;
759 if (bytesread
!= 12) return E_FAIL
;
760 This
->bih
.bV5AlphaMask
= 0;
763 /* decide what kind of bitmap this is and how/if we can read it */
764 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
766 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
767 TRACE("BITMAPCOREHEADER with depth=%i\n", bch
->bcBitCount
);
768 This
->bitsperpixel
= bch
->bcBitCount
;
769 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
770 switch(bch
->bcBitCount
)
773 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
776 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
779 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
782 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
785 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
788 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
789 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch
->bcBitCount
);
793 else /* struct is compatible with BITMAPINFOHEADER */
795 TRACE("bitmap header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
796 switch(This
->bih
.bV5Compression
)
799 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
800 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
801 switch(This
->bih
.bV5BitCount
)
804 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
807 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
810 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
813 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
816 This
->pixelformat
= &GUID_WICPixelFormat16bppBGR555
;
819 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
822 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
825 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
826 FIXME("unsupported bit depth %i for uncompressed RGB\n", This
->bih
.bV5BitCount
);
830 This
->bitsperpixel
= 32;
831 This
->read_data_func
= BmpFrameDecode_ReadRLE8
;
832 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
835 This
->bitsperpixel
= 32;
836 This
->read_data_func
= BmpFrameDecode_ReadRLE4
;
837 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
841 const struct bitfields_format
*format
;
842 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER2
))
844 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
845 This
->bitsperpixel
= 0;
846 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
847 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
848 FIXME("Huffman 1D compression is unsupported\n");
851 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
852 for (format
= bitfields_formats
; format
->bitcount
; format
++)
854 if ((format
->bitcount
== This
->bih
.bV5BitCount
) &&
855 (format
->redmask
== This
->bih
.bV5RedMask
) &&
856 (format
->greenmask
== This
->bih
.bV5GreenMask
) &&
857 (format
->bluemask
== This
->bih
.bV5BlueMask
) &&
858 (format
->alphamask
== This
->bih
.bV5AlphaMask
))
860 This
->read_data_func
= format
->read_data_func
;
861 This
->pixelformat
= format
->pixelformat
;
865 if (!format
->bitcount
)
867 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
868 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
869 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
870 This
->bih
.bV5BitCount
, This
->bih
.bV5RedMask
, This
->bih
.bV5GreenMask
, This
->bih
.bV5BlueMask
, This
->bih
.bV5AlphaMask
);
875 This
->bitsperpixel
= 0;
876 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
877 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
878 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
883 This
->initialized
= TRUE
;
888 static HRESULT WINAPI
BmpDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
891 BmpDecoder
*This
= (BmpDecoder
*)iface
;
892 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
894 if (!ppv
) return E_INVALIDARG
;
896 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
903 return E_NOINTERFACE
;
906 IUnknown_AddRef((IUnknown
*)*ppv
);
910 static ULONG WINAPI
BmpDecoder_AddRef(IWICBitmapDecoder
*iface
)
912 BmpDecoder
*This
= (BmpDecoder
*)iface
;
913 ULONG ref
= InterlockedIncrement(&This
->ref
);
915 TRACE("(%p) refcount=%u\n", iface
, ref
);
920 static ULONG WINAPI
BmpDecoder_Release(IWICBitmapDecoder
*iface
)
922 BmpDecoder
*This
= (BmpDecoder
*)iface
;
923 ULONG ref
= InterlockedDecrement(&This
->ref
);
925 TRACE("(%p) refcount=%u\n", iface
, ref
);
929 if (This
->stream
) IStream_Release(This
->stream
);
930 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
931 This
->lock
.DebugInfo
->Spare
[0] = 0;
932 DeleteCriticalSection(&This
->lock
);
933 HeapFree(GetProcessHeap(), 0, This
);
939 static HRESULT WINAPI
BmpDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
940 DWORD
*pdwCapability
)
943 BmpDecoder
*This
= (BmpDecoder
*)iface
;
945 EnterCriticalSection(&This
->lock
);
946 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
947 LeaveCriticalSection(&This
->lock
);
948 if (FAILED(hr
)) return hr
;
950 if (This
->read_data_func
== BmpFrameDecode_ReadUnsupported
)
953 *pdwCapability
= WICBitmapDecoderCapabilityCanDecodeAllImages
;
958 static HRESULT WINAPI
BmpDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
959 WICDecodeOptions cacheOptions
)
962 BmpDecoder
*This
= (BmpDecoder
*)iface
;
964 EnterCriticalSection(&This
->lock
);
965 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
969 This
->stream
= pIStream
;
970 IStream_AddRef(pIStream
);
972 LeaveCriticalSection(&This
->lock
);
977 static HRESULT WINAPI
BmpDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
978 GUID
*pguidContainerFormat
)
980 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
984 static HRESULT WINAPI
BmpDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
985 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
988 IWICComponentInfo
*compinfo
;
990 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
992 hr
= CreateComponentInfo(&CLSID_WICBmpDecoder
, &compinfo
);
993 if (FAILED(hr
)) return hr
;
995 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
996 (void**)ppIDecoderInfo
);
998 IWICComponentInfo_Release(compinfo
);
1003 static HRESULT WINAPI
BmpDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1004 IWICPalette
*pIPalette
)
1006 TRACE("(%p,%p)\n", iface
, pIPalette
);
1008 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1011 static HRESULT WINAPI
BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1012 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1014 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1015 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1018 static HRESULT WINAPI
BmpDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1019 IWICBitmapSource
**ppIBitmapSource
)
1021 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1022 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1025 static HRESULT WINAPI
BmpDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1026 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1028 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1029 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1032 static HRESULT WINAPI
BmpDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1033 IWICBitmapSource
**ppIThumbnail
)
1035 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1036 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1039 static HRESULT WINAPI
BmpDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1046 static HRESULT WINAPI
BmpDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1047 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1049 BmpDecoder
*This
= (BmpDecoder
*)iface
;
1051 if (index
!= 0) return E_INVALIDARG
;
1053 if (!This
->stream
) return WINCODEC_ERR_WRONGSTATE
;
1055 *ppIBitmapFrame
= (IWICBitmapFrameDecode
*)&This
->lpFrameVtbl
;
1056 IWICBitmapDecoder_AddRef(iface
);
1061 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl
= {
1062 BmpDecoder_QueryInterface
,
1065 BmpDecoder_QueryCapability
,
1066 BmpDecoder_Initialize
,
1067 BmpDecoder_GetContainerFormat
,
1068 BmpDecoder_GetDecoderInfo
,
1069 BmpDecoder_CopyPalette
,
1070 BmpDecoder_GetMetadataQueryReader
,
1071 BmpDecoder_GetPreview
,
1072 BmpDecoder_GetColorContexts
,
1073 BmpDecoder_GetThumbnail
,
1074 BmpDecoder_GetFrameCount
,
1078 HRESULT
BmpDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1083 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1087 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1089 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder
));
1090 if (!This
) return E_OUTOFMEMORY
;
1092 This
->lpVtbl
= &BmpDecoder_Vtbl
;
1093 This
->lpFrameVtbl
= &BmpDecoder_FrameVtbl
;
1095 This
->initialized
= FALSE
;
1096 This
->stream
= NULL
;
1097 This
->imagedata
= NULL
;
1098 InitializeCriticalSection(&This
->lock
);
1099 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BmpDecoder.lock");
1101 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1102 IUnknown_Release((IUnknown
*)This
);