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
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
47 DWORD bc2ClrImportant
;
48 /* same as BITMAPINFOHEADER until this point */
53 DWORD bc2HalftoneSize1
;
54 DWORD bc2HalftoneSize2
;
59 typedef HRESULT (*ReadDataFunc
)(BmpDecoder
* This
);
62 IWICBitmapDecoder IWICBitmapDecoder_iface
;
63 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
70 const WICPixelFormatGUID
*pixelformat
;
72 ReadDataFunc read_data_func
;
76 CRITICAL_SECTION lock
; /* must be held when initialized/imagedata is set or stream is accessed */
77 int packed
; /* If TRUE, don't look for a file header and assume a packed DIB. */
78 int icoframe
; /* If TRUE, this is a frame of a .ico file. */
81 static inline BmpDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
83 return CONTAINING_RECORD(iface
, BmpDecoder
, IWICBitmapDecoder_iface
);
86 static inline BmpDecoder
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
88 return CONTAINING_RECORD(iface
, BmpDecoder
, IWICBitmapFrameDecode_iface
);
91 static HRESULT WINAPI
BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
94 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
96 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
98 if (!ppv
) return E_INVALIDARG
;
100 if (IsEqualIID(&IID_IUnknown
, iid
) ||
101 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
102 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
104 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
109 return E_NOINTERFACE
;
112 IUnknown_AddRef((IUnknown
*)*ppv
);
116 static ULONG WINAPI
BmpFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
118 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
120 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
123 static ULONG WINAPI
BmpFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
125 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
127 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
130 static HRESULT WINAPI
BmpFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
131 UINT
*puiWidth
, UINT
*puiHeight
)
133 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
134 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
136 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
138 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
139 *puiWidth
= bch
->bcWidth
;
140 *puiHeight
= bch
->bcHeight
;
144 *puiWidth
= This
->bih
.bV5Width
;
145 *puiHeight
= abs(This
->bih
.bV5Height
);
150 static HRESULT WINAPI
BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
151 WICPixelFormatGUID
*pPixelFormat
)
153 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
154 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
156 memcpy(pPixelFormat
, This
->pixelformat
, sizeof(GUID
));
161 static HRESULT
BmpHeader_GetResolution(BITMAPV5HEADER
*bih
, double *pDpiX
, double *pDpiY
)
163 LONG resx
= 0, resy
= 0;
165 switch (bih
->bV5Size
)
168 case sizeof(BITMAPCOREHEADER
):
171 case sizeof(BITMAPCOREHEADER2
):
172 case sizeof(BITMAPINFOHEADER
):
173 case sizeof(BITMAPV4HEADER
):
174 case sizeof(BITMAPV5HEADER
):
175 resx
= bih
->bV5XPelsPerMeter
;
176 resy
= bih
->bV5YPelsPerMeter
;
187 *pDpiX
= resx
* 0.0254;
188 *pDpiY
= resy
* 0.0254;
194 static HRESULT WINAPI
BmpFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
195 double *pDpiX
, double *pDpiY
)
197 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
198 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
200 return BmpHeader_GetResolution(&This
->bih
, pDpiX
, pDpiY
);
203 static HRESULT WINAPI
BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
204 IWICPalette
*pIPalette
)
207 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
209 WICColor
*wiccolors
=NULL
;
210 RGBTRIPLE
*bgrcolors
=NULL
;
212 TRACE("(%p,%p)\n", iface
, pIPalette
);
214 EnterCriticalSection(&This
->lock
);
216 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
218 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
219 if (bch
->bcBitCount
<= 8)
221 /* 2**n colors in BGR format after the header */
222 ULONG tablesize
, bytesread
;
223 LARGE_INTEGER offset
;
226 count
= 1 << bch
->bcBitCount
;
227 wiccolors
= malloc(sizeof(WICColor
) * count
);
228 tablesize
= sizeof(RGBTRIPLE
) * count
;
229 bgrcolors
= malloc(tablesize
);
230 if (!wiccolors
|| !bgrcolors
)
236 offset
.QuadPart
= This
->palette_offset
;
237 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
238 if (FAILED(hr
)) goto end
;
240 hr
= IStream_Read(This
->stream
, bgrcolors
, tablesize
, &bytesread
);
241 if (FAILED(hr
)) goto end
;
242 if (bytesread
!= tablesize
) {
247 for (i
=0; i
<count
; i
++)
249 wiccolors
[i
] = 0xff000000|
250 (bgrcolors
[i
].rgbtRed
<<16)|
251 (bgrcolors
[i
].rgbtGreen
<<8)|
252 bgrcolors
[i
].rgbtBlue
;
257 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
263 if (This
->bih
.bV5BitCount
<= 8)
265 ULONG tablesize
, bytesread
;
266 LARGE_INTEGER offset
;
269 if (This
->bih
.bV5ClrUsed
== 0)
270 count
= 1 << This
->bih
.bV5BitCount
;
272 count
= min(This
->bih
.bV5ClrUsed
, 1 << This
->bih
.bV5BitCount
);
274 tablesize
= sizeof(WICColor
) * count
;
275 wiccolors
= malloc(tablesize
);
282 offset
.QuadPart
= This
->palette_offset
;
283 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
284 if (FAILED(hr
)) goto end
;
286 hr
= IStream_Read(This
->stream
, wiccolors
, tablesize
, &bytesread
);
287 if (FAILED(hr
)) goto end
;
288 if (bytesread
!= tablesize
) {
293 /* convert from BGR to BGRA by setting alpha to 100% */
294 for (i
=0; i
<count
; i
++)
295 wiccolors
[i
] |= 0xff000000;
299 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
306 LeaveCriticalSection(&This
->lock
);
309 hr
= IWICPalette_InitializeCustom(pIPalette
, wiccolors
, count
);
316 static HRESULT WINAPI
BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
317 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
319 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
322 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
324 EnterCriticalSection(&This
->lock
);
325 if (!This
->imagedata
)
327 hr
= This
->read_data_func(This
);
329 LeaveCriticalSection(&This
->lock
);
330 if (FAILED(hr
)) return hr
;
332 hr
= BmpFrameDecode_GetSize(iface
, &width
, &height
);
333 if (FAILED(hr
)) return hr
;
335 return copy_pixels(This
->bitsperpixel
, This
->imagedatastart
,
336 width
, height
, This
->stride
,
337 prc
, cbStride
, cbBufferSize
, pbBuffer
);
340 static HRESULT WINAPI
BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
341 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
343 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
344 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
347 static HRESULT WINAPI
BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
348 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
350 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
351 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
354 static HRESULT WINAPI
BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
355 IWICBitmapSource
**ppIThumbnail
)
357 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
358 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
361 static HRESULT
BmpFrameDecode_ReadUncompressed(BmpDecoder
* This
)
368 LARGE_INTEGER offbits
;
371 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
373 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
374 width
= bch
->bcWidth
;
375 height
= bch
->bcHeight
;
380 width
= This
->bih
.bV5Width
;
381 height
= abs(This
->bih
.bV5Height
);
382 bottomup
= (This
->bih
.bV5Height
> 0);
385 /* row sizes in BMP files must be divisible by 4 bytes */
386 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
387 datasize
= bytesperrow
* height
;
389 This
->imagedata
= malloc(datasize
);
390 if (!This
->imagedata
) return E_OUTOFMEMORY
;
392 offbits
.QuadPart
= This
->image_offset
;
393 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
394 if (FAILED(hr
)) goto fail
;
396 hr
= IStream_Read(This
->stream
, This
->imagedata
, datasize
, &bytesread
);
397 if (FAILED(hr
) || bytesread
!= datasize
) goto fail
;
401 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
402 This
->stride
= -bytesperrow
;
406 This
->imagedatastart
= This
->imagedata
;
407 This
->stride
= bytesperrow
;
412 free(This
->imagedata
);
413 This
->imagedata
= NULL
;
414 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
418 static HRESULT
BmpFrameDecode_ReadABGRasBGR(BmpDecoder
* This
)
420 UINT x
, y
, width
, height
;
424 hr
= IWICBitmapFrameDecode_GetSize(&This
->IWICBitmapFrameDecode_iface
, &width
, &height
);
428 hr
= BmpFrameDecode_ReadUncompressed(This
);
433 for (y
= 0; y
< height
; y
++)
435 pixel
= This
->imagedatastart
+ This
->stride
* (INT
)y
;
437 for (x
= 0; x
< width
; x
++)
451 static HRESULT
BmpFrameDecode_ReadRGB8(BmpDecoder
* This
)
456 hr
= IWICBitmapFrameDecode_GetSize(&This
->IWICBitmapFrameDecode_iface
, &width
, &height
);
460 hr
= BmpFrameDecode_ReadUncompressed(This
);
465 reverse_bgr8(This
->bitsperpixel
/8, This
->imagedatastart
,
466 width
, height
, This
->stride
);
472 static HRESULT
ReadByte(IStream
*stream
, BYTE
*buffer
, ULONG buffer_size
,
473 ULONG
*cursor
, ULONG
*bytesread
, BYTE
*result
)
477 if (*bytesread
== 0 || *cursor
== *bytesread
)
479 hr
= IStream_Read(stream
, buffer
, buffer_size
, bytesread
);
485 if (*cursor
< *bytesread
)
486 *result
= buffer
[(*cursor
)++];
494 static HRESULT
BmpFrameDecode_ReadRLE8(BmpDecoder
* This
)
499 UINT datasize
, palettesize
;
504 LARGE_INTEGER offbits
;
505 ULONG cursor
=0, bytesread
=0;
507 width
= This
->bih
.bV5Width
;
508 height
= abs(This
->bih
.bV5Height
);
509 bytesperrow
= width
* 4;
510 datasize
= bytesperrow
* height
;
511 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 256)
512 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
514 palettesize
= 4 * 256;
516 This
->imagedata
= malloc(datasize
);
517 if (!This
->imagedata
)
524 offbits
.QuadPart
= This
->palette_offset
;
525 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
526 if (FAILED(hr
)) goto fail
;
528 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
529 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
532 offbits
.QuadPart
= This
->image_offset
;
533 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
534 if (FAILED(hr
)) goto fail
;
537 bgrdata
= (DWORD
*)This
->imagedata
;
545 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
549 else if (length
== 0)
553 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
558 case 0: /* end of line */
562 case 1: /* end of bitmap */
567 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
569 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
576 default: /* absolute mode */
578 while (length
-- && x
< width
)
581 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
584 bgrdata
[y
*width
+ x
++] = palette
[index
];
587 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
596 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
599 color
= palette
[index
];
600 while (length
-- && x
< width
)
601 bgrdata
[y
*width
+ x
++] = color
;
606 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
607 This
->stride
= -bytesperrow
;
612 free(This
->imagedata
);
613 This
->imagedata
= NULL
;
614 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
618 static HRESULT
BmpFrameDecode_ReadRLE4(BmpDecoder
* This
)
623 UINT datasize
, palettesize
;
628 LARGE_INTEGER offbits
;
629 ULONG cursor
=0, bytesread
=0;
631 width
= This
->bih
.bV5Width
;
632 height
= abs(This
->bih
.bV5Height
);
633 bytesperrow
= width
* 4;
634 datasize
= bytesperrow
* height
;
635 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 16)
636 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
638 palettesize
= 4 * 16;
640 This
->imagedata
= malloc(datasize
);
641 if (!This
->imagedata
)
648 offbits
.QuadPart
= This
->palette_offset
;
649 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
650 if (FAILED(hr
)) goto fail
;
652 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
653 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
656 offbits
.QuadPart
= This
->image_offset
;
657 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
658 if (FAILED(hr
)) goto fail
;
661 bgrdata
= (DWORD
*)This
->imagedata
;
669 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
673 else if (length
== 0)
677 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
682 case 0: /* end of line */
686 case 1: /* end of bitmap */
691 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
693 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
700 default: /* absolute mode */
704 while (length
-- && x
< width
)
707 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
711 bgrdata
[y
*width
+ x
++] = palette
[colors
>>4];
712 if (length
-- && x
< width
)
713 bgrdata
[y
*width
+ x
++] = palette
[colors
&0xf];
718 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
729 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
732 color1
= palette
[colors
>>4];
733 color2
= palette
[colors
&0xf];
734 while (length
-- && x
< width
)
736 bgrdata
[y
*width
+ x
++] = color1
;
737 if (length
-- && x
< width
)
738 bgrdata
[y
*width
+ x
++] = color2
;
746 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
747 This
->stride
= -bytesperrow
;
752 free(This
->imagedata
);
753 This
->imagedata
= NULL
;
754 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
758 static HRESULT
BmpFrameDecode_ReadUnsupported(BmpDecoder
* This
)
763 struct bitfields_format
{
764 WORD bitcount
; /* 0 for end of list */
769 const WICPixelFormatGUID
*pixelformat
;
770 ReadDataFunc read_data_func
;
773 static const struct bitfields_format bitfields_formats
[] = {
774 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555
,BmpFrameDecode_ReadUncompressed
},
775 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565
,BmpFrameDecode_ReadUncompressed
},
776 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadUncompressed
},
777 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA
,BmpFrameDecode_ReadUncompressed
},
778 {32,0xff000000,0xff0000,0xff00,0xff,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadABGRasBGR
},
779 {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadRGB8
},
783 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl
= {
784 BmpFrameDecode_QueryInterface
,
785 BmpFrameDecode_AddRef
,
786 BmpFrameDecode_Release
,
787 BmpFrameDecode_GetSize
,
788 BmpFrameDecode_GetPixelFormat
,
789 BmpFrameDecode_GetResolution
,
790 BmpFrameDecode_CopyPalette
,
791 BmpFrameDecode_CopyPixels
,
792 BmpFrameDecode_GetMetadataQueryReader
,
793 BmpFrameDecode_GetColorContexts
,
794 BmpFrameDecode_GetThumbnail
797 static HRESULT
BmpDecoder_ReadHeaders(BmpDecoder
* This
, IStream
*stream
)
800 ULONG bytestoread
, bytesread
;
803 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
806 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, NULL
);
807 if (FAILED(hr
)) return hr
;
811 BITMAPFILEHEADER bfh
;
812 hr
= IStream_Read(stream
, &bfh
, sizeof(BITMAPFILEHEADER
), &bytesread
);
813 if (FAILED(hr
)) return hr
;
814 if (bytesread
!= sizeof(BITMAPFILEHEADER
) ||
815 bfh
.bfType
!= 0x4d42 /* "BM" */) return E_FAIL
;
816 This
->image_offset
= bfh
.bfOffBits
;
819 hr
= IStream_Read(stream
, &This
->bih
.bV5Size
, sizeof(DWORD
), &bytesread
);
820 if (FAILED(hr
)) return hr
;
821 if (bytesread
!= sizeof(DWORD
) ||
822 (This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER
) &&
823 This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER2
) &&
824 This
->bih
.bV5Size
!= sizeof(BITMAPINFOHEADER
) &&
825 This
->bih
.bV5Size
!= sizeof(BITMAPV4HEADER
) &&
826 This
->bih
.bV5Size
!= sizeof(BITMAPV5HEADER
))) return E_FAIL
;
828 bytestoread
= This
->bih
.bV5Size
-sizeof(DWORD
);
829 hr
= IStream_Read(stream
, &This
->bih
.bV5Width
, bytestoread
, &bytesread
);
830 if (FAILED(hr
)) return hr
;
831 if (bytestoread
!= bytesread
) return E_FAIL
;
834 This
->palette_offset
= This
->bih
.bV5Size
;
836 This
->palette_offset
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
840 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
842 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
847 This
->bih
.bV5Height
/= 2;
851 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
852 read the extra fields */
853 if (This
->bih
.bV5Size
== sizeof(BITMAPINFOHEADER
) &&
854 This
->bih
.bV5Compression
== BI_BITFIELDS
)
856 hr
= IStream_Read(stream
, &This
->bih
.bV5RedMask
, 12, &bytesread
);
857 if (FAILED(hr
)) return hr
;
858 if (bytesread
!= 12) return E_FAIL
;
859 This
->bih
.bV5AlphaMask
= 0;
860 This
->palette_offset
+= 12;
863 /* decide what kind of bitmap this is and how/if we can read it */
864 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
866 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
867 TRACE("BITMAPCOREHEADER with depth=%i\n", bch
->bcBitCount
);
868 This
->bitsperpixel
= bch
->bcBitCount
;
869 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
870 switch(bch
->bcBitCount
)
873 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
876 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
879 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
882 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
885 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
888 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
889 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch
->bcBitCount
);
893 else /* struct is compatible with BITMAPINFOHEADER */
895 TRACE("bitmap header=%li compression=%li depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
896 switch(This
->bih
.bV5Compression
)
899 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
900 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
901 switch(This
->bih
.bV5BitCount
)
904 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
907 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
910 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
913 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
916 This
->pixelformat
= &GUID_WICPixelFormat16bppBGR555
;
919 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
922 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
925 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
926 FIXME("unsupported bit depth %i for uncompressed RGB\n", This
->bih
.bV5BitCount
);
930 This
->bitsperpixel
= 32;
931 This
->read_data_func
= BmpFrameDecode_ReadRLE8
;
932 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
935 This
->bitsperpixel
= 32;
936 This
->read_data_func
= BmpFrameDecode_ReadRLE4
;
937 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
941 const struct bitfields_format
*format
;
942 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER2
))
944 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
945 This
->bitsperpixel
= 0;
946 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
947 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
948 FIXME("Huffman 1D compression is unsupported\n");
951 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
952 for (format
= bitfields_formats
; format
->bitcount
; format
++)
954 if ((format
->bitcount
== This
->bih
.bV5BitCount
) &&
955 (format
->redmask
== This
->bih
.bV5RedMask
) &&
956 (format
->greenmask
== This
->bih
.bV5GreenMask
) &&
957 (format
->bluemask
== This
->bih
.bV5BlueMask
) &&
958 (format
->alphamask
== This
->bih
.bV5AlphaMask
))
960 This
->read_data_func
= format
->read_data_func
;
961 This
->pixelformat
= format
->pixelformat
;
965 if (!format
->bitcount
)
967 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
968 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
969 FIXME("unsupported bitfields type depth=%i red=%lx green=%lx blue=%lx alpha=%lx\n",
970 This
->bih
.bV5BitCount
, This
->bih
.bV5RedMask
, This
->bih
.bV5GreenMask
, This
->bih
.bV5BlueMask
, This
->bih
.bV5AlphaMask
);
975 This
->bitsperpixel
= 0;
976 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
977 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
978 FIXME("unsupported bitmap type header=%li compression=%li depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
985 /* In a packed DIB, the image follows the palette. */
986 ULONG palette_count
, palette_size
;
987 if (This
->bih
.bV5ClrUsed
)
988 palette_count
= This
->bih
.bV5ClrUsed
;
989 else if (This
->bih
.bV5BitCount
<= 8)
990 palette_count
= 1 << This
->bih
.bV5BitCount
;
993 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
994 palette_size
= sizeof(RGBTRIPLE
) * palette_count
;
996 palette_size
= sizeof(RGBQUAD
) * palette_count
;
997 This
->image_offset
= This
->palette_offset
+ palette_size
;
1000 This
->initialized
= TRUE
;
1005 static HRESULT WINAPI
BmpDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1008 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1009 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1011 if (!ppv
) return E_INVALIDARG
;
1013 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1014 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1016 *ppv
= &This
->IWICBitmapDecoder_iface
;
1021 return E_NOINTERFACE
;
1024 IUnknown_AddRef((IUnknown
*)*ppv
);
1028 static ULONG WINAPI
BmpDecoder_AddRef(IWICBitmapDecoder
*iface
)
1030 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1031 ULONG ref
= InterlockedIncrement(&This
->ref
);
1033 TRACE("(%p) refcount=%lu\n", iface
, ref
);
1038 static ULONG WINAPI
BmpDecoder_Release(IWICBitmapDecoder
*iface
)
1040 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1041 ULONG ref
= InterlockedDecrement(&This
->ref
);
1043 TRACE("(%p) refcount=%lu\n", iface
, ref
);
1047 if (This
->stream
) IStream_Release(This
->stream
);
1048 free(This
->imagedata
);
1049 This
->lock
.DebugInfo
->Spare
[0] = 0;
1050 DeleteCriticalSection(&This
->lock
);
1057 static HRESULT WINAPI
BmpDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1061 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1063 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1065 if (!stream
|| !capability
) return E_INVALIDARG
;
1067 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1068 if (hr
!= S_OK
) return hr
;
1070 *capability
= This
->read_data_func
== BmpFrameDecode_ReadUnsupported
? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages
;
1074 static HRESULT WINAPI
BmpDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1075 WICDecodeOptions cacheOptions
)
1078 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1080 EnterCriticalSection(&This
->lock
);
1081 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
1085 This
->stream
= pIStream
;
1086 IStream_AddRef(pIStream
);
1088 LeaveCriticalSection(&This
->lock
);
1093 static HRESULT WINAPI
BmpDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1094 GUID
*pguidContainerFormat
)
1096 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
1100 static HRESULT WINAPI
BmpDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1101 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1103 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1105 return get_decoder_info(&CLSID_WICBmpDecoder
, ppIDecoderInfo
);
1108 static HRESULT WINAPI
BmpDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1109 IWICPalette
*pIPalette
)
1111 TRACE("(%p,%p)\n", iface
, pIPalette
);
1113 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1116 static HRESULT WINAPI
BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1117 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1119 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1120 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1123 static HRESULT WINAPI
BmpDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1124 IWICBitmapSource
**ppIBitmapSource
)
1126 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1127 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1130 static HRESULT WINAPI
BmpDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1131 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1133 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1134 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1137 static HRESULT WINAPI
BmpDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1138 IWICBitmapSource
**ppIThumbnail
)
1140 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1141 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1144 static HRESULT WINAPI
BmpDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1147 if (!pCount
) return E_INVALIDARG
;
1153 static HRESULT WINAPI
BmpDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1154 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1156 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1158 if (index
!= 0) return E_INVALIDARG
;
1160 if (!This
->stream
) return WINCODEC_ERR_FRAMEMISSING
;
1162 *ppIBitmapFrame
= &This
->IWICBitmapFrameDecode_iface
;
1163 IWICBitmapDecoder_AddRef(iface
);
1168 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl
= {
1169 BmpDecoder_QueryInterface
,
1172 BmpDecoder_QueryCapability
,
1173 BmpDecoder_Initialize
,
1174 BmpDecoder_GetContainerFormat
,
1175 BmpDecoder_GetDecoderInfo
,
1176 BmpDecoder_CopyPalette
,
1177 BmpDecoder_GetMetadataQueryReader
,
1178 BmpDecoder_GetPreview
,
1179 BmpDecoder_GetColorContexts
,
1180 BmpDecoder_GetThumbnail
,
1181 BmpDecoder_GetFrameCount
,
1185 static HRESULT
BmpDecoder_Create(int packed
, int icoframe
, BmpDecoder
**ppDecoder
)
1189 This
= malloc(sizeof(BmpDecoder
));
1190 if (!This
) return E_OUTOFMEMORY
;
1192 This
->IWICBitmapDecoder_iface
.lpVtbl
= &BmpDecoder_Vtbl
;
1193 This
->IWICBitmapFrameDecode_iface
.lpVtbl
= &BmpDecoder_FrameVtbl
;
1195 This
->initialized
= FALSE
;
1196 This
->stream
= NULL
;
1197 This
->imagedata
= NULL
;
1198 InitializeCriticalSectionEx(&This
->lock
, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO
);
1199 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BmpDecoder.lock");
1200 This
->packed
= packed
;
1201 This
->icoframe
= icoframe
;
1208 static HRESULT
BmpDecoder_Construct(int packed
, int icoframe
, REFIID iid
, void** ppv
)
1213 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1217 ret
= BmpDecoder_Create(packed
, icoframe
, &This
);
1218 if (FAILED(ret
)) return ret
;
1220 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1221 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1226 HRESULT
BmpDecoder_CreateInstance(REFIID iid
, void** ppv
)
1228 return BmpDecoder_Construct(FALSE
, FALSE
, iid
, ppv
);
1231 HRESULT
DibDecoder_CreateInstance(REFIID iid
, void** ppv
)
1233 return BmpDecoder_Construct(TRUE
, FALSE
, iid
, ppv
);
1236 HRESULT
IcoDibDecoder_CreateInstance(BmpDecoder
**ppDecoder
)
1238 return BmpDecoder_Create(TRUE
, TRUE
, ppDecoder
);
1241 void BmpDecoder_GetWICDecoder(BmpDecoder
*This
, IWICBitmapDecoder
**ppDecoder
)
1243 *ppDecoder
= &This
->IWICBitmapDecoder_iface
;
1246 /* Return the offset where the mask of an icon might be, or 0 for failure. */
1247 void BmpDecoder_FindIconMask(BmpDecoder
*This
, ULONG
*mask_offset
, int *topdown
)
1249 assert(This
->stream
!= NULL
);
1251 if (This
->read_data_func
== BmpFrameDecode_ReadUncompressed
)
1253 /* RGB or BITFIELDS data */
1255 ULONG bytesperrow
, datasize
;
1256 IWICBitmapFrameDecode_GetSize(&This
->IWICBitmapFrameDecode_iface
, &width
, &height
);
1257 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
1258 datasize
= bytesperrow
* height
;
1259 *mask_offset
= This
->image_offset
+ datasize
;
1264 *topdown
= This
->stride
> 0;