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
19 #define WIN32_NO_STATUS
21 #define COM_NO_WINDOWS_H
37 #include "wincodecs_private.h"
39 #include <wine/debug.h>
41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
54 DWORD bc2ClrImportant
;
55 /* same as BITMAPINFOHEADER until this point */
60 DWORD bc2HalftoneSize1
;
61 DWORD bc2HalftoneSize2
;
66 typedef HRESULT (*ReadDataFunc
)(BmpDecoder
* This
);
69 IWICBitmapDecoder IWICBitmapDecoder_iface
;
70 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
77 const WICPixelFormatGUID
*pixelformat
;
79 ReadDataFunc read_data_func
;
83 CRITICAL_SECTION lock
; /* must be held when initialized/imagedata is set or stream is accessed */
84 int packed
; /* If TRUE, don't look for a file header and assume a packed DIB. */
85 int icoframe
; /* If TRUE, this is a frame of a .ico file. */
88 static inline BmpDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
90 return CONTAINING_RECORD(iface
, BmpDecoder
, IWICBitmapDecoder_iface
);
93 static inline BmpDecoder
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
95 return CONTAINING_RECORD(iface
, BmpDecoder
, IWICBitmapFrameDecode_iface
);
98 static HRESULT WINAPI
BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
101 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
103 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
105 if (!ppv
) return E_INVALIDARG
;
107 if (IsEqualIID(&IID_IUnknown
, iid
) ||
108 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
109 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
111 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
116 return E_NOINTERFACE
;
119 IUnknown_AddRef((IUnknown
*)*ppv
);
123 static ULONG WINAPI
BmpFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
125 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
127 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
130 static ULONG WINAPI
BmpFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
132 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
134 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
137 static HRESULT WINAPI
BmpFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
138 UINT
*puiWidth
, UINT
*puiHeight
)
140 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
141 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
143 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
145 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
146 *puiWidth
= bch
->bcWidth
;
147 *puiHeight
= bch
->bcHeight
;
151 *puiWidth
= This
->bih
.bV5Width
;
152 *puiHeight
= abs(This
->bih
.bV5Height
);
157 static HRESULT WINAPI
BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
158 WICPixelFormatGUID
*pPixelFormat
)
160 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
161 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
163 memcpy(pPixelFormat
, This
->pixelformat
, sizeof(GUID
));
168 static HRESULT
BmpHeader_GetResolution(BITMAPV5HEADER
*bih
, double *pDpiX
, double *pDpiY
)
170 LONG resx
= 0, resy
= 0;
172 switch (bih
->bV5Size
)
175 case sizeof(BITMAPCOREHEADER
):
178 case sizeof(BITMAPCOREHEADER2
):
179 case sizeof(BITMAPINFOHEADER
):
180 case sizeof(BITMAPV4HEADER
):
181 case sizeof(BITMAPV5HEADER
):
182 resx
= bih
->bV5XPelsPerMeter
;
183 resy
= bih
->bV5YPelsPerMeter
;
194 *pDpiX
= resx
* 0.0254;
195 *pDpiY
= resy
* 0.0254;
201 static HRESULT WINAPI
BmpFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
202 double *pDpiX
, double *pDpiY
)
204 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
205 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
207 return BmpHeader_GetResolution(&This
->bih
, pDpiX
, pDpiY
);
210 static HRESULT WINAPI
BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
211 IWICPalette
*pIPalette
)
214 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
216 WICColor
*wiccolors
=NULL
;
217 RGBTRIPLE
*bgrcolors
=NULL
;
219 TRACE("(%p,%p)\n", iface
, pIPalette
);
221 EnterCriticalSection(&This
->lock
);
223 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
225 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
226 if (bch
->bcBitCount
<= 8)
228 /* 2**n colors in BGR format after the header */
229 ULONG tablesize
, bytesread
;
230 LARGE_INTEGER offset
;
233 count
= 1 << bch
->bcBitCount
;
234 wiccolors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * count
);
235 tablesize
= sizeof(RGBTRIPLE
) * count
;
236 bgrcolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
237 if (!wiccolors
|| !bgrcolors
)
243 offset
.QuadPart
= This
->palette_offset
;
244 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
245 if (FAILED(hr
)) goto end
;
247 hr
= IStream_Read(This
->stream
, bgrcolors
, tablesize
, &bytesread
);
248 if (FAILED(hr
)) goto end
;
249 if (bytesread
!= tablesize
) {
254 for (i
=0; i
<count
; i
++)
256 wiccolors
[i
] = 0xff000000|
257 (bgrcolors
[i
].rgbtRed
<<16)|
258 (bgrcolors
[i
].rgbtGreen
<<8)|
259 bgrcolors
[i
].rgbtBlue
;
264 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
270 if (This
->bih
.bV5BitCount
<= 8)
272 ULONG tablesize
, bytesread
;
273 LARGE_INTEGER offset
;
276 if (This
->bih
.bV5ClrUsed
== 0)
277 count
= 1 << This
->bih
.bV5BitCount
;
279 count
= This
->bih
.bV5ClrUsed
;
281 tablesize
= sizeof(WICColor
) * count
;
282 wiccolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
289 offset
.QuadPart
= This
->palette_offset
;
290 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
291 if (FAILED(hr
)) goto end
;
293 hr
= IStream_Read(This
->stream
, wiccolors
, tablesize
, &bytesread
);
294 if (FAILED(hr
)) goto end
;
295 if (bytesread
!= tablesize
) {
300 /* convert from BGR to BGRA by setting alpha to 100% */
301 for (i
=0; i
<count
; i
++)
302 wiccolors
[i
] |= 0xff000000;
306 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
313 LeaveCriticalSection(&This
->lock
);
316 hr
= IWICPalette_InitializeCustom(pIPalette
, wiccolors
, count
);
318 HeapFree(GetProcessHeap(), 0, wiccolors
);
319 HeapFree(GetProcessHeap(), 0, bgrcolors
);
323 static HRESULT WINAPI
BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
324 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
326 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
329 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
331 EnterCriticalSection(&This
->lock
);
332 if (!This
->imagedata
)
334 hr
= This
->read_data_func(This
);
336 LeaveCriticalSection(&This
->lock
);
337 if (FAILED(hr
)) return hr
;
339 hr
= BmpFrameDecode_GetSize(iface
, &width
, &height
);
340 if (FAILED(hr
)) return hr
;
342 return copy_pixels(This
->bitsperpixel
, This
->imagedatastart
,
343 width
, height
, This
->stride
,
344 prc
, cbStride
, cbBufferSize
, pbBuffer
);
347 static HRESULT WINAPI
BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
348 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
350 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
351 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
354 static HRESULT WINAPI
BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
355 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
357 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
358 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
361 static HRESULT WINAPI
BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
362 IWICBitmapSource
**ppIThumbnail
)
364 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
365 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
368 static HRESULT
BmpFrameDecode_ReadUncompressed(BmpDecoder
* This
)
375 LARGE_INTEGER offbits
;
378 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
380 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
381 width
= bch
->bcWidth
;
382 height
= bch
->bcHeight
;
387 width
= This
->bih
.bV5Width
;
388 height
= abs(This
->bih
.bV5Height
);
389 bottomup
= (This
->bih
.bV5Height
> 0);
392 /* row sizes in BMP files must be divisible by 4 bytes */
393 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
394 datasize
= bytesperrow
* height
;
396 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
397 if (!This
->imagedata
) return E_OUTOFMEMORY
;
399 offbits
.QuadPart
= This
->image_offset
;
400 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
401 if (FAILED(hr
)) goto fail
;
403 hr
= IStream_Read(This
->stream
, This
->imagedata
, datasize
, &bytesread
);
404 if (FAILED(hr
) || bytesread
!= datasize
) goto fail
;
408 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
409 This
->stride
= -bytesperrow
;
413 This
->imagedatastart
= This
->imagedata
;
414 This
->stride
= bytesperrow
;
419 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
420 This
->imagedata
= NULL
;
421 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
425 static HRESULT
BmpFrameDecode_ReadRGB8(BmpDecoder
* This
)
430 hr
= IWICBitmapFrameDecode_GetSize(&This
->IWICBitmapFrameDecode_iface
, &width
, &height
);
434 hr
= BmpFrameDecode_ReadUncompressed(This
);
439 reverse_bgr8(This
->bitsperpixel
/8, This
->imagedatastart
,
440 width
, height
, This
->stride
);
446 static HRESULT
ReadByte(IStream
*stream
, BYTE
*buffer
, ULONG buffer_size
,
447 ULONG
*cursor
, ULONG
*bytesread
, BYTE
*result
)
451 if (*bytesread
== 0 || *cursor
== *bytesread
)
453 hr
= IStream_Read(stream
, buffer
, buffer_size
, bytesread
);
459 if (*cursor
< *bytesread
)
460 *result
= buffer
[(*cursor
)++];
468 static HRESULT
BmpFrameDecode_ReadRLE8(BmpDecoder
* This
)
473 UINT datasize
, palettesize
;
478 LARGE_INTEGER offbits
;
479 ULONG cursor
=0, bytesread
=0;
481 width
= This
->bih
.bV5Width
;
482 height
= abs(This
->bih
.bV5Height
);
483 bytesperrow
= width
* 4;
484 datasize
= bytesperrow
* height
;
485 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 256)
486 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
488 palettesize
= 4 * 256;
490 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
491 if (!This
->imagedata
)
498 offbits
.QuadPart
= This
->palette_offset
;
499 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
500 if (FAILED(hr
)) goto fail
;
502 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
503 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
506 offbits
.QuadPart
= This
->image_offset
;
507 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
508 if (FAILED(hr
)) goto fail
;
511 bgrdata
= (DWORD
*)This
->imagedata
;
519 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
523 else if (length
== 0)
527 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
532 case 0: /* end of line */
536 case 1: /* end of bitmap */
541 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
543 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
550 default: /* absolute mode */
552 while (length
-- && x
< width
)
555 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
558 bgrdata
[y
*width
+ x
++] = palette
[index
];
561 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
570 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
573 color
= palette
[index
];
574 while (length
-- && x
< width
)
575 bgrdata
[y
*width
+ x
++] = color
;
580 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
581 This
->stride
= -bytesperrow
;
586 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
587 This
->imagedata
= NULL
;
588 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
592 static HRESULT
BmpFrameDecode_ReadRLE4(BmpDecoder
* This
)
597 UINT datasize
, palettesize
;
602 LARGE_INTEGER offbits
;
603 ULONG cursor
=0, bytesread
=0;
605 width
= This
->bih
.bV5Width
;
606 height
= abs(This
->bih
.bV5Height
);
607 bytesperrow
= width
* 4;
608 datasize
= bytesperrow
* height
;
609 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 16)
610 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
612 palettesize
= 4 * 16;
614 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
615 if (!This
->imagedata
)
622 offbits
.QuadPart
= This
->palette_offset
;
623 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
624 if (FAILED(hr
)) goto fail
;
626 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
627 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
630 offbits
.QuadPart
= This
->image_offset
;
631 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
632 if (FAILED(hr
)) goto fail
;
635 bgrdata
= (DWORD
*)This
->imagedata
;
643 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
647 else if (length
== 0)
651 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
656 case 0: /* end of line */
660 case 1: /* end of bitmap */
665 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
667 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
674 default: /* absolute mode */
678 while (length
-- && x
< width
)
681 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
685 bgrdata
[y
*width
+ x
++] = palette
[colors
>>4];
686 if (length
-- && x
< width
)
687 bgrdata
[y
*width
+ x
++] = palette
[colors
&0xf];
692 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
703 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
706 color1
= palette
[colors
>>4];
707 color2
= palette
[colors
&0xf];
708 while (length
-- && x
< width
)
710 bgrdata
[y
*width
+ x
++] = color1
;
711 if (length
-- && x
< width
)
712 bgrdata
[y
*width
+ x
++] = color2
;
720 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
721 This
->stride
= -bytesperrow
;
726 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
727 This
->imagedata
= NULL
;
728 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
732 static HRESULT
BmpFrameDecode_ReadUnsupported(BmpDecoder
* This
)
737 struct bitfields_format
{
738 WORD bitcount
; /* 0 for end of list */
743 const WICPixelFormatGUID
*pixelformat
;
744 ReadDataFunc read_data_func
;
747 static const struct bitfields_format bitfields_formats
[] = {
748 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555
,BmpFrameDecode_ReadUncompressed
},
749 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565
,BmpFrameDecode_ReadUncompressed
},
750 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadUncompressed
},
751 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA
,BmpFrameDecode_ReadUncompressed
},
752 {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadRGB8
},
756 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl
= {
757 BmpFrameDecode_QueryInterface
,
758 BmpFrameDecode_AddRef
,
759 BmpFrameDecode_Release
,
760 BmpFrameDecode_GetSize
,
761 BmpFrameDecode_GetPixelFormat
,
762 BmpFrameDecode_GetResolution
,
763 BmpFrameDecode_CopyPalette
,
764 BmpFrameDecode_CopyPixels
,
765 BmpFrameDecode_GetMetadataQueryReader
,
766 BmpFrameDecode_GetColorContexts
,
767 BmpFrameDecode_GetThumbnail
770 static HRESULT
BmpDecoder_ReadHeaders(BmpDecoder
* This
, IStream
*stream
)
773 ULONG bytestoread
, bytesread
;
776 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
779 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, NULL
);
780 if (FAILED(hr
)) return hr
;
784 BITMAPFILEHEADER bfh
;
785 hr
= IStream_Read(stream
, &bfh
, sizeof(BITMAPFILEHEADER
), &bytesread
);
786 if (FAILED(hr
)) return hr
;
787 if (bytesread
!= sizeof(BITMAPFILEHEADER
) ||
788 bfh
.bfType
!= 0x4d42 /* "BM" */) return E_FAIL
;
789 This
->image_offset
= bfh
.bfOffBits
;
792 hr
= IStream_Read(stream
, &This
->bih
.bV5Size
, sizeof(DWORD
), &bytesread
);
793 if (FAILED(hr
)) return hr
;
794 if (bytesread
!= sizeof(DWORD
) ||
795 (This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER
) &&
796 This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER2
) &&
797 This
->bih
.bV5Size
!= sizeof(BITMAPINFOHEADER
) &&
798 This
->bih
.bV5Size
!= sizeof(BITMAPV4HEADER
) &&
799 This
->bih
.bV5Size
!= sizeof(BITMAPV5HEADER
))) return E_FAIL
;
801 bytestoread
= This
->bih
.bV5Size
-sizeof(DWORD
);
802 hr
= IStream_Read(stream
, &This
->bih
.bV5Width
, bytestoread
, &bytesread
);
803 if (FAILED(hr
)) return hr
;
804 if (bytestoread
!= bytesread
) return E_FAIL
;
807 This
->palette_offset
= This
->bih
.bV5Size
;
809 This
->palette_offset
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
813 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
815 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
820 This
->bih
.bV5Height
/= 2;
824 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
825 read the extra fields */
826 if (This
->bih
.bV5Size
== sizeof(BITMAPINFOHEADER
) &&
827 This
->bih
.bV5Compression
== BI_BITFIELDS
)
829 hr
= IStream_Read(stream
, &This
->bih
.bV5RedMask
, 12, &bytesread
);
830 if (FAILED(hr
)) return hr
;
831 if (bytesread
!= 12) return E_FAIL
;
832 This
->bih
.bV5AlphaMask
= 0;
833 This
->palette_offset
+= 12;
836 /* decide what kind of bitmap this is and how/if we can read it */
837 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
839 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
840 TRACE("BITMAPCOREHEADER with depth=%i\n", bch
->bcBitCount
);
841 This
->bitsperpixel
= bch
->bcBitCount
;
842 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
843 switch(bch
->bcBitCount
)
846 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
849 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
852 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
855 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
858 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
861 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
862 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch
->bcBitCount
);
866 else /* struct is compatible with BITMAPINFOHEADER */
868 TRACE("bitmap header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
869 switch(This
->bih
.bV5Compression
)
872 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
873 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
874 switch(This
->bih
.bV5BitCount
)
877 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
880 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
883 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
886 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
889 This
->pixelformat
= &GUID_WICPixelFormat16bppBGR555
;
892 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
895 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
898 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
899 FIXME("unsupported bit depth %i for uncompressed RGB\n", This
->bih
.bV5BitCount
);
903 This
->bitsperpixel
= 32;
904 This
->read_data_func
= BmpFrameDecode_ReadRLE8
;
905 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
908 This
->bitsperpixel
= 32;
909 This
->read_data_func
= BmpFrameDecode_ReadRLE4
;
910 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
914 const struct bitfields_format
*format
;
915 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER2
))
917 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
918 This
->bitsperpixel
= 0;
919 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
920 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
921 FIXME("Huffman 1D compression is unsupported\n");
924 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
925 for (format
= bitfields_formats
; format
->bitcount
; format
++)
927 if ((format
->bitcount
== This
->bih
.bV5BitCount
) &&
928 (format
->redmask
== This
->bih
.bV5RedMask
) &&
929 (format
->greenmask
== This
->bih
.bV5GreenMask
) &&
930 (format
->bluemask
== This
->bih
.bV5BlueMask
) &&
931 (format
->alphamask
== This
->bih
.bV5AlphaMask
))
933 This
->read_data_func
= format
->read_data_func
;
934 This
->pixelformat
= format
->pixelformat
;
938 if (!format
->bitcount
)
940 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
941 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
942 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
943 This
->bih
.bV5BitCount
, This
->bih
.bV5RedMask
, This
->bih
.bV5GreenMask
, This
->bih
.bV5BlueMask
, This
->bih
.bV5AlphaMask
);
948 This
->bitsperpixel
= 0;
949 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
950 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
951 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
958 /* In a packed DIB, the image follows the palette. */
959 ULONG palette_count
, palette_size
;
960 if (This
->bih
.bV5ClrUsed
)
961 palette_count
= This
->bih
.bV5ClrUsed
;
962 else if (This
->bih
.bV5BitCount
<= 8)
963 palette_count
= 1 << This
->bih
.bV5BitCount
;
966 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
967 palette_size
= sizeof(RGBTRIPLE
) * palette_count
;
969 palette_size
= sizeof(RGBQUAD
) * palette_count
;
970 This
->image_offset
= This
->palette_offset
+ palette_size
;
973 This
->initialized
= TRUE
;
978 static HRESULT WINAPI
BmpDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
981 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
982 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
984 if (!ppv
) return E_INVALIDARG
;
986 if (IsEqualIID(&IID_IUnknown
, iid
) ||
987 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
989 *ppv
= &This
->IWICBitmapDecoder_iface
;
994 return E_NOINTERFACE
;
997 IUnknown_AddRef((IUnknown
*)*ppv
);
1001 static ULONG WINAPI
BmpDecoder_AddRef(IWICBitmapDecoder
*iface
)
1003 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1004 ULONG ref
= InterlockedIncrement(&This
->ref
);
1006 TRACE("(%p) refcount=%u\n", iface
, ref
);
1011 static ULONG WINAPI
BmpDecoder_Release(IWICBitmapDecoder
*iface
)
1013 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1014 ULONG ref
= InterlockedDecrement(&This
->ref
);
1016 TRACE("(%p) refcount=%u\n", iface
, ref
);
1020 if (This
->stream
) IStream_Release(This
->stream
);
1021 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
1022 This
->lock
.DebugInfo
->Spare
[0] = 0;
1023 DeleteCriticalSection(&This
->lock
);
1024 HeapFree(GetProcessHeap(), 0, This
);
1030 static HRESULT WINAPI
BmpDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1034 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1036 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1038 if (!stream
|| !capability
) return E_INVALIDARG
;
1040 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1041 if (hr
!= S_OK
) return hr
;
1043 *capability
= This
->read_data_func
== BmpFrameDecode_ReadUnsupported
? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages
;
1047 static HRESULT WINAPI
BmpDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1048 WICDecodeOptions cacheOptions
)
1051 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1053 EnterCriticalSection(&This
->lock
);
1054 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
1058 This
->stream
= pIStream
;
1059 IStream_AddRef(pIStream
);
1061 LeaveCriticalSection(&This
->lock
);
1066 static HRESULT WINAPI
BmpDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1067 GUID
*pguidContainerFormat
)
1069 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
1073 static HRESULT WINAPI
BmpDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1074 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1077 IWICComponentInfo
*compinfo
;
1079 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1081 hr
= CreateComponentInfo(&CLSID_WICBmpDecoder
, &compinfo
);
1082 if (FAILED(hr
)) return hr
;
1084 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1085 (void**)ppIDecoderInfo
);
1087 IWICComponentInfo_Release(compinfo
);
1092 static HRESULT WINAPI
BmpDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1093 IWICPalette
*pIPalette
)
1095 TRACE("(%p,%p)\n", iface
, pIPalette
);
1097 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1100 static HRESULT WINAPI
BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1101 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1103 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1104 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1107 static HRESULT WINAPI
BmpDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1108 IWICBitmapSource
**ppIBitmapSource
)
1110 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1111 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1114 static HRESULT WINAPI
BmpDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1115 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1117 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1118 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1121 static HRESULT WINAPI
BmpDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1122 IWICBitmapSource
**ppIThumbnail
)
1124 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1125 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1128 static HRESULT WINAPI
BmpDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1131 if (!pCount
) return E_INVALIDARG
;
1137 static HRESULT WINAPI
BmpDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1138 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1140 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1142 if (index
!= 0) return E_INVALIDARG
;
1144 if (!This
->stream
) return WINCODEC_ERR_FRAMEMISSING
;
1146 *ppIBitmapFrame
= &This
->IWICBitmapFrameDecode_iface
;
1147 IWICBitmapDecoder_AddRef(iface
);
1152 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl
= {
1153 BmpDecoder_QueryInterface
,
1156 BmpDecoder_QueryCapability
,
1157 BmpDecoder_Initialize
,
1158 BmpDecoder_GetContainerFormat
,
1159 BmpDecoder_GetDecoderInfo
,
1160 BmpDecoder_CopyPalette
,
1161 BmpDecoder_GetMetadataQueryReader
,
1162 BmpDecoder_GetPreview
,
1163 BmpDecoder_GetColorContexts
,
1164 BmpDecoder_GetThumbnail
,
1165 BmpDecoder_GetFrameCount
,
1169 static HRESULT
BmpDecoder_Create(int packed
, int icoframe
, BmpDecoder
**ppDecoder
)
1173 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder
));
1174 if (!This
) return E_OUTOFMEMORY
;
1176 This
->IWICBitmapDecoder_iface
.lpVtbl
= &BmpDecoder_Vtbl
;
1177 This
->IWICBitmapFrameDecode_iface
.lpVtbl
= &BmpDecoder_FrameVtbl
;
1179 This
->initialized
= FALSE
;
1180 This
->stream
= NULL
;
1181 This
->imagedata
= NULL
;
1182 InitializeCriticalSection(&This
->lock
);
1183 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BmpDecoder.lock");
1184 This
->packed
= packed
;
1185 This
->icoframe
= icoframe
;
1192 static HRESULT
BmpDecoder_Construct(int packed
, int icoframe
, IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1197 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1201 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1203 ret
= BmpDecoder_Create(packed
, icoframe
, &This
);
1204 if (FAILED(ret
)) return ret
;
1206 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1207 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1212 HRESULT
BmpDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1214 return BmpDecoder_Construct(FALSE
, FALSE
, pUnkOuter
, iid
, ppv
);
1217 HRESULT
DibDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1219 return BmpDecoder_Construct(TRUE
, FALSE
, pUnkOuter
, iid
, ppv
);
1222 HRESULT
IcoDibDecoder_CreateInstance(BmpDecoder
**ppDecoder
)
1224 return BmpDecoder_Create(TRUE
, TRUE
, ppDecoder
);
1227 void BmpDecoder_GetWICDecoder(BmpDecoder
*This
, IWICBitmapDecoder
**ppDecoder
)
1229 *ppDecoder
= &This
->IWICBitmapDecoder_iface
;
1232 /* Return the offset where the mask of an icon might be, or 0 for failure. */
1233 void BmpDecoder_FindIconMask(BmpDecoder
*This
, ULONG
*mask_offset
, int *topdown
)
1235 assert(This
->stream
!= NULL
);
1237 if (This
->read_data_func
== BmpFrameDecode_ReadUncompressed
)
1239 /* RGB or BITFIELDS data */
1240 ULONG width
, height
, bytesperrow
, datasize
;
1241 IWICBitmapFrameDecode_GetSize(&This
->IWICBitmapFrameDecode_iface
, &width
, &height
);
1242 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
1243 datasize
= bytesperrow
* height
;
1244 *mask_offset
= This
->image_offset
+ datasize
;
1249 *topdown
= This
->stride
> 0;