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 IWICBitmapDecoder IWICBitmapDecoder_iface
;
66 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
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_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
86 return CONTAINING_RECORD(iface
, BmpDecoder
, IWICBitmapDecoder_iface
);
89 static inline BmpDecoder
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
91 return CONTAINING_RECORD(iface
, BmpDecoder
, IWICBitmapFrameDecode_iface
);
94 static HRESULT WINAPI
BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
97 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
99 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
101 if (!ppv
) return E_INVALIDARG
;
103 if (IsEqualIID(&IID_IUnknown
, iid
) ||
104 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
105 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
107 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
112 return E_NOINTERFACE
;
115 IUnknown_AddRef((IUnknown
*)*ppv
);
119 static ULONG WINAPI
BmpFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
121 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
123 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
126 static ULONG WINAPI
BmpFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
128 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
130 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
133 static HRESULT WINAPI
BmpFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
134 UINT
*puiWidth
, UINT
*puiHeight
)
136 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
137 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
139 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
141 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
142 *puiWidth
= bch
->bcWidth
;
143 *puiHeight
= bch
->bcHeight
;
147 *puiWidth
= This
->bih
.bV5Width
;
148 *puiHeight
= abs(This
->bih
.bV5Height
);
153 static HRESULT WINAPI
BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
154 WICPixelFormatGUID
*pPixelFormat
)
156 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
157 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
159 memcpy(pPixelFormat
, This
->pixelformat
, sizeof(GUID
));
164 static HRESULT
BmpHeader_GetResolution(BITMAPV5HEADER
*bih
, double *pDpiX
, double *pDpiY
)
166 switch (bih
->bV5Size
)
168 case sizeof(BITMAPCOREHEADER
):
172 case sizeof(BITMAPCOREHEADER2
):
173 case sizeof(BITMAPINFOHEADER
):
174 case sizeof(BITMAPV4HEADER
):
175 case sizeof(BITMAPV5HEADER
):
176 *pDpiX
= bih
->bV5XPelsPerMeter
* 0.0254;
177 *pDpiY
= bih
->bV5YPelsPerMeter
* 0.0254;
184 static HRESULT WINAPI
BmpFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
185 double *pDpiX
, double *pDpiY
)
187 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
188 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
190 return BmpHeader_GetResolution(&This
->bih
, pDpiX
, pDpiY
);
193 static HRESULT WINAPI
BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
194 IWICPalette
*pIPalette
)
197 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
199 WICColor
*wiccolors
=NULL
;
200 RGBTRIPLE
*bgrcolors
=NULL
;
202 TRACE("(%p,%p)\n", iface
, pIPalette
);
204 EnterCriticalSection(&This
->lock
);
206 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
208 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
209 if (bch
->bcBitCount
<= 8)
211 /* 2**n colors in BGR format after the header */
212 ULONG tablesize
, bytesread
;
213 LARGE_INTEGER offset
;
216 count
= 1 << bch
->bcBitCount
;
217 wiccolors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * count
);
218 tablesize
= sizeof(RGBTRIPLE
) * count
;
219 bgrcolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
220 if (!wiccolors
|| !bgrcolors
)
226 offset
.QuadPart
= This
->palette_offset
;
227 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
228 if (FAILED(hr
)) goto end
;
230 hr
= IStream_Read(This
->stream
, bgrcolors
, tablesize
, &bytesread
);
231 if (FAILED(hr
)) goto end
;
232 if (bytesread
!= tablesize
) {
237 for (i
=0; i
<count
; i
++)
239 wiccolors
[i
] = 0xff000000|
240 (bgrcolors
[i
].rgbtRed
<<16)|
241 (bgrcolors
[i
].rgbtGreen
<<8)|
242 bgrcolors
[i
].rgbtBlue
;
247 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
253 if (This
->bih
.bV5BitCount
<= 8)
255 ULONG tablesize
, bytesread
;
256 LARGE_INTEGER offset
;
259 if (This
->bih
.bV5ClrUsed
== 0)
260 count
= 1 << This
->bih
.bV5BitCount
;
262 count
= This
->bih
.bV5ClrUsed
;
264 tablesize
= sizeof(WICColor
) * count
;
265 wiccolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
272 offset
.QuadPart
= This
->palette_offset
;
273 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
274 if (FAILED(hr
)) goto end
;
276 hr
= IStream_Read(This
->stream
, wiccolors
, tablesize
, &bytesread
);
277 if (FAILED(hr
)) goto end
;
278 if (bytesread
!= tablesize
) {
283 /* convert from BGR to BGRA by setting alpha to 100% */
284 for (i
=0; i
<count
; i
++)
285 wiccolors
[i
] |= 0xff000000;
289 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
296 LeaveCriticalSection(&This
->lock
);
299 hr
= IWICPalette_InitializeCustom(pIPalette
, wiccolors
, count
);
301 HeapFree(GetProcessHeap(), 0, wiccolors
);
302 HeapFree(GetProcessHeap(), 0, bgrcolors
);
306 static HRESULT WINAPI
BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
307 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
309 BmpDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
312 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
314 EnterCriticalSection(&This
->lock
);
315 if (!This
->imagedata
)
317 hr
= This
->read_data_func(This
);
319 LeaveCriticalSection(&This
->lock
);
320 if (FAILED(hr
)) return hr
;
322 hr
= BmpFrameDecode_GetSize(iface
, &width
, &height
);
323 if (FAILED(hr
)) return hr
;
325 return copy_pixels(This
->bitsperpixel
, This
->imagedatastart
,
326 width
, height
, This
->stride
,
327 prc
, cbStride
, cbBufferSize
, pbBuffer
);
330 static HRESULT WINAPI
BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
331 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
333 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
334 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
337 static HRESULT WINAPI
BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
338 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
340 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
341 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
344 static HRESULT WINAPI
BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
345 IWICBitmapSource
**ppIThumbnail
)
347 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
348 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
351 static HRESULT
BmpFrameDecode_ReadUncompressed(BmpDecoder
* This
)
358 LARGE_INTEGER offbits
;
361 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
363 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
364 width
= bch
->bcWidth
;
365 height
= bch
->bcHeight
;
370 width
= This
->bih
.bV5Width
;
371 height
= abs(This
->bih
.bV5Height
);
372 bottomup
= (This
->bih
.bV5Height
> 0);
375 /* row sizes in BMP files must be divisible by 4 bytes */
376 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
377 datasize
= bytesperrow
* height
;
379 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
380 if (!This
->imagedata
) return E_OUTOFMEMORY
;
382 offbits
.QuadPart
= This
->image_offset
;
383 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
384 if (FAILED(hr
)) goto fail
;
386 hr
= IStream_Read(This
->stream
, This
->imagedata
, datasize
, &bytesread
);
387 if (FAILED(hr
) || bytesread
!= datasize
) goto fail
;
391 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
392 This
->stride
= -bytesperrow
;
396 This
->imagedatastart
= This
->imagedata
;
397 This
->stride
= bytesperrow
;
402 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
403 This
->imagedata
= NULL
;
404 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
408 static HRESULT
BmpFrameDecode_ReadRGB8(BmpDecoder
* This
)
413 hr
= IWICBitmapFrameDecode_GetSize(&This
->IWICBitmapFrameDecode_iface
, &width
, &height
);
417 hr
= BmpFrameDecode_ReadUncompressed(This
);
422 reverse_bgr8(This
->bitsperpixel
/8, This
->imagedatastart
,
423 width
, height
, This
->stride
);
429 static HRESULT
ReadByte(IStream
*stream
, BYTE
*buffer
, ULONG buffer_size
,
430 ULONG
*cursor
, ULONG
*bytesread
, BYTE
*result
)
434 if (*bytesread
== 0 || *cursor
== *bytesread
)
436 hr
= IStream_Read(stream
, buffer
, buffer_size
, bytesread
);
442 if (*cursor
< *bytesread
)
443 *result
= buffer
[(*cursor
)++];
451 static HRESULT
BmpFrameDecode_ReadRLE8(BmpDecoder
* This
)
456 UINT datasize
, palettesize
;
461 LARGE_INTEGER offbits
;
462 ULONG cursor
=0, bytesread
=0;
464 width
= This
->bih
.bV5Width
;
465 height
= abs(This
->bih
.bV5Height
);
466 bytesperrow
= width
* 4;
467 datasize
= bytesperrow
* height
;
468 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 256)
469 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
471 palettesize
= 4 * 256;
473 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
474 if (!This
->imagedata
)
481 offbits
.QuadPart
= This
->palette_offset
;
482 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
483 if (FAILED(hr
)) goto fail
;
485 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
486 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
489 offbits
.QuadPart
= This
->image_offset
;
490 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
491 if (FAILED(hr
)) goto fail
;
494 bgrdata
= (DWORD
*)This
->imagedata
;
502 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
506 else if (length
== 0)
510 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
515 case 0: /* end of line */
519 case 1: /* end of bitmap */
524 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
526 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
533 default: /* absolute mode */
535 while (length
-- && x
< width
)
538 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
541 bgrdata
[y
*width
+ x
++] = palette
[index
];
544 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
553 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
556 color
= palette
[index
];
557 while (length
-- && x
< width
)
558 bgrdata
[y
*width
+ x
++] = color
;
563 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
564 This
->stride
= -bytesperrow
;
569 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
570 This
->imagedata
= NULL
;
571 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
575 static HRESULT
BmpFrameDecode_ReadRLE4(BmpDecoder
* This
)
580 UINT datasize
, palettesize
;
585 LARGE_INTEGER offbits
;
586 ULONG cursor
=0, bytesread
=0;
588 width
= This
->bih
.bV5Width
;
589 height
= abs(This
->bih
.bV5Height
);
590 bytesperrow
= width
* 4;
591 datasize
= bytesperrow
* height
;
592 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 16)
593 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
595 palettesize
= 4 * 16;
597 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
598 if (!This
->imagedata
)
605 offbits
.QuadPart
= This
->palette_offset
;
606 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
607 if (FAILED(hr
)) goto fail
;
609 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
610 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
613 offbits
.QuadPart
= This
->image_offset
;
614 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
615 if (FAILED(hr
)) goto fail
;
618 bgrdata
= (DWORD
*)This
->imagedata
;
626 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
630 else if (length
== 0)
634 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
639 case 0: /* end of line */
643 case 1: /* end of bitmap */
648 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
650 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
657 default: /* absolute mode */
661 while (length
-- && x
< width
)
664 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
668 bgrdata
[y
*width
+ x
++] = palette
[colors
>>4];
669 if (length
-- && x
< width
)
670 bgrdata
[y
*width
+ x
++] = palette
[colors
&0xf];
675 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
686 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
689 color1
= palette
[colors
>>4];
690 color2
= palette
[colors
&0xf];
691 while (length
-- && x
< width
)
693 bgrdata
[y
*width
+ x
++] = color1
;
694 if (length
-- && x
< width
)
695 bgrdata
[y
*width
+ x
++] = color2
;
703 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
704 This
->stride
= -bytesperrow
;
709 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
710 This
->imagedata
= NULL
;
711 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
715 static HRESULT
BmpFrameDecode_ReadUnsupported(BmpDecoder
* This
)
720 struct bitfields_format
{
721 WORD bitcount
; /* 0 for end of list */
726 const WICPixelFormatGUID
*pixelformat
;
727 ReadDataFunc read_data_func
;
730 static const struct bitfields_format bitfields_formats
[] = {
731 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555
,BmpFrameDecode_ReadUncompressed
},
732 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565
,BmpFrameDecode_ReadUncompressed
},
733 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadUncompressed
},
734 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA
,BmpFrameDecode_ReadUncompressed
},
735 {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadRGB8
},
739 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl
= {
740 BmpFrameDecode_QueryInterface
,
741 BmpFrameDecode_AddRef
,
742 BmpFrameDecode_Release
,
743 BmpFrameDecode_GetSize
,
744 BmpFrameDecode_GetPixelFormat
,
745 BmpFrameDecode_GetResolution
,
746 BmpFrameDecode_CopyPalette
,
747 BmpFrameDecode_CopyPixels
,
748 BmpFrameDecode_GetMetadataQueryReader
,
749 BmpFrameDecode_GetColorContexts
,
750 BmpFrameDecode_GetThumbnail
753 static HRESULT
BmpDecoder_ReadHeaders(BmpDecoder
* This
, IStream
*stream
)
756 ULONG bytestoread
, bytesread
;
759 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
762 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, NULL
);
763 if (FAILED(hr
)) return hr
;
767 BITMAPFILEHEADER bfh
;
768 hr
= IStream_Read(stream
, &bfh
, sizeof(BITMAPFILEHEADER
), &bytesread
);
769 if (FAILED(hr
)) return hr
;
770 if (bytesread
!= sizeof(BITMAPFILEHEADER
) ||
771 bfh
.bfType
!= 0x4d42 /* "BM" */) return E_FAIL
;
772 This
->image_offset
= bfh
.bfOffBits
;
775 hr
= IStream_Read(stream
, &This
->bih
.bV5Size
, sizeof(DWORD
), &bytesread
);
776 if (FAILED(hr
)) return hr
;
777 if (bytesread
!= sizeof(DWORD
) ||
778 (This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER
) &&
779 This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER2
) &&
780 This
->bih
.bV5Size
!= sizeof(BITMAPINFOHEADER
) &&
781 This
->bih
.bV5Size
!= sizeof(BITMAPV4HEADER
) &&
782 This
->bih
.bV5Size
!= sizeof(BITMAPV5HEADER
))) return E_FAIL
;
784 bytestoread
= This
->bih
.bV5Size
-sizeof(DWORD
);
785 hr
= IStream_Read(stream
, &This
->bih
.bV5Width
, bytestoread
, &bytesread
);
786 if (FAILED(hr
)) return hr
;
787 if (bytestoread
!= bytesread
) return E_FAIL
;
790 This
->palette_offset
= This
->bih
.bV5Size
;
792 This
->palette_offset
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
796 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
798 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
803 This
->bih
.bV5Height
/= 2;
807 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
808 read the extra fields */
809 if (This
->bih
.bV5Size
== sizeof(BITMAPINFOHEADER
) &&
810 This
->bih
.bV5Compression
== BI_BITFIELDS
)
812 hr
= IStream_Read(stream
, &This
->bih
.bV5RedMask
, 12, &bytesread
);
813 if (FAILED(hr
)) return hr
;
814 if (bytesread
!= 12) return E_FAIL
;
815 This
->bih
.bV5AlphaMask
= 0;
816 This
->palette_offset
+= 12;
819 /* decide what kind of bitmap this is and how/if we can read it */
820 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
822 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
823 TRACE("BITMAPCOREHEADER with depth=%i\n", bch
->bcBitCount
);
824 This
->bitsperpixel
= bch
->bcBitCount
;
825 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
826 switch(bch
->bcBitCount
)
829 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
832 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
835 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
838 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
841 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
844 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
845 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch
->bcBitCount
);
849 else /* struct is compatible with BITMAPINFOHEADER */
851 TRACE("bitmap header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
852 switch(This
->bih
.bV5Compression
)
855 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
856 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
857 switch(This
->bih
.bV5BitCount
)
860 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
863 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
866 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
869 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
872 This
->pixelformat
= &GUID_WICPixelFormat16bppBGR555
;
875 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
878 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
881 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
882 FIXME("unsupported bit depth %i for uncompressed RGB\n", This
->bih
.bV5BitCount
);
886 This
->bitsperpixel
= 32;
887 This
->read_data_func
= BmpFrameDecode_ReadRLE8
;
888 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
891 This
->bitsperpixel
= 32;
892 This
->read_data_func
= BmpFrameDecode_ReadRLE4
;
893 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
897 const struct bitfields_format
*format
;
898 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER2
))
900 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
901 This
->bitsperpixel
= 0;
902 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
903 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
904 FIXME("Huffman 1D compression is unsupported\n");
907 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
908 for (format
= bitfields_formats
; format
->bitcount
; format
++)
910 if ((format
->bitcount
== This
->bih
.bV5BitCount
) &&
911 (format
->redmask
== This
->bih
.bV5RedMask
) &&
912 (format
->greenmask
== This
->bih
.bV5GreenMask
) &&
913 (format
->bluemask
== This
->bih
.bV5BlueMask
) &&
914 (format
->alphamask
== This
->bih
.bV5AlphaMask
))
916 This
->read_data_func
= format
->read_data_func
;
917 This
->pixelformat
= format
->pixelformat
;
921 if (!format
->bitcount
)
923 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
924 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
925 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
926 This
->bih
.bV5BitCount
, This
->bih
.bV5RedMask
, This
->bih
.bV5GreenMask
, This
->bih
.bV5BlueMask
, This
->bih
.bV5AlphaMask
);
931 This
->bitsperpixel
= 0;
932 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
933 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
934 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
941 /* In a packed DIB, the image follows the palette. */
942 ULONG palette_count
, palette_size
;
943 if (This
->bih
.bV5ClrUsed
)
944 palette_count
= This
->bih
.bV5ClrUsed
;
945 else if (This
->bih
.bV5BitCount
<= 8)
946 palette_count
= 1 << This
->bih
.bV5BitCount
;
949 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
950 palette_size
= sizeof(RGBTRIPLE
) * palette_count
;
952 palette_size
= sizeof(RGBQUAD
) * palette_count
;
953 This
->image_offset
= This
->palette_offset
+ palette_size
;
956 This
->initialized
= TRUE
;
961 static HRESULT WINAPI
BmpDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
964 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
965 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
967 if (!ppv
) return E_INVALIDARG
;
969 if (IsEqualIID(&IID_IUnknown
, iid
) ||
970 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
972 *ppv
= &This
->IWICBitmapDecoder_iface
;
977 return E_NOINTERFACE
;
980 IUnknown_AddRef((IUnknown
*)*ppv
);
984 static ULONG WINAPI
BmpDecoder_AddRef(IWICBitmapDecoder
*iface
)
986 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
987 ULONG ref
= InterlockedIncrement(&This
->ref
);
989 TRACE("(%p) refcount=%u\n", iface
, ref
);
994 static ULONG WINAPI
BmpDecoder_Release(IWICBitmapDecoder
*iface
)
996 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
997 ULONG ref
= InterlockedDecrement(&This
->ref
);
999 TRACE("(%p) refcount=%u\n", iface
, ref
);
1003 if (This
->stream
) IStream_Release(This
->stream
);
1004 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
1005 This
->lock
.DebugInfo
->Spare
[0] = 0;
1006 DeleteCriticalSection(&This
->lock
);
1007 HeapFree(GetProcessHeap(), 0, This
);
1013 static HRESULT WINAPI
BmpDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1017 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1019 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1021 if (!stream
|| !capability
) return E_INVALIDARG
;
1023 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1024 if (hr
!= S_OK
) return hr
;
1026 *capability
= This
->read_data_func
== BmpFrameDecode_ReadUnsupported
? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages
;
1030 static HRESULT WINAPI
BmpDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1031 WICDecodeOptions cacheOptions
)
1034 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1036 EnterCriticalSection(&This
->lock
);
1037 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
1041 This
->stream
= pIStream
;
1042 IStream_AddRef(pIStream
);
1044 LeaveCriticalSection(&This
->lock
);
1049 static HRESULT WINAPI
BmpDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1050 GUID
*pguidContainerFormat
)
1052 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
1056 static HRESULT WINAPI
BmpDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1057 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1060 IWICComponentInfo
*compinfo
;
1062 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1064 hr
= CreateComponentInfo(&CLSID_WICBmpDecoder
, &compinfo
);
1065 if (FAILED(hr
)) return hr
;
1067 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1068 (void**)ppIDecoderInfo
);
1070 IWICComponentInfo_Release(compinfo
);
1075 static HRESULT WINAPI
BmpDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1076 IWICPalette
*pIPalette
)
1078 TRACE("(%p,%p)\n", iface
, pIPalette
);
1080 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1083 static HRESULT WINAPI
BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1084 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1086 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1087 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1090 static HRESULT WINAPI
BmpDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1091 IWICBitmapSource
**ppIBitmapSource
)
1093 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1094 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1097 static HRESULT WINAPI
BmpDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1098 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1100 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1101 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1104 static HRESULT WINAPI
BmpDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1105 IWICBitmapSource
**ppIThumbnail
)
1107 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1108 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1111 static HRESULT WINAPI
BmpDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1114 if (!pCount
) return E_INVALIDARG
;
1120 static HRESULT WINAPI
BmpDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1121 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1123 BmpDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1125 if (index
!= 0) return E_INVALIDARG
;
1127 if (!This
->stream
) return WINCODEC_ERR_FRAMEMISSING
;
1129 *ppIBitmapFrame
= &This
->IWICBitmapFrameDecode_iface
;
1130 IWICBitmapDecoder_AddRef(iface
);
1135 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl
= {
1136 BmpDecoder_QueryInterface
,
1139 BmpDecoder_QueryCapability
,
1140 BmpDecoder_Initialize
,
1141 BmpDecoder_GetContainerFormat
,
1142 BmpDecoder_GetDecoderInfo
,
1143 BmpDecoder_CopyPalette
,
1144 BmpDecoder_GetMetadataQueryReader
,
1145 BmpDecoder_GetPreview
,
1146 BmpDecoder_GetColorContexts
,
1147 BmpDecoder_GetThumbnail
,
1148 BmpDecoder_GetFrameCount
,
1152 static HRESULT
BmpDecoder_Create(int packed
, int icoframe
, BmpDecoder
**ppDecoder
)
1156 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder
));
1157 if (!This
) return E_OUTOFMEMORY
;
1159 This
->IWICBitmapDecoder_iface
.lpVtbl
= &BmpDecoder_Vtbl
;
1160 This
->IWICBitmapFrameDecode_iface
.lpVtbl
= &BmpDecoder_FrameVtbl
;
1162 This
->initialized
= FALSE
;
1163 This
->stream
= NULL
;
1164 This
->imagedata
= NULL
;
1165 InitializeCriticalSection(&This
->lock
);
1166 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BmpDecoder.lock");
1167 This
->packed
= packed
;
1168 This
->icoframe
= icoframe
;
1175 static HRESULT
BmpDecoder_Construct(int packed
, int icoframe
, IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1180 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1184 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1186 ret
= BmpDecoder_Create(packed
, icoframe
, &This
);
1187 if (FAILED(ret
)) return ret
;
1189 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1190 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1195 HRESULT
BmpDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1197 return BmpDecoder_Construct(FALSE
, FALSE
, pUnkOuter
, iid
, ppv
);
1200 HRESULT
DibDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1202 return BmpDecoder_Construct(TRUE
, FALSE
, pUnkOuter
, iid
, ppv
);
1205 HRESULT
IcoDibDecoder_CreateInstance(BmpDecoder
**ppDecoder
)
1207 return BmpDecoder_Create(TRUE
, TRUE
, ppDecoder
);
1210 void BmpDecoder_GetWICDecoder(BmpDecoder
*This
, IWICBitmapDecoder
**ppDecoder
)
1212 *ppDecoder
= &This
->IWICBitmapDecoder_iface
;
1215 /* Return the offset where the mask of an icon might be, or 0 for failure. */
1216 void BmpDecoder_FindIconMask(BmpDecoder
*This
, ULONG
*mask_offset
, int *topdown
)
1218 assert(This
->stream
!= NULL
);
1220 if (This
->read_data_func
== BmpFrameDecode_ReadUncompressed
)
1222 /* RGB or BITFIELDS data */
1223 ULONG width
, height
, bytesperrow
, datasize
;
1224 IWICBitmapFrameDecode_GetSize(&This
->IWICBitmapFrameDecode_iface
, &width
, &height
);
1225 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
1226 datasize
= bytesperrow
* height
;
1227 *mask_offset
= This
->image_offset
+ datasize
;
1232 *topdown
= This
->stride
> 0;