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
;
63 typedef HRESULT (*ReadDataFunc
)(struct BmpDecoder
* This
);
65 typedef struct BmpDecoder
{
66 const IWICBitmapDecoderVtbl
*lpVtbl
;
67 const IWICBitmapFrameDecodeVtbl
*lpFrameVtbl
;
74 const WICPixelFormatGUID
*pixelformat
;
76 ReadDataFunc read_data_func
;
80 CRITICAL_SECTION lock
; /* must be held when initialized/imagedata is set or stream is accessed */
81 int packed
; /* If TRUE, don't look for a file header and assume a packed DIB. */
82 int icoframe
; /* If TRUE, this is a frame of a .ico file. */
85 static inline BmpDecoder
*impl_from_frame(IWICBitmapFrameDecode
*iface
)
87 return CONTAINING_RECORD(iface
, BmpDecoder
, lpFrameVtbl
);
90 static HRESULT WINAPI
BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
93 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
95 if (!ppv
) return E_INVALIDARG
;
97 if (IsEqualIID(&IID_IUnknown
, iid
) ||
98 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
99 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
106 return E_NOINTERFACE
;
109 IUnknown_AddRef((IUnknown
*)*ppv
);
113 static ULONG WINAPI
BmpFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
115 BmpDecoder
*This
= impl_from_frame(iface
);
117 return IUnknown_AddRef((IUnknown
*)This
);
120 static ULONG WINAPI
BmpFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
122 BmpDecoder
*This
= impl_from_frame(iface
);
124 return IUnknown_Release((IUnknown
*)This
);
127 static HRESULT WINAPI
BmpFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
128 UINT
*puiWidth
, UINT
*puiHeight
)
130 BmpDecoder
*This
= impl_from_frame(iface
);
131 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
133 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
135 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
136 *puiWidth
= bch
->bcWidth
;
137 *puiHeight
= bch
->bcHeight
;
141 *puiWidth
= This
->bih
.bV5Width
;
142 *puiHeight
= abs(This
->bih
.bV5Height
);
147 static HRESULT WINAPI
BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
148 WICPixelFormatGUID
*pPixelFormat
)
150 BmpDecoder
*This
= impl_from_frame(iface
);
151 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
153 memcpy(pPixelFormat
, This
->pixelformat
, sizeof(GUID
));
158 static HRESULT
BmpHeader_GetResolution(BITMAPV5HEADER
*bih
, double *pDpiX
, double *pDpiY
)
160 switch (bih
->bV5Size
)
162 case sizeof(BITMAPCOREHEADER
):
166 case sizeof(BITMAPCOREHEADER2
):
167 case sizeof(BITMAPINFOHEADER
):
168 case sizeof(BITMAPV4HEADER
):
169 case sizeof(BITMAPV5HEADER
):
170 *pDpiX
= bih
->bV5XPelsPerMeter
* 0.0254;
171 *pDpiY
= bih
->bV5YPelsPerMeter
* 0.0254;
178 static HRESULT WINAPI
BmpFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
179 double *pDpiX
, double *pDpiY
)
181 BmpDecoder
*This
= impl_from_frame(iface
);
182 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
184 return BmpHeader_GetResolution(&This
->bih
, pDpiX
, pDpiY
);
187 static HRESULT WINAPI
BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
188 IWICPalette
*pIPalette
)
191 BmpDecoder
*This
= impl_from_frame(iface
);
193 WICColor
*wiccolors
=NULL
;
194 RGBTRIPLE
*bgrcolors
=NULL
;
196 TRACE("(%p,%p)\n", iface
, pIPalette
);
198 EnterCriticalSection(&This
->lock
);
200 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
202 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
203 if (bch
->bcBitCount
<= 8)
205 /* 2**n colors in BGR format after the header */
206 ULONG tablesize
, bytesread
;
207 LARGE_INTEGER offset
;
210 count
= 1 << bch
->bcBitCount
;
211 wiccolors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * count
);
212 tablesize
= sizeof(RGBTRIPLE
) * count
;
213 bgrcolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
214 if (!wiccolors
|| !bgrcolors
)
220 offset
.QuadPart
= This
->palette_offset
;
221 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
222 if (FAILED(hr
)) goto end
;
224 hr
= IStream_Read(This
->stream
, bgrcolors
, tablesize
, &bytesread
);
225 if (FAILED(hr
)) goto end
;
226 if (bytesread
!= tablesize
) {
231 for (i
=0; i
<count
; i
++)
233 wiccolors
[i
] = 0xff000000|
234 (bgrcolors
[i
].rgbtRed
<<16)|
235 (bgrcolors
[i
].rgbtGreen
<<8)|
236 bgrcolors
[i
].rgbtBlue
;
241 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
247 if (This
->bih
.bV5BitCount
<= 8)
249 ULONG tablesize
, bytesread
;
250 LARGE_INTEGER offset
;
253 if (This
->bih
.bV5ClrUsed
== 0)
254 count
= 1 << This
->bih
.bV5BitCount
;
256 count
= This
->bih
.bV5ClrUsed
;
258 tablesize
= sizeof(WICColor
) * count
;
259 wiccolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
266 offset
.QuadPart
= This
->palette_offset
;
267 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
268 if (FAILED(hr
)) goto end
;
270 hr
= IStream_Read(This
->stream
, wiccolors
, tablesize
, &bytesread
);
271 if (FAILED(hr
)) goto end
;
272 if (bytesread
!= tablesize
) {
277 /* convert from BGR to BGRA by setting alpha to 100% */
278 for (i
=0; i
<count
; i
++)
279 wiccolors
[i
] |= 0xff000000;
283 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
290 LeaveCriticalSection(&This
->lock
);
293 hr
= IWICPalette_InitializeCustom(pIPalette
, wiccolors
, count
);
295 HeapFree(GetProcessHeap(), 0, wiccolors
);
296 HeapFree(GetProcessHeap(), 0, bgrcolors
);
300 static HRESULT WINAPI
BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
301 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
303 BmpDecoder
*This
= impl_from_frame(iface
);
306 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
308 EnterCriticalSection(&This
->lock
);
309 if (!This
->imagedata
)
311 hr
= This
->read_data_func(This
);
313 LeaveCriticalSection(&This
->lock
);
314 if (FAILED(hr
)) return hr
;
316 hr
= BmpFrameDecode_GetSize(iface
, &width
, &height
);
317 if (FAILED(hr
)) return hr
;
319 return copy_pixels(This
->bitsperpixel
, This
->imagedatastart
,
320 width
, height
, This
->stride
,
321 prc
, cbStride
, cbBufferSize
, pbBuffer
);
324 static HRESULT WINAPI
BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
325 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
327 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
328 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
331 static HRESULT WINAPI
BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
332 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
334 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
335 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
338 static HRESULT WINAPI
BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
339 IWICBitmapSource
**ppIThumbnail
)
341 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
342 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
345 static HRESULT
BmpFrameDecode_ReadUncompressed(BmpDecoder
* This
)
352 LARGE_INTEGER offbits
;
355 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
357 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
358 width
= bch
->bcWidth
;
359 height
= bch
->bcHeight
;
364 width
= This
->bih
.bV5Width
;
365 height
= abs(This
->bih
.bV5Height
);
366 bottomup
= (This
->bih
.bV5Height
> 0);
369 /* row sizes in BMP files must be divisible by 4 bytes */
370 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
371 datasize
= bytesperrow
* height
;
373 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
374 if (!This
->imagedata
) return E_OUTOFMEMORY
;
376 offbits
.QuadPart
= This
->image_offset
;
377 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
378 if (FAILED(hr
)) goto fail
;
380 hr
= IStream_Read(This
->stream
, This
->imagedata
, datasize
, &bytesread
);
381 if (FAILED(hr
) || bytesread
!= datasize
) goto fail
;
385 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
386 This
->stride
= -bytesperrow
;
390 This
->imagedatastart
= This
->imagedata
;
391 This
->stride
= bytesperrow
;
396 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
397 This
->imagedata
= NULL
;
398 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
402 static HRESULT
ReadByte(IStream
*stream
, BYTE
*buffer
, ULONG buffer_size
,
403 ULONG
*cursor
, ULONG
*bytesread
, BYTE
*result
)
407 if (*bytesread
== 0 || *cursor
== *bytesread
)
409 hr
= IStream_Read(stream
, buffer
, buffer_size
, bytesread
);
415 if (*cursor
< *bytesread
)
416 *result
= buffer
[(*cursor
)++];
424 static HRESULT
BmpFrameDecode_ReadRLE8(BmpDecoder
* This
)
429 UINT datasize
, palettesize
;
434 LARGE_INTEGER offbits
;
435 ULONG cursor
=0, bytesread
=0;
437 width
= This
->bih
.bV5Width
;
438 height
= abs(This
->bih
.bV5Height
);
439 bytesperrow
= width
* 4;
440 datasize
= bytesperrow
* height
;
441 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 256)
442 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
444 palettesize
= 4 * 256;
446 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
447 if (!This
->imagedata
)
454 offbits
.QuadPart
= This
->palette_offset
;
455 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
456 if (FAILED(hr
)) goto fail
;
458 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
459 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
462 offbits
.QuadPart
= This
->image_offset
;
463 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
464 if (FAILED(hr
)) goto fail
;
467 bgrdata
= (DWORD
*)This
->imagedata
;
475 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
479 else if (length
== 0)
483 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
488 case 0: /* end of line */
492 case 1: /* end of bitmap */
497 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
499 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
506 default: /* absolute mode */
508 while (length
-- && x
< width
)
511 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
514 bgrdata
[y
*width
+ x
++] = palette
[index
];
517 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
526 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &index
);
529 color
= palette
[index
];
530 while (length
-- && x
< width
)
531 bgrdata
[y
*width
+ x
++] = color
;
536 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
537 This
->stride
= -bytesperrow
;
542 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
543 This
->imagedata
= NULL
;
544 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
548 static HRESULT
BmpFrameDecode_ReadRLE4(BmpDecoder
* This
)
553 UINT datasize
, palettesize
;
558 LARGE_INTEGER offbits
;
559 ULONG cursor
=0, bytesread
=0;
561 width
= This
->bih
.bV5Width
;
562 height
= abs(This
->bih
.bV5Height
);
563 bytesperrow
= width
* 4;
564 datasize
= bytesperrow
* height
;
565 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 16)
566 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
568 palettesize
= 4 * 16;
570 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
571 if (!This
->imagedata
)
578 offbits
.QuadPart
= This
->palette_offset
;
579 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
580 if (FAILED(hr
)) goto fail
;
582 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
583 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
586 offbits
.QuadPart
= This
->image_offset
;
587 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
588 if (FAILED(hr
)) goto fail
;
591 bgrdata
= (DWORD
*)This
->imagedata
;
599 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
);
603 else if (length
== 0)
607 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &escape
);
612 case 0: /* end of line */
616 case 1: /* end of bitmap */
621 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dx
);
623 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &dy
);
630 default: /* absolute mode */
634 while (length
-- && x
< width
)
637 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
641 bgrdata
[y
*width
+ x
++] = palette
[colors
>>4];
642 if (length
-- && x
< width
)
643 bgrdata
[y
*width
+ x
++] = palette
[colors
&0xf];
648 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &length
); /* skip pad byte */
659 hr
= ReadByte(This
->stream
, rledata
, 4096, &cursor
, &bytesread
, &colors
);
662 color1
= palette
[colors
>>4];
663 color2
= palette
[colors
&0xf];
664 while (length
-- && x
< width
)
666 bgrdata
[y
*width
+ x
++] = color1
;
667 if (length
-- && x
< width
)
668 bgrdata
[y
*width
+ x
++] = color2
;
676 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
677 This
->stride
= -bytesperrow
;
682 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
683 This
->imagedata
= NULL
;
684 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
688 static HRESULT
BmpFrameDecode_ReadUnsupported(BmpDecoder
* This
)
693 struct bitfields_format
{
694 WORD bitcount
; /* 0 for end of list */
699 const WICPixelFormatGUID
*pixelformat
;
700 ReadDataFunc read_data_func
;
703 static const struct bitfields_format bitfields_formats
[] = {
704 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555
,BmpFrameDecode_ReadUncompressed
},
705 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565
,BmpFrameDecode_ReadUncompressed
},
706 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadUncompressed
},
707 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA
,BmpFrameDecode_ReadUncompressed
},
711 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl
= {
712 BmpFrameDecode_QueryInterface
,
713 BmpFrameDecode_AddRef
,
714 BmpFrameDecode_Release
,
715 BmpFrameDecode_GetSize
,
716 BmpFrameDecode_GetPixelFormat
,
717 BmpFrameDecode_GetResolution
,
718 BmpFrameDecode_CopyPalette
,
719 BmpFrameDecode_CopyPixels
,
720 BmpFrameDecode_GetMetadataQueryReader
,
721 BmpFrameDecode_GetColorContexts
,
722 BmpFrameDecode_GetThumbnail
725 static HRESULT
BmpDecoder_ReadHeaders(BmpDecoder
* This
, IStream
*stream
)
728 ULONG bytestoread
, bytesread
;
731 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
734 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, NULL
);
735 if (FAILED(hr
)) return hr
;
739 BITMAPFILEHEADER bfh
;
740 hr
= IStream_Read(stream
, &bfh
, sizeof(BITMAPFILEHEADER
), &bytesread
);
741 if (FAILED(hr
)) return hr
;
742 if (bytesread
!= sizeof(BITMAPFILEHEADER
) ||
743 bfh
.bfType
!= 0x4d42 /* "BM" */) return E_FAIL
;
744 This
->image_offset
= bfh
.bfOffBits
;
747 hr
= IStream_Read(stream
, &This
->bih
.bV5Size
, sizeof(DWORD
), &bytesread
);
748 if (FAILED(hr
)) return hr
;
749 if (bytesread
!= sizeof(DWORD
) ||
750 (This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER
) &&
751 This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER2
) &&
752 This
->bih
.bV5Size
!= sizeof(BITMAPINFOHEADER
) &&
753 This
->bih
.bV5Size
!= sizeof(BITMAPV4HEADER
) &&
754 This
->bih
.bV5Size
!= sizeof(BITMAPV5HEADER
))) return E_FAIL
;
756 bytestoread
= This
->bih
.bV5Size
-sizeof(DWORD
);
757 hr
= IStream_Read(stream
, &This
->bih
.bV5Width
, bytestoread
, &bytesread
);
758 if (FAILED(hr
)) return hr
;
759 if (bytestoread
!= bytesread
) return E_FAIL
;
762 This
->palette_offset
= This
->bih
.bV5Size
;
764 This
->palette_offset
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
768 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
770 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
775 This
->bih
.bV5Height
/= 2;
779 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
780 read the extra fields */
781 if (This
->bih
.bV5Size
== sizeof(BITMAPINFOHEADER
) &&
782 This
->bih
.bV5Compression
== BI_BITFIELDS
)
784 hr
= IStream_Read(stream
, &This
->bih
.bV5RedMask
, 12, &bytesread
);
785 if (FAILED(hr
)) return hr
;
786 if (bytesread
!= 12) return E_FAIL
;
787 This
->bih
.bV5AlphaMask
= 0;
788 This
->palette_offset
+= 12;
791 /* decide what kind of bitmap this is and how/if we can read it */
792 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
794 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
795 TRACE("BITMAPCOREHEADER with depth=%i\n", bch
->bcBitCount
);
796 This
->bitsperpixel
= bch
->bcBitCount
;
797 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
798 switch(bch
->bcBitCount
)
801 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
804 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
807 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
810 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
813 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
816 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
817 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch
->bcBitCount
);
821 else /* struct is compatible with BITMAPINFOHEADER */
823 TRACE("bitmap header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
824 switch(This
->bih
.bV5Compression
)
827 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
828 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
829 switch(This
->bih
.bV5BitCount
)
832 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
835 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
838 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
841 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
844 This
->pixelformat
= &GUID_WICPixelFormat16bppBGR555
;
847 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
850 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
853 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
854 FIXME("unsupported bit depth %i for uncompressed RGB\n", This
->bih
.bV5BitCount
);
858 This
->bitsperpixel
= 32;
859 This
->read_data_func
= BmpFrameDecode_ReadRLE8
;
860 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
863 This
->bitsperpixel
= 32;
864 This
->read_data_func
= BmpFrameDecode_ReadRLE4
;
865 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
869 const struct bitfields_format
*format
;
870 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER2
))
872 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
873 This
->bitsperpixel
= 0;
874 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
875 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
876 FIXME("Huffman 1D compression is unsupported\n");
879 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
880 for (format
= bitfields_formats
; format
->bitcount
; format
++)
882 if ((format
->bitcount
== This
->bih
.bV5BitCount
) &&
883 (format
->redmask
== This
->bih
.bV5RedMask
) &&
884 (format
->greenmask
== This
->bih
.bV5GreenMask
) &&
885 (format
->bluemask
== This
->bih
.bV5BlueMask
) &&
886 (format
->alphamask
== This
->bih
.bV5AlphaMask
))
888 This
->read_data_func
= format
->read_data_func
;
889 This
->pixelformat
= format
->pixelformat
;
893 if (!format
->bitcount
)
895 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
896 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
897 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
898 This
->bih
.bV5BitCount
, This
->bih
.bV5RedMask
, This
->bih
.bV5GreenMask
, This
->bih
.bV5BlueMask
, This
->bih
.bV5AlphaMask
);
903 This
->bitsperpixel
= 0;
904 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
905 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
906 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
913 /* In a packed DIB, the image follows the palette. */
914 ULONG palette_count
, palette_size
;
915 if (This
->bih
.bV5ClrUsed
)
916 palette_count
= This
->bih
.bV5ClrUsed
;
917 else if (This
->bih
.bV5BitCount
<= 8)
918 palette_count
= 1 << This
->bih
.bV5BitCount
;
921 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
922 palette_size
= sizeof(RGBTRIPLE
) * palette_count
;
924 palette_size
= sizeof(RGBQUAD
) * palette_count
;
925 This
->image_offset
= This
->palette_offset
+ palette_size
;
928 This
->initialized
= TRUE
;
933 static HRESULT WINAPI
BmpDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
936 BmpDecoder
*This
= (BmpDecoder
*)iface
;
937 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
939 if (!ppv
) return E_INVALIDARG
;
941 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
948 return E_NOINTERFACE
;
951 IUnknown_AddRef((IUnknown
*)*ppv
);
955 static ULONG WINAPI
BmpDecoder_AddRef(IWICBitmapDecoder
*iface
)
957 BmpDecoder
*This
= (BmpDecoder
*)iface
;
958 ULONG ref
= InterlockedIncrement(&This
->ref
);
960 TRACE("(%p) refcount=%u\n", iface
, ref
);
965 static ULONG WINAPI
BmpDecoder_Release(IWICBitmapDecoder
*iface
)
967 BmpDecoder
*This
= (BmpDecoder
*)iface
;
968 ULONG ref
= InterlockedDecrement(&This
->ref
);
970 TRACE("(%p) refcount=%u\n", iface
, ref
);
974 if (This
->stream
) IStream_Release(This
->stream
);
975 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
976 This
->lock
.DebugInfo
->Spare
[0] = 0;
977 DeleteCriticalSection(&This
->lock
);
978 HeapFree(GetProcessHeap(), 0, This
);
984 static HRESULT WINAPI
BmpDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
985 DWORD
*pdwCapability
)
988 BmpDecoder
*This
= (BmpDecoder
*)iface
;
990 EnterCriticalSection(&This
->lock
);
991 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
992 LeaveCriticalSection(&This
->lock
);
993 if (FAILED(hr
)) return hr
;
995 if (This
->read_data_func
== BmpFrameDecode_ReadUnsupported
)
998 *pdwCapability
= WICBitmapDecoderCapabilityCanDecodeAllImages
;
1003 static HRESULT WINAPI
BmpDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1004 WICDecodeOptions cacheOptions
)
1007 BmpDecoder
*This
= (BmpDecoder
*)iface
;
1009 EnterCriticalSection(&This
->lock
);
1010 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
1014 This
->stream
= pIStream
;
1015 IStream_AddRef(pIStream
);
1017 LeaveCriticalSection(&This
->lock
);
1022 static HRESULT WINAPI
BmpDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1023 GUID
*pguidContainerFormat
)
1025 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
1029 static HRESULT WINAPI
BmpDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1030 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1033 IWICComponentInfo
*compinfo
;
1035 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1037 hr
= CreateComponentInfo(&CLSID_WICBmpDecoder
, &compinfo
);
1038 if (FAILED(hr
)) return hr
;
1040 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1041 (void**)ppIDecoderInfo
);
1043 IWICComponentInfo_Release(compinfo
);
1048 static HRESULT WINAPI
BmpDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1049 IWICPalette
*pIPalette
)
1051 TRACE("(%p,%p)\n", iface
, pIPalette
);
1053 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1056 static HRESULT WINAPI
BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1057 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1059 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1060 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1063 static HRESULT WINAPI
BmpDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1064 IWICBitmapSource
**ppIBitmapSource
)
1066 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1067 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1070 static HRESULT WINAPI
BmpDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1071 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1073 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1074 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1077 static HRESULT WINAPI
BmpDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1078 IWICBitmapSource
**ppIThumbnail
)
1080 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1081 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1084 static HRESULT WINAPI
BmpDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1091 static HRESULT WINAPI
BmpDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1092 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1094 BmpDecoder
*This
= (BmpDecoder
*)iface
;
1096 if (index
!= 0) return E_INVALIDARG
;
1098 if (!This
->stream
) return WINCODEC_ERR_WRONGSTATE
;
1100 *ppIBitmapFrame
= (IWICBitmapFrameDecode
*)&This
->lpFrameVtbl
;
1101 IWICBitmapDecoder_AddRef(iface
);
1106 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl
= {
1107 BmpDecoder_QueryInterface
,
1110 BmpDecoder_QueryCapability
,
1111 BmpDecoder_Initialize
,
1112 BmpDecoder_GetContainerFormat
,
1113 BmpDecoder_GetDecoderInfo
,
1114 BmpDecoder_CopyPalette
,
1115 BmpDecoder_GetMetadataQueryReader
,
1116 BmpDecoder_GetPreview
,
1117 BmpDecoder_GetColorContexts
,
1118 BmpDecoder_GetThumbnail
,
1119 BmpDecoder_GetFrameCount
,
1123 static HRESULT
BmpDecoder_Construct(int packed
, int icoframe
, IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1128 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1132 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1134 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder
));
1135 if (!This
) return E_OUTOFMEMORY
;
1137 This
->lpVtbl
= &BmpDecoder_Vtbl
;
1138 This
->lpFrameVtbl
= &BmpDecoder_FrameVtbl
;
1140 This
->initialized
= FALSE
;
1141 This
->stream
= NULL
;
1142 This
->imagedata
= NULL
;
1143 InitializeCriticalSection(&This
->lock
);
1144 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BmpDecoder.lock");
1145 This
->packed
= packed
;
1146 This
->icoframe
= icoframe
;
1148 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1149 IUnknown_Release((IUnknown
*)This
);
1154 HRESULT
BmpDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1156 return BmpDecoder_Construct(FALSE
, FALSE
, pUnkOuter
, iid
, ppv
);
1159 HRESULT
DibDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1161 return BmpDecoder_Construct(TRUE
, FALSE
, pUnkOuter
, iid
, ppv
);
1164 HRESULT
IcoDibDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1166 return BmpDecoder_Construct(TRUE
, TRUE
, pUnkOuter
, iid
, ppv
);
1169 /* Return the offset where the mask of an icon might be, or 0 for failure. */
1170 void BmpDecoder_FindIconMask(IWICBitmapDecoder
*decoder
, ULONG
*mask_offset
, int *topdown
)
1172 BmpDecoder
*This
= (BmpDecoder
*)decoder
;
1174 assert(This
->lpVtbl
== &BmpDecoder_Vtbl
);
1175 assert(This
->stream
!= NULL
);
1177 if (This
->read_data_func
== BmpFrameDecode_ReadUncompressed
)
1179 /* RGB or BITFIELDS data */
1180 ULONG width
, height
, bytesperrow
, datasize
;
1181 IWICBitmapFrameDecode_GetSize((IWICBitmapFrameDecode
*)&This
->lpFrameVtbl
, &width
, &height
);
1182 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
1183 datasize
= bytesperrow
* height
;
1184 *mask_offset
= This
->image_offset
+ datasize
;
1189 *topdown
= This
->stride
> 0;