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
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
49 DWORD bc2ClrImportant
;
50 /* same as BITMAPINFOHEADER until this point */
55 DWORD bc2HalftoneSize1
;
56 DWORD bc2HalftoneSize2
;
62 typedef HRESULT (*ReadDataFunc
)(struct BmpDecoder
* This
);
64 typedef struct BmpDecoder
{
65 const IWICBitmapDecoderVtbl
*lpVtbl
;
66 const IWICBitmapFrameDecodeVtbl
*lpFrameVtbl
;
72 const WICPixelFormatGUID
*pixelformat
;
74 ReadDataFunc read_data_func
;
78 CRITICAL_SECTION lock
; /* must be held when initialized/imagedata is set or stream is accessed */
81 static inline BmpDecoder
*impl_from_frame(IWICBitmapFrameDecode
*iface
)
83 return CONTAINING_RECORD(iface
, BmpDecoder
, lpFrameVtbl
);
86 static HRESULT WINAPI
BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
89 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
91 if (!ppv
) return E_INVALIDARG
;
93 if (IsEqualIID(&IID_IUnknown
, iid
) ||
94 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
95 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
102 return E_NOINTERFACE
;
105 IUnknown_AddRef((IUnknown
*)*ppv
);
109 static ULONG WINAPI
BmpFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
111 BmpDecoder
*This
= impl_from_frame(iface
);
113 return IUnknown_AddRef((IUnknown
*)This
);
116 static ULONG WINAPI
BmpFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
118 BmpDecoder
*This
= impl_from_frame(iface
);
120 return IUnknown_Release((IUnknown
*)This
);
123 static HRESULT WINAPI
BmpFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
124 UINT
*puiWidth
, UINT
*puiHeight
)
126 BmpDecoder
*This
= impl_from_frame(iface
);
127 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
129 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
131 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
132 *puiWidth
= bch
->bcWidth
;
133 *puiHeight
= bch
->bcHeight
;
137 *puiWidth
= This
->bih
.bV5Width
;
138 *puiHeight
= abs(This
->bih
.bV5Height
);
143 static HRESULT WINAPI
BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
144 WICPixelFormatGUID
*pPixelFormat
)
146 BmpDecoder
*This
= impl_from_frame(iface
);
147 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
149 memcpy(pPixelFormat
, This
->pixelformat
, sizeof(GUID
));
154 static HRESULT
BmpHeader_GetResolution(BITMAPV5HEADER
*bih
, double *pDpiX
, double *pDpiY
)
156 switch (bih
->bV5Size
)
158 case sizeof(BITMAPCOREHEADER
):
162 case sizeof(BITMAPCOREHEADER2
):
163 case sizeof(BITMAPINFOHEADER
):
164 case sizeof(BITMAPV4HEADER
):
165 case sizeof(BITMAPV5HEADER
):
166 *pDpiX
= bih
->bV5XPelsPerMeter
* 0.0254;
167 *pDpiY
= bih
->bV5YPelsPerMeter
* 0.0254;
174 static HRESULT WINAPI
BmpFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
175 double *pDpiX
, double *pDpiY
)
177 BmpDecoder
*This
= impl_from_frame(iface
);
178 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
180 return BmpHeader_GetResolution(&This
->bih
, pDpiX
, pDpiY
);
183 static HRESULT WINAPI
BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
184 IWICPalette
*pIPalette
)
187 BmpDecoder
*This
= impl_from_frame(iface
);
189 WICColor
*wiccolors
=NULL
;
190 RGBTRIPLE
*bgrcolors
=NULL
;
192 TRACE("(%p,%p)\n", iface
, pIPalette
);
194 EnterCriticalSection(&This
->lock
);
196 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
198 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
199 if (bch
->bcBitCount
<= 8)
201 /* 2**n colors in BGR format after the header */
202 ULONG tablesize
, bytesread
;
203 LARGE_INTEGER offset
;
206 count
= 1 << bch
->bcBitCount
;
207 wiccolors
= HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor
) * count
);
208 tablesize
= sizeof(RGBTRIPLE
) * count
;
209 bgrcolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
210 if (!wiccolors
|| !bgrcolors
)
216 offset
.QuadPart
= sizeof(BITMAPFILEHEADER
)+sizeof(BITMAPCOREHEADER
);
217 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
218 if (FAILED(hr
)) goto end
;
220 hr
= IStream_Read(This
->stream
, bgrcolors
, tablesize
, &bytesread
);
221 if (FAILED(hr
)) goto end
;
222 if (bytesread
!= tablesize
) {
227 for (i
=0; i
<count
; i
++)
229 wiccolors
[i
] = 0xff000000|
230 (bgrcolors
[i
].rgbtRed
<<16)|
231 (bgrcolors
[i
].rgbtGreen
<<8)|
232 bgrcolors
[i
].rgbtBlue
;
237 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
243 if (This
->bih
.bV5BitCount
<= 8)
245 ULONG tablesize
, bytesread
;
246 LARGE_INTEGER offset
;
249 if (This
->bih
.bV5ClrUsed
== 0)
250 count
= 1 << This
->bih
.bV5BitCount
;
252 count
= This
->bih
.bV5ClrUsed
;
254 tablesize
= sizeof(WICColor
) * count
;
255 wiccolors
= HeapAlloc(GetProcessHeap(), 0, tablesize
);
262 offset
.QuadPart
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
263 hr
= IStream_Seek(This
->stream
, offset
, STREAM_SEEK_SET
, NULL
);
264 if (FAILED(hr
)) goto end
;
266 hr
= IStream_Read(This
->stream
, wiccolors
, tablesize
, &bytesread
);
267 if (FAILED(hr
)) goto end
;
268 if (bytesread
!= tablesize
) {
273 /* convert from BGR to BGRA by setting alpha to 100% */
274 for (i
=0; i
<count
; i
++)
275 wiccolors
[i
] |= 0xff000000;
279 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
286 LeaveCriticalSection(&This
->lock
);
289 hr
= IWICPalette_InitializeCustom(pIPalette
, wiccolors
, count
);
291 HeapFree(GetProcessHeap(), 0, wiccolors
);
292 HeapFree(GetProcessHeap(), 0, bgrcolors
);
296 static HRESULT WINAPI
BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
297 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
299 BmpDecoder
*This
= impl_from_frame(iface
);
302 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
304 EnterCriticalSection(&This
->lock
);
305 if (!This
->imagedata
)
307 hr
= This
->read_data_func(This
);
309 LeaveCriticalSection(&This
->lock
);
310 if (FAILED(hr
)) return hr
;
312 hr
= BmpFrameDecode_GetSize(iface
, &width
, &height
);
313 if (FAILED(hr
)) return hr
;
315 return copy_pixels(This
->bitsperpixel
, This
->imagedatastart
,
316 width
, height
, This
->stride
,
317 prc
, cbStride
, cbBufferSize
, pbBuffer
);
320 static HRESULT WINAPI
BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
321 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
323 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
324 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
327 static HRESULT WINAPI
BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
328 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
330 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
331 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
334 static HRESULT WINAPI
BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
335 IWICBitmapSource
**ppIThumbnail
)
337 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
338 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
341 static HRESULT
BmpFrameDecode_ReadUncompressed(BmpDecoder
* This
)
348 LARGE_INTEGER offbits
;
351 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
353 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
354 width
= bch
->bcWidth
;
355 height
= bch
->bcHeight
;
360 width
= This
->bih
.bV5Width
;
361 height
= abs(This
->bih
.bV5Height
);
362 bottomup
= (This
->bih
.bV5Height
> 0);
365 /* row sizes in BMP files must be divisible by 4 bytes */
366 bytesperrow
= (((width
* This
->bitsperpixel
)+31)/32)*4;
367 datasize
= bytesperrow
* height
;
369 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
370 if (!This
->imagedata
) return E_OUTOFMEMORY
;
372 offbits
.QuadPart
= This
->bfh
.bfOffBits
;
373 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
374 if (FAILED(hr
)) goto fail
;
376 hr
= IStream_Read(This
->stream
, This
->imagedata
, datasize
, &bytesread
);
377 if (FAILED(hr
) || bytesread
!= datasize
) goto fail
;
381 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
382 This
->stride
= -bytesperrow
;
386 This
->imagedatastart
= This
->imagedata
;
387 This
->stride
= bytesperrow
;
392 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
393 This
->imagedata
= NULL
;
394 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
398 static HRESULT
BmpFrameDecode_ReadRLE8(BmpDecoder
* This
)
402 BYTE
*rledata
, *cursor
, *rledataend
;
403 UINT rlesize
, datasize
, palettesize
;
408 LARGE_INTEGER offbits
;
411 width
= This
->bih
.bV5Width
;
412 height
= abs(This
->bih
.bV5Height
);
413 bytesperrow
= width
* 4;
414 datasize
= bytesperrow
* height
;
415 rlesize
= This
->bih
.bV5SizeImage
;
416 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 256)
417 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
419 palettesize
= 4 * 256;
421 rledata
= HeapAlloc(GetProcessHeap(), 0, rlesize
);
422 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
423 if (!This
->imagedata
|| !rledata
)
430 offbits
.QuadPart
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
431 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
432 if (FAILED(hr
)) goto fail
;
434 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
435 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
438 offbits
.QuadPart
= This
->bfh
.bfOffBits
;
439 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
440 if (FAILED(hr
)) goto fail
;
442 hr
= IStream_Read(This
->stream
, rledata
, rlesize
, &bytesread
);
443 if (FAILED(hr
) || bytesread
!= rlesize
) goto fail
;
446 bgrdata
= (DWORD
*)This
->imagedata
;
449 rledataend
= rledata
+ rlesize
;
451 while (cursor
< rledataend
&& y
< height
)
453 BYTE length
= *cursor
++;
457 BYTE escape
= *cursor
++;
460 case 0: /* end of line */
464 case 1: /* end of bitmap */
467 if (cursor
< rledataend
)
473 default: /* absolute mode */
475 while (cursor
< rledataend
&& length
-- && x
< width
)
476 bgrdata
[y
*width
+ x
++] = palette
[*cursor
++];
477 if (escape
& 1) cursor
++; /* skip pad byte */
482 DWORD color
= palette
[*cursor
++];
483 while (length
-- && x
< width
)
484 bgrdata
[y
*width
+ x
++] = color
;
489 HeapFree(GetProcessHeap(), 0, rledata
);
491 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
492 This
->stride
= -bytesperrow
;
497 HeapFree(GetProcessHeap(), 0, rledata
);
498 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
499 This
->imagedata
= NULL
;
500 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
504 static HRESULT
BmpFrameDecode_ReadRLE4(BmpDecoder
* This
)
508 BYTE
*rledata
, *cursor
, *rledataend
;
509 UINT rlesize
, datasize
, palettesize
;
514 LARGE_INTEGER offbits
;
517 width
= This
->bih
.bV5Width
;
518 height
= abs(This
->bih
.bV5Height
);
519 bytesperrow
= width
* 4;
520 datasize
= bytesperrow
* height
;
521 rlesize
= This
->bih
.bV5SizeImage
;
522 if (This
->bih
.bV5ClrUsed
&& This
->bih
.bV5ClrUsed
< 16)
523 palettesize
= 4 * This
->bih
.bV5ClrUsed
;
525 palettesize
= 4 * 16;
527 rledata
= HeapAlloc(GetProcessHeap(), 0, rlesize
);
528 This
->imagedata
= HeapAlloc(GetProcessHeap(), 0, datasize
);
529 if (!This
->imagedata
|| !rledata
)
536 offbits
.QuadPart
= sizeof(BITMAPFILEHEADER
) + This
->bih
.bV5Size
;
537 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
538 if (FAILED(hr
)) goto fail
;
540 hr
= IStream_Read(This
->stream
, palette
, palettesize
, &bytesread
);
541 if (FAILED(hr
) || bytesread
!= palettesize
) goto fail
;
544 offbits
.QuadPart
= This
->bfh
.bfOffBits
;
545 hr
= IStream_Seek(This
->stream
, offbits
, STREAM_SEEK_SET
, NULL
);
546 if (FAILED(hr
)) goto fail
;
548 hr
= IStream_Read(This
->stream
, rledata
, rlesize
, &bytesread
);
549 if (FAILED(hr
) || bytesread
!= rlesize
) goto fail
;
552 bgrdata
= (DWORD
*)This
->imagedata
;
555 rledataend
= rledata
+ rlesize
;
557 while (cursor
< rledataend
&& y
< height
)
559 BYTE length
= *cursor
++;
563 BYTE escape
= *cursor
++;
566 case 0: /* end of line */
570 case 1: /* end of bitmap */
573 if (cursor
< rledataend
)
579 default: /* absolute mode */
581 while (cursor
< rledataend
&& length
-- && x
< width
)
583 BYTE colors
= *cursor
++;
584 bgrdata
[y
*width
+ x
++] = palette
[colors
>>4];
585 if (length
-- && x
< width
)
586 bgrdata
[y
*width
+ x
++] = palette
[colors
&0xf];
590 if ((cursor
- rledata
) & 1) cursor
++; /* skip pad byte */
595 BYTE colors
= *cursor
++;
596 DWORD color1
= palette
[colors
>>4];
597 DWORD color2
= palette
[colors
&0xf];
598 while (length
-- && x
< width
)
600 bgrdata
[y
*width
+ x
++] = color1
;
601 if (length
-- && x
< width
)
602 bgrdata
[y
*width
+ x
++] = color2
;
610 HeapFree(GetProcessHeap(), 0, rledata
);
612 This
->imagedatastart
= This
->imagedata
+ (height
-1) * bytesperrow
;
613 This
->stride
= -bytesperrow
;
618 HeapFree(GetProcessHeap(), 0, rledata
);
619 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
620 This
->imagedata
= NULL
;
621 if (SUCCEEDED(hr
)) hr
= E_FAIL
;
625 static HRESULT
BmpFrameDecode_ReadUnsupported(BmpDecoder
* This
)
630 struct bitfields_format
{
631 WORD bitcount
; /* 0 for end of list */
636 const WICPixelFormatGUID
*pixelformat
;
637 ReadDataFunc read_data_func
;
640 static const struct bitfields_format bitfields_formats
[] = {
641 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555
,BmpFrameDecode_ReadUncompressed
},
642 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565
,BmpFrameDecode_ReadUncompressed
},
643 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR
,BmpFrameDecode_ReadUncompressed
},
644 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA
,BmpFrameDecode_ReadUncompressed
},
648 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl
= {
649 BmpFrameDecode_QueryInterface
,
650 BmpFrameDecode_AddRef
,
651 BmpFrameDecode_Release
,
652 BmpFrameDecode_GetSize
,
653 BmpFrameDecode_GetPixelFormat
,
654 BmpFrameDecode_GetResolution
,
655 BmpFrameDecode_CopyPalette
,
656 BmpFrameDecode_CopyPixels
,
657 BmpFrameDecode_GetMetadataQueryReader
,
658 BmpFrameDecode_GetColorContexts
,
659 BmpFrameDecode_GetThumbnail
662 static HRESULT
BmpDecoder_ReadHeaders(BmpDecoder
* This
, IStream
*stream
)
665 ULONG bytestoread
, bytesread
;
668 if (This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
671 hr
= IStream_Seek(stream
, seek
, STREAM_SEEK_SET
, NULL
);
672 if (FAILED(hr
)) return hr
;
674 hr
= IStream_Read(stream
, &This
->bfh
, sizeof(BITMAPFILEHEADER
), &bytesread
);
675 if (FAILED(hr
)) return hr
;
676 if (bytesread
!= sizeof(BITMAPFILEHEADER
) ||
677 This
->bfh
.bfType
!= 0x4d42 /* "BM" */) return E_FAIL
;
679 hr
= IStream_Read(stream
, &This
->bih
.bV5Size
, sizeof(DWORD
), &bytesread
);
680 if (FAILED(hr
)) return hr
;
681 if (bytesread
!= sizeof(DWORD
) ||
682 (This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER
) &&
683 This
->bih
.bV5Size
!= sizeof(BITMAPCOREHEADER2
) &&
684 This
->bih
.bV5Size
!= sizeof(BITMAPINFOHEADER
) &&
685 This
->bih
.bV5Size
!= sizeof(BITMAPV4HEADER
) &&
686 This
->bih
.bV5Size
!= sizeof(BITMAPV5HEADER
))) return E_FAIL
;
688 bytestoread
= This
->bih
.bV5Size
-sizeof(DWORD
);
689 hr
= IStream_Read(stream
, &This
->bih
.bV5Width
, bytestoread
, &bytesread
);
690 if (FAILED(hr
)) return hr
;
691 if (bytestoread
!= bytesread
) return E_FAIL
;
693 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
694 read the extra fields */
695 if (This
->bih
.bV5Size
== sizeof(BITMAPINFOHEADER
) &&
696 This
->bih
.bV5Compression
== BI_BITFIELDS
)
698 hr
= IStream_Read(stream
, &This
->bih
.bV5RedMask
, 12, &bytesread
);
699 if (FAILED(hr
)) return hr
;
700 if (bytesread
!= 12) return E_FAIL
;
701 This
->bih
.bV5AlphaMask
= 0;
704 /* decide what kind of bitmap this is and how/if we can read it */
705 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER
))
707 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)&This
->bih
;
708 TRACE("BITMAPCOREHEADER with depth=%i\n", bch
->bcBitCount
);
709 This
->bitsperpixel
= bch
->bcBitCount
;
710 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
711 switch(bch
->bcBitCount
)
714 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
717 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
720 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
723 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
726 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
729 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
730 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch
->bcBitCount
);
734 else /* struct is compatible with BITMAPINFOHEADER */
736 TRACE("bitmap header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
737 switch(This
->bih
.bV5Compression
)
740 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
741 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
742 switch(This
->bih
.bV5BitCount
)
745 This
->pixelformat
= &GUID_WICPixelFormat1bppIndexed
;
748 This
->pixelformat
= &GUID_WICPixelFormat2bppIndexed
;
751 This
->pixelformat
= &GUID_WICPixelFormat4bppIndexed
;
754 This
->pixelformat
= &GUID_WICPixelFormat8bppIndexed
;
757 This
->pixelformat
= &GUID_WICPixelFormat16bppBGR555
;
760 This
->pixelformat
= &GUID_WICPixelFormat24bppBGR
;
763 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
766 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
767 FIXME("unsupported bit depth %i for uncompressed RGB\n", This
->bih
.bV5BitCount
);
771 This
->bitsperpixel
= 32;
772 This
->read_data_func
= BmpFrameDecode_ReadRLE8
;
773 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
776 This
->bitsperpixel
= 32;
777 This
->read_data_func
= BmpFrameDecode_ReadRLE4
;
778 This
->pixelformat
= &GUID_WICPixelFormat32bppBGR
;
782 const struct bitfields_format
*format
;
783 if (This
->bih
.bV5Size
== sizeof(BITMAPCOREHEADER2
))
785 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
786 This
->bitsperpixel
= 0;
787 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
788 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
789 FIXME("Huffman 1D compression is unsupported\n");
792 This
->bitsperpixel
= This
->bih
.bV5BitCount
;
793 for (format
= bitfields_formats
; format
->bitcount
; format
++)
795 if ((format
->bitcount
== This
->bih
.bV5BitCount
) &&
796 (format
->redmask
== This
->bih
.bV5RedMask
) &&
797 (format
->greenmask
== This
->bih
.bV5GreenMask
) &&
798 (format
->bluemask
== This
->bih
.bV5BlueMask
) &&
799 (format
->alphamask
== This
->bih
.bV5AlphaMask
))
801 This
->read_data_func
= format
->read_data_func
;
802 This
->pixelformat
= format
->pixelformat
;
806 if (!format
->bitcount
)
808 This
->read_data_func
= BmpFrameDecode_ReadUncompressed
;
809 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
810 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
811 This
->bih
.bV5BitCount
, This
->bih
.bV5RedMask
, This
->bih
.bV5GreenMask
, This
->bih
.bV5BlueMask
, This
->bih
.bV5AlphaMask
);
816 This
->bitsperpixel
= 0;
817 This
->read_data_func
= BmpFrameDecode_ReadUnsupported
;
818 This
->pixelformat
= &GUID_WICPixelFormatUndefined
;
819 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This
->bih
.bV5Size
, This
->bih
.bV5Compression
, This
->bih
.bV5BitCount
);
824 This
->initialized
= TRUE
;
829 static HRESULT WINAPI
BmpDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
832 BmpDecoder
*This
= (BmpDecoder
*)iface
;
833 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
835 if (!ppv
) return E_INVALIDARG
;
837 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
844 return E_NOINTERFACE
;
847 IUnknown_AddRef((IUnknown
*)*ppv
);
851 static ULONG WINAPI
BmpDecoder_AddRef(IWICBitmapDecoder
*iface
)
853 BmpDecoder
*This
= (BmpDecoder
*)iface
;
854 ULONG ref
= InterlockedIncrement(&This
->ref
);
856 TRACE("(%p) refcount=%u\n", iface
, ref
);
861 static ULONG WINAPI
BmpDecoder_Release(IWICBitmapDecoder
*iface
)
863 BmpDecoder
*This
= (BmpDecoder
*)iface
;
864 ULONG ref
= InterlockedDecrement(&This
->ref
);
866 TRACE("(%p) refcount=%u\n", iface
, ref
);
870 if (This
->stream
) IStream_Release(This
->stream
);
871 HeapFree(GetProcessHeap(), 0, This
->imagedata
);
872 This
->lock
.DebugInfo
->Spare
[0] = 0;
873 DeleteCriticalSection(&This
->lock
);
874 HeapFree(GetProcessHeap(), 0, This
);
880 static HRESULT WINAPI
BmpDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
881 DWORD
*pdwCapability
)
884 BmpDecoder
*This
= (BmpDecoder
*)iface
;
886 EnterCriticalSection(&This
->lock
);
887 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
888 LeaveCriticalSection(&This
->lock
);
889 if (FAILED(hr
)) return hr
;
891 if (This
->read_data_func
== BmpFrameDecode_ReadUnsupported
)
894 *pdwCapability
= WICBitmapDecoderCapabilityCanDecodeAllImages
;
899 static HRESULT WINAPI
BmpDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
900 WICDecodeOptions cacheOptions
)
903 BmpDecoder
*This
= (BmpDecoder
*)iface
;
905 EnterCriticalSection(&This
->lock
);
906 hr
= BmpDecoder_ReadHeaders(This
, pIStream
);
910 This
->stream
= pIStream
;
911 IStream_AddRef(pIStream
);
913 LeaveCriticalSection(&This
->lock
);
918 static HRESULT WINAPI
BmpDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
919 GUID
*pguidContainerFormat
)
921 memcpy(pguidContainerFormat
, &GUID_ContainerFormatBmp
, sizeof(GUID
));
925 static HRESULT WINAPI
BmpDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
926 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
929 IWICComponentInfo
*compinfo
;
931 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
933 hr
= CreateComponentInfo(&CLSID_WICBmpDecoder
, &compinfo
);
934 if (FAILED(hr
)) return hr
;
936 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
937 (void**)ppIDecoderInfo
);
939 IWICComponentInfo_Release(compinfo
);
944 static HRESULT WINAPI
BmpDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
945 IWICPalette
*pIPalette
)
947 TRACE("(%p,%p)\n", iface
, pIPalette
);
949 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
952 static HRESULT WINAPI
BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
953 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
955 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
956 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
959 static HRESULT WINAPI
BmpDecoder_GetPreview(IWICBitmapDecoder
*iface
,
960 IWICBitmapSource
**ppIBitmapSource
)
962 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
963 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
966 static HRESULT WINAPI
BmpDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
967 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
969 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
970 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
973 static HRESULT WINAPI
BmpDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
974 IWICBitmapSource
**ppIThumbnail
)
976 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
977 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
980 static HRESULT WINAPI
BmpDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
987 static HRESULT WINAPI
BmpDecoder_GetFrame(IWICBitmapDecoder
*iface
,
988 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
990 BmpDecoder
*This
= (BmpDecoder
*)iface
;
992 if (index
!= 0) return E_INVALIDARG
;
994 if (!This
->stream
) return WINCODEC_ERR_WRONGSTATE
;
996 *ppIBitmapFrame
= (IWICBitmapFrameDecode
*)&This
->lpFrameVtbl
;
997 IWICBitmapDecoder_AddRef(iface
);
1002 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl
= {
1003 BmpDecoder_QueryInterface
,
1006 BmpDecoder_QueryCapability
,
1007 BmpDecoder_Initialize
,
1008 BmpDecoder_GetContainerFormat
,
1009 BmpDecoder_GetDecoderInfo
,
1010 BmpDecoder_CopyPalette
,
1011 BmpDecoder_GetMetadataQueryReader
,
1012 BmpDecoder_GetPreview
,
1013 BmpDecoder_GetColorContexts
,
1014 BmpDecoder_GetThumbnail
,
1015 BmpDecoder_GetFrameCount
,
1019 HRESULT
BmpDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1024 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1028 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1030 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder
));
1031 if (!This
) return E_OUTOFMEMORY
;
1033 This
->lpVtbl
= &BmpDecoder_Vtbl
;
1034 This
->lpFrameVtbl
= &BmpDecoder_FrameVtbl
;
1036 This
->initialized
= FALSE
;
1037 This
->stream
= NULL
;
1038 This
->imagedata
= NULL
;
1039 InitializeCriticalSection(&This
->lock
);
1040 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BmpDecoder.lock");
1042 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1043 IUnknown_Release((IUnknown
*)This
);