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
33 #include "wincodecs_private.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
50 DWORD bc2ClrImportant
;
51 /* same as BITMAPINFOHEADER until this point */
56 DWORD bc2HalftoneSize1
;
57 DWORD bc2HalftoneSize2
;
62 typedef HRESULT (*ReadDataFunc
)(BmpDecoder
* This
);
65 const IWICBitmapDecoderVtbl
*lpVtbl
;
66 const IWICBitmapFrameDecodeVtbl
*lpFrameVtbl
;
73 const WICPixelFormatGUID
*pixelformat
;
75 ReadDataFunc read_data_func
;
79 CRITICAL_SECTION lock
; /* must be held when initialized/imagedata is set or stream is accessed */
80 int packed
; /* If TRUE, don't look for a file header and assume a packed DIB. */
81 int icoframe
; /* If TRUE, this is a frame of a .ico file. */
84 static inline BmpDecoder
*impl_from_frame(IWICBitmapFrameDecode
*iface
)
86 return CONTAINING_RECORD(iface
, BmpDecoder
, lpFrameVtbl
);
89 static HRESULT WINAPI
BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
92 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
94 if (!ppv
) return E_INVALIDARG
;
96 if (IsEqualIID(&IID_IUnknown
, iid
) ||
97 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
98 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
105 return E_NOINTERFACE
;
108 IUnknown_AddRef((IUnknown
*)*ppv
);
112 static ULONG WINAPI
BmpFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
114 BmpDecoder
*This
= impl_from_frame(iface
);
116 return IUnknown_AddRef((IUnknown
*)This
);
119 static ULONG WINAPI
BmpFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
121 BmpDecoder
*This
= impl_from_frame(iface
);
123 return IUnknown_Release((IUnknown
*)This
);
126 static HRESULT WINAPI
BmpFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
127 UINT
*puiWidth
, UINT
*puiHeight
)
129 BmpDecoder
*This
= impl_from_frame(iface
);
130 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
132 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
134 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
135 *puiWidth
= bch
->bcWidth
;
136 *puiHeight
= bch
->bcHeight
;
140 *puiWidth
= This
->bih
.bV5Width
;
141 *puiHeight
= abs(This
->bih
.bV5Height
);
146 static HRESULT WINAPI
BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
147 WICPixelFormatGUID
*pPixelFormat
)
149 BmpDecoder
*This
= impl_from_frame(iface
);
150 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
152 memcpy(pPixelFormat
, This
->pixelformat
, sizeof(GUID
));
157 static HRESULT
BmpHeader_GetResolution(BITMAPV5HEADER
*bih
, double *pDpiX
, double *pDpiY
)
159 switch (bih
->bV5Size
)
161 case sizeof(BITMAPCOREHEADER
):
165 case sizeof(BITMAPCOREHEADER2
):
166 case sizeof(BITMAPINFOHEADER
):
167 case sizeof(BITMAPV4HEADER
):
168 case sizeof(BITMAPV5HEADER
):
169 *pDpiX
= bih
->bV5XPelsPerMeter
* 0.0254;
170 *pDpiY
= bih
->bV5YPelsPerMeter
* 0.0254;
177 static HRESULT WINAPI
BmpFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
178 double *pDpiX
, double *pDpiY
)
180 BmpDecoder
*This
= impl_from_frame(iface
);
181 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
183 return BmpHeader_GetResolution(&This
->bih
, pDpiX
, pDpiY
);
186 static HRESULT WINAPI
BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
187 IWICPalette
*pIPalette
)
190 BmpDecoder
*This
= impl_from_frame(iface
);
192 WICColor
*wiccolors
=NULL
;
193 RGBTRIPLE
*bgrcolors
=NULL
;
195 TRACE("(%p,%p)\n", iface
, pIPalette
);
197 EnterCriticalSection(&This
->lock
);
199 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
201 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
202 if (bch
->bcBitCount
<= 8)
204 /* 2**n colors in BGR format after the header */
205 ULONG tablesize
, bytesread
;
206 LARGE_INTEGER offset
;
209 count
= 1 << bch
->bcBitCount
;
210 wiccolors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * count
);
211 tablesize
= sizeof(RGBTRIPLE
) * count
;
212 bgrcolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
213 if (!wiccolors
|| !bgrcolors
)
219 offset
.QuadPart
= This
->palette_offset
;
220 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
221 if (FAILED(hr
)) goto end
;
223 hr
= IStream_Read(This
->stream
, bgrcolors
, tablesize
, &bytesread
);
224 if (FAILED(hr
)) goto end
;
225 if (bytesread
!= tablesize
) {
230 for (i
=0; i
<count
; i
++)
232 wiccolors
[i
] = 0xff000000|
233 (bgrcolors
[i
].rgbtRed
<<16)|
234 (bgrcolors
[i
].rgbtGreen
<<8)|
235 bgrcolors
[i
].rgbtBlue
;
240 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
246 if (This
->bih
.bV5BitCount
<= 8)
248 ULONG tablesize
, bytesread
;
249 LARGE_INTEGER offset
;
252 if (This
->bih
.bV5ClrUsed
== 0)
253 count
= 1 << This
->bih
.bV5BitCount
;
255 count
= This
->bih
.bV5ClrUsed
;
257 tablesize
= sizeof(WICColor
) * count
;
258 wiccolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
265 offset
.QuadPart
= This
->palette_offset
;
266 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
267 if (FAILED(hr
)) goto end
;
269 hr
= IStream_Read(This
->stream
, wiccolors
, tablesize
, &bytesread
);
270 if (FAILED(hr
)) goto end
;
271 if (bytesread
!= tablesize
) {
276 /* convert from BGR to BGRA by setting alpha to 100% */
277 for (i
=0; i
<count
; i
++)
278 wiccolors
[i
] |= 0xff000000;
282 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
289 LeaveCriticalSection(&This
->lock
);
292 hr
= IWICPalette_InitializeCustom(pIPalette
, wiccolors
, count
);
294 HeapFree(GetProcessHeap(), 0, wiccolors
);
295 HeapFree(GetProcessHeap(), 0, bgrcolors
);
299 static HRESULT WINAPI
BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
300 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
302 BmpDecoder
*This
= impl_from_frame(iface
);
305 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
307 EnterCriticalSection(&This
->lock
);
308 if (!This
->imagedata
)
310 hr
= This
->read_data_func(This
);
312 LeaveCriticalSection(&This
->lock
);
313 if (FAILED(hr
)) return hr
;
315 hr
= BmpFrameDecode_GetSize(iface
, &width
, &height
);
316 if (FAILED(hr
)) return hr
;
318 return copy_pixels(This
->bitsperpixel
, This
->imagedatastart
,
319 width
, height
, This
->stride
,
320 prc
, cbStride
, cbBufferSize
, pbBuffer
);
323 static HRESULT WINAPI
BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
324 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
326 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
327 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
330 static HRESULT WINAPI
BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
331 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
333 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
334 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
337 static HRESULT WINAPI
BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
338 IWICBitmapSource
**ppIThumbnail
)
340 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
341 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
344 static HRESULT
BmpFrameDecode_ReadUncompressed(BmpDecoder
* This
)
351 LARGE_INTEGER offbits
;
354 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
356 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
357 width
= bch
->bcWidth
;
358 height
= bch
->bcHeight
;
363 width
= This
->bih
.bV5Width
;
364 height
= abs(This
->bih
.bV5Height
);
365 bottomup
= (This
->bih
.bV5Height
> 0);
368 /* row sizes in BMP files must be divisible by 4 bytes */
369 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
370 datasize
= bytesperrow
* height
;
372 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
373 if (!This
->imagedata
) return E_OUTOFMEMORY
;
375 offbits
.QuadPart
= This
->image_offset
;
376 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
377 if (FAILED(hr
)) goto fail
;
379 hr
= IStream_Read(This
->stream
, This
->imagedata
, datasize
, &bytesread
);
380 if (FAILED(hr
) || bytesread
!= datasize
) goto fail
;
384 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
385 This
->stride
= -bytesperrow
;
389 This
->imagedatastart
= This
->imagedata
;
390 This
->stride
= bytesperrow
;
395 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
396 This
->imagedata
= NULL
;
397 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
401 static HRESULT
BmpFrameDecode_ReadRGB8(BmpDecoder
* This
)
406 hr
= IWICBitmapFrameDecode_GetSize((IWICBitmapFrameDecode
*)&This
->lpFrameVtbl
, &width
, &height
);
410 hr
= BmpFrameDecode_ReadUncompressed(This
);
415 reverse_bgr8(This
->bitsperpixel
/8, This
->imagedatastart
,
416 width
, height
, This
->stride
);
422 static HRESULT
ReadByte(IStream
*stream
, BYTE
*buffer
, ULONG buffer_size
,
423 ULONG
*cursor
, ULONG
*bytesread
, BYTE
*result
)
427 if (*bytesread
== 0 || *cursor
== *bytesread
)
429 hr
= IStream_Read(stream
, buffer
, buffer_size
, bytesread
);
435 if (*cursor
< *bytesread
)
436 *result
= buffer
[(*cursor
)++];
444 static HRESULT
BmpFrameDecode_ReadRLE8(BmpDecoder
* This
)
449 UINT datasize
, palettesize
;
454 LARGE_INTEGER offbits
;
455 ULONG cursor
=0, bytesread
=0;
457 width
= This
->bih
.bV5Width
;
458 height
= abs(This
->bih
.bV5Height
);
459 bytesperrow
= width
* 4;
460 datasize
= bytesperrow
* height
;
461 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 256)
462 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
464 palettesize
= 4 * 256;
466 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
467 if (!This
->imagedata
)
474 offbits
.QuadPart
= This
->palette_offset
;
475 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
476 if (FAILED(hr
)) goto fail
;
478 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
479 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
482 offbits
.QuadPart
= This
->image_offset
;
483 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
484 if (FAILED(hr
)) goto fail
;
487 bgrdata
= (DWORD
*)This
->imagedata
;
495 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
499 else if (length
== 0)
503 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
508 case 0: /* end of line */
512 case 1: /* end of bitmap */
517 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
519 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
526 default: /* absolute mode */
528 while (length
-- && x
< width
)
531 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
534 bgrdata
[y
*width
+ x
++] = palette
[index
];
537 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
546 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
549 color
= palette
[index
];
550 while (length
-- && x
< width
)
551 bgrdata
[y
*width
+ x
++] = color
;
556 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
557 This
->stride
= -bytesperrow
;
562 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
563 This
->imagedata
= NULL
;
564 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
568 static HRESULT
BmpFrameDecode_ReadRLE4(BmpDecoder
* This
)
573 UINT datasize
, palettesize
;
578 LARGE_INTEGER offbits
;
579 ULONG cursor
=0, bytesread
=0;
581 width
= This
->bih
.bV5Width
;
582 height
= abs(This
->bih
.bV5Height
);
583 bytesperrow
= width
* 4;
584 datasize
= bytesperrow
* height
;
585 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 16)
586 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
588 palettesize
= 4 * 16;
590 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
591 if (!This
->imagedata
)
598 offbits
.QuadPart
= This
->palette_offset
;
599 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
600 if (FAILED(hr
)) goto fail
;
602 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
603 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
606 offbits
.QuadPart
= This
->image_offset
;
607 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
608 if (FAILED(hr
)) goto fail
;
611 bgrdata
= (DWORD
*)This
->imagedata
;
619 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
623 else if (length
== 0)
627 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
632 case 0: /* end of line */
636 case 1: /* end of bitmap */
641 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
643 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
650 default: /* absolute mode */
654 while (length
-- && x
< width
)
657 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
661 bgrdata
[y
*width
+ x
++] = palette
[colors
>>4];
662 if (length
-- && x
< width
)
663 bgrdata
[y
*width
+ x
++] = palette
[colors
&0xf];
668 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
679 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
682 color1
= palette
[colors
>>4];
683 color2
= palette
[colors
&0xf];
684 while (length
-- && x
< width
)
686 bgrdata
[y
*width
+ x
++] = color1
;
687 if (length
-- && x
< width
)
688 bgrdata
[y
*width
+ x
++] = color2
;
696 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
697 This
->stride
= -bytesperrow
;
702 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
703 This
->imagedata
= NULL
;
704 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
708 static HRESULT
BmpFrameDecode_ReadUnsupported(BmpDecoder
* This
)
713 struct bitfields_format
{
714 WORD bitcount
; /* 0 for end of list */
719 const WICPixelFormatGUID
*pixelformat
;
720 ReadDataFunc read_data_func
;
723 static const struct bitfields_format bitfields_formats
[] = {
724 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555
,BmpFrameDecode_ReadUncompressed
},
725 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565
,BmpFrameDecode_ReadUncompressed
},
726 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadUncompressed
},
727 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA
,BmpFrameDecode_ReadUncompressed
},
728 {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadRGB8
},
732 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl
= {
733 BmpFrameDecode_QueryInterface
,
734 BmpFrameDecode_AddRef
,
735 BmpFrameDecode_Release
,
736 BmpFrameDecode_GetSize
,
737 BmpFrameDecode_GetPixelFormat
,
738 BmpFrameDecode_GetResolution
,
739 BmpFrameDecode_CopyPalette
,
740 BmpFrameDecode_CopyPixels
,
741 BmpFrameDecode_GetMetadataQueryReader
,
742 BmpFrameDecode_GetColorContexts
,
743 BmpFrameDecode_GetThumbnail
746 static HRESULT
BmpDecoder_ReadHeaders(BmpDecoder
* This
, IStream
*stream
)
749 ULONG bytestoread
, bytesread
;
752 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
755 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, NULL
);
756 if (FAILED(hr
)) return hr
;
760 BITMAPFILEHEADER bfh
;
761 hr
= IStream_Read(stream
, &bfh
, sizeof(BITMAPFILEHEADER
), &bytesread
);
762 if (FAILED(hr
)) return hr
;
763 if (bytesread
!= sizeof(BITMAPFILEHEADER
) ||
764 bfh
.bfType
!= 0x4d42 /* "BM" */) return E_FAIL
;
765 This
->image_offset
= bfh
.bfOffBits
;
768 hr
= IStream_Read(stream
, &This
->bih
.bV5Size
, sizeof(DWORD
), &bytesread
);
769 if (FAILED(hr
)) return hr
;
770 if (bytesread
!= sizeof(DWORD
) ||
771 (This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER
) &&
772 This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER2
) &&
773 This
->bih
.bV5Size
!= sizeof(BITMAPINFOHEADER
) &&
774 This
->bih
.bV5Size
!= sizeof(BITMAPV4HEADER
) &&
775 This
->bih
.bV5Size
!= sizeof(BITMAPV5HEADER
))) return E_FAIL
;
777 bytestoread
= This
->bih
.bV5Size
-sizeof(DWORD
);
778 hr
= IStream_Read(stream
, &This
->bih
.bV5Width
, bytestoread
, &bytesread
);
779 if (FAILED(hr
)) return hr
;
780 if (bytestoread
!= bytesread
) return E_FAIL
;
783 This
->palette_offset
= This
->bih
.bV5Size
;
785 This
->palette_offset
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
789 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
791 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
796 This
->bih
.bV5Height
/= 2;
800 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
801 read the extra fields */
802 if (This
->bih
.bV5Size
== sizeof(BITMAPINFOHEADER
) &&
803 This
->bih
.bV5Compression
== BI_BITFIELDS
)
805 hr
= IStream_Read(stream
, &This
->bih
.bV5RedMask
, 12, &bytesread
);
806 if (FAILED(hr
)) return hr
;
807 if (bytesread
!= 12) return E_FAIL
;
808 This
->bih
.bV5AlphaMask
= 0;
809 This
->palette_offset
+= 12;
812 /* decide what kind of bitmap this is and how/if we can read it */
813 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
815 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
816 TRACE("BITMAPCOREHEADER with depth=%i\n", bch
->bcBitCount
);
817 This
->bitsperpixel
= bch
->bcBitCount
;
818 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
819 switch(bch
->bcBitCount
)
822 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
825 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
828 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
831 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
834 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
837 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
838 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch
->bcBitCount
);
842 else /* struct is compatible with BITMAPINFOHEADER */
844 TRACE("bitmap header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
845 switch(This
->bih
.bV5Compression
)
848 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
849 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
850 switch(This
->bih
.bV5BitCount
)
853 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
856 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
859 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
862 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
865 This
->pixelformat
= &GUID_WICPixelFormat16bppBGR555
;
868 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
871 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
874 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
875 FIXME("unsupported bit depth %i for uncompressed RGB\n", This
->bih
.bV5BitCount
);
879 This
->bitsperpixel
= 32;
880 This
->read_data_func
= BmpFrameDecode_ReadRLE8
;
881 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
884 This
->bitsperpixel
= 32;
885 This
->read_data_func
= BmpFrameDecode_ReadRLE4
;
886 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
890 const struct bitfields_format
*format
;
891 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER2
))
893 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
894 This
->bitsperpixel
= 0;
895 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
896 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
897 FIXME("Huffman 1D compression is unsupported\n");
900 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
901 for (format
= bitfields_formats
; format
->bitcount
; format
++)
903 if ((format
->bitcount
== This
->bih
.bV5BitCount
) &&
904 (format
->redmask
== This
->bih
.bV5RedMask
) &&
905 (format
->greenmask
== This
->bih
.bV5GreenMask
) &&
906 (format
->bluemask
== This
->bih
.bV5BlueMask
) &&
907 (format
->alphamask
== This
->bih
.bV5AlphaMask
))
909 This
->read_data_func
= format
->read_data_func
;
910 This
->pixelformat
= format
->pixelformat
;
914 if (!format
->bitcount
)
916 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
917 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
918 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
919 This
->bih
.bV5BitCount
, This
->bih
.bV5RedMask
, This
->bih
.bV5GreenMask
, This
->bih
.bV5BlueMask
, This
->bih
.bV5AlphaMask
);
924 This
->bitsperpixel
= 0;
925 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
926 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
927 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
934 /* In a packed DIB, the image follows the palette. */
935 ULONG palette_count
, palette_size
;
936 if (This
->bih
.bV5ClrUsed
)
937 palette_count
= This
->bih
.bV5ClrUsed
;
938 else if (This
->bih
.bV5BitCount
<= 8)
939 palette_count
= 1 << This
->bih
.bV5BitCount
;
942 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
943 palette_size
= sizeof(RGBTRIPLE
) * palette_count
;
945 palette_size
= sizeof(RGBQUAD
) * palette_count
;
946 This
->image_offset
= This
->palette_offset
+ palette_size
;
949 This
->initialized
= TRUE
;
954 static HRESULT WINAPI
BmpDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
957 BmpDecoder
*This
= (BmpDecoder
*)iface
;
958 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
960 if (!ppv
) return E_INVALIDARG
;
962 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
969 return E_NOINTERFACE
;
972 IUnknown_AddRef((IUnknown
*)*ppv
);
976 static ULONG WINAPI
BmpDecoder_AddRef(IWICBitmapDecoder
*iface
)
978 BmpDecoder
*This
= (BmpDecoder
*)iface
;
979 ULONG ref
= InterlockedIncrement(&This
->ref
);
981 TRACE("(%p) refcount=%u\n", iface
, ref
);
986 static ULONG WINAPI
BmpDecoder_Release(IWICBitmapDecoder
*iface
)
988 BmpDecoder
*This
= (BmpDecoder
*)iface
;
989 ULONG ref
= InterlockedDecrement(&This
->ref
);
991 TRACE("(%p) refcount=%u\n", iface
, ref
);
995 if (This
->stream
) IStream_Release(This
->stream
);
996 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
997 This
->lock
.DebugInfo
->Spare
[0] = 0;
998 DeleteCriticalSection(&This
->lock
);
999 HeapFree(GetProcessHeap(), 0, This
);
1005 static HRESULT WINAPI
BmpDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1006 DWORD
*pdwCapability
)
1009 BmpDecoder
*This
= (BmpDecoder
*)iface
;
1011 EnterCriticalSection(&This
->lock
);
1012 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
1013 LeaveCriticalSection(&This
->lock
);
1014 if (FAILED(hr
)) return hr
;
1016 if (This
->read_data_func
== BmpFrameDecode_ReadUnsupported
)
1019 *pdwCapability
= WICBitmapDecoderCapabilityCanDecodeAllImages
;
1024 static HRESULT WINAPI
BmpDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1025 WICDecodeOptions cacheOptions
)
1028 BmpDecoder
*This
= (BmpDecoder
*)iface
;
1030 EnterCriticalSection(&This
->lock
);
1031 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
1035 This
->stream
= pIStream
;
1036 IStream_AddRef(pIStream
);
1038 LeaveCriticalSection(&This
->lock
);
1043 static HRESULT WINAPI
BmpDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1044 GUID
*pguidContainerFormat
)
1046 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
1050 static HRESULT WINAPI
BmpDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1051 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1054 IWICComponentInfo
*compinfo
;
1056 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1058 hr
= CreateComponentInfo(&CLSID_WICBmpDecoder
, &compinfo
);
1059 if (FAILED(hr
)) return hr
;
1061 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1062 (void**)ppIDecoderInfo
);
1064 IWICComponentInfo_Release(compinfo
);
1069 static HRESULT WINAPI
BmpDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1070 IWICPalette
*pIPalette
)
1072 TRACE("(%p,%p)\n", iface
, pIPalette
);
1074 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1077 static HRESULT WINAPI
BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1078 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1080 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1081 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1084 static HRESULT WINAPI
BmpDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1085 IWICBitmapSource
**ppIBitmapSource
)
1087 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1088 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1091 static HRESULT WINAPI
BmpDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1092 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1094 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1095 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1098 static HRESULT WINAPI
BmpDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1099 IWICBitmapSource
**ppIThumbnail
)
1101 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1102 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1105 static HRESULT WINAPI
BmpDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1112 static HRESULT WINAPI
BmpDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1113 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1115 BmpDecoder
*This
= (BmpDecoder
*)iface
;
1117 if (index
!= 0) return E_INVALIDARG
;
1119 if (!This
->stream
) return WINCODEC_ERR_WRONGSTATE
;
1121 *ppIBitmapFrame
= (IWICBitmapFrameDecode
*)&This
->lpFrameVtbl
;
1122 IWICBitmapDecoder_AddRef(iface
);
1127 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl
= {
1128 BmpDecoder_QueryInterface
,
1131 BmpDecoder_QueryCapability
,
1132 BmpDecoder_Initialize
,
1133 BmpDecoder_GetContainerFormat
,
1134 BmpDecoder_GetDecoderInfo
,
1135 BmpDecoder_CopyPalette
,
1136 BmpDecoder_GetMetadataQueryReader
,
1137 BmpDecoder_GetPreview
,
1138 BmpDecoder_GetColorContexts
,
1139 BmpDecoder_GetThumbnail
,
1140 BmpDecoder_GetFrameCount
,
1144 static HRESULT
BmpDecoder_Create(int packed
, int icoframe
, BmpDecoder
**ppDecoder
)
1148 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder
));
1149 if (!This
) return E_OUTOFMEMORY
;
1151 This
->lpVtbl
= &BmpDecoder_Vtbl
;
1152 This
->lpFrameVtbl
= &BmpDecoder_FrameVtbl
;
1154 This
->initialized
= FALSE
;
1155 This
->stream
= NULL
;
1156 This
->imagedata
= NULL
;
1157 InitializeCriticalSection(&This
->lock
);
1158 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BmpDecoder.lock");
1159 This
->packed
= packed
;
1160 This
->icoframe
= icoframe
;
1167 static HRESULT
BmpDecoder_Construct(int packed
, int icoframe
, IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1172 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1176 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1178 ret
= BmpDecoder_Create(packed
, icoframe
, &This
);
1179 if (FAILED(ret
)) return ret
;
1181 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1182 IUnknown_Release((IUnknown
*)This
);
1187 HRESULT
BmpDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1189 return BmpDecoder_Construct(FALSE
, FALSE
, pUnkOuter
, iid
, ppv
);
1192 HRESULT
DibDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1194 return BmpDecoder_Construct(TRUE
, FALSE
, pUnkOuter
, iid
, ppv
);
1197 HRESULT
IcoDibDecoder_CreateInstance(BmpDecoder
**ppDecoder
)
1199 return BmpDecoder_Create(TRUE
, TRUE
, ppDecoder
);
1202 void BmpDecoder_GetWICDecoder(BmpDecoder
*This
, IWICBitmapDecoder
**ppDecoder
)
1204 *ppDecoder
= (IWICBitmapDecoder
*)This
;
1207 /* Return the offset where the mask of an icon might be, or 0 for failure. */
1208 void BmpDecoder_FindIconMask(BmpDecoder
*This
, ULONG
*mask_offset
, int *topdown
)
1210 assert(This
->stream
!= NULL
);
1212 if (This
->read_data_func
== BmpFrameDecode_ReadUncompressed
)
1214 /* RGB or BITFIELDS data */
1215 ULONG width
, height
, bytesperrow
, datasize
;
1216 IWICBitmapFrameDecode_GetSize((IWICBitmapFrameDecode
*)&This
->lpFrameVtbl
, &width
, &height
);
1217 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
1218 datasize
= bytesperrow
* height
;
1219 *mask_offset
= This
->image_offset
+ datasize
;
1224 *topdown
= This
->stride
> 0;