windowscodecs: Avoid an iface -> impl conversion from a non-method.
[wine.git] / dlls / windowscodecs / bmpdecode.c
blobbd0ace1a09d5844c64e34768c18e408daf8470cd
1 /*
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
19 #include "config.h"
21 #include <assert.h>
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "wingdi.h"
30 #include "objbase.h"
31 #include "wincodec.h"
33 #include "wincodecs_private.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
39 typedef struct {
40 DWORD bc2Size;
41 DWORD bc2Width;
42 DWORD bc2Height;
43 WORD bc2Planes;
44 WORD bc2BitCount;
45 DWORD bc2Compression;
46 DWORD bc2SizeImage;
47 DWORD bc2XRes;
48 DWORD bc2YRes;
49 DWORD bc2ClrUsed;
50 DWORD bc2ClrImportant;
51 /* same as BITMAPINFOHEADER until this point */
52 WORD bc2ResUnit;
53 WORD bc2Reserved;
54 WORD bc2Orientation;
55 WORD bc2Halftoning;
56 DWORD bc2HalftoneSize1;
57 DWORD bc2HalftoneSize2;
58 DWORD bc2ColorSpace;
59 DWORD bc2AppData;
60 } BITMAPCOREHEADER2;
62 typedef HRESULT (*ReadDataFunc)(BmpDecoder* This);
64 struct BmpDecoder {
65 const IWICBitmapDecoderVtbl *lpVtbl;
66 const IWICBitmapFrameDecodeVtbl *lpFrameVtbl;
67 LONG ref;
68 BOOL initialized;
69 IStream *stream;
70 ULONG palette_offset;
71 ULONG image_offset;
72 BITMAPV5HEADER bih;
73 const WICPixelFormatGUID *pixelformat;
74 int bitsperpixel;
75 ReadDataFunc read_data_func;
76 INT stride;
77 BYTE *imagedata;
78 BYTE *imagedatastart;
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,
90 void **ppv)
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))
100 *ppv = iface;
102 else
104 *ppv = NULL;
105 return E_NOINTERFACE;
108 IUnknown_AddRef((IUnknown*)*ppv);
109 return S_OK;
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;
138 else
140 *puiWidth = This->bih.bV5Width;
141 *puiHeight = abs(This->bih.bV5Height);
143 return S_OK;
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));
154 return S_OK;
157 static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, double *pDpiY)
159 switch (bih->bV5Size)
161 case sizeof(BITMAPCOREHEADER):
162 *pDpiX = 96.0;
163 *pDpiY = 96.0;
164 return S_OK;
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;
171 return S_OK;
172 default:
173 return E_FAIL;
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)
189 HRESULT hr;
190 BmpDecoder *This = impl_from_frame(iface);
191 int count;
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;
207 int i;
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)
215 hr = E_OUTOFMEMORY;
216 goto end;
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) {
226 hr = E_FAIL;
227 goto end;
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;
238 else
240 hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
241 goto end;
244 else
246 if (This->bih.bV5BitCount <= 8)
248 ULONG tablesize, bytesread;
249 LARGE_INTEGER offset;
250 int i;
252 if (This->bih.bV5ClrUsed == 0)
253 count = 1 << This->bih.bV5BitCount;
254 else
255 count = This->bih.bV5ClrUsed;
257 tablesize = sizeof(WICColor) * count;
258 wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
259 if (!wiccolors)
261 hr = E_OUTOFMEMORY;
262 goto end;
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) {
272 hr = E_FAIL;
273 goto end;
276 /* convert from BGR to BGRA by setting alpha to 100% */
277 for (i=0; i<count; i++)
278 wiccolors[i] |= 0xff000000;
280 else
282 hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
283 goto end;
287 end:
289 LeaveCriticalSection(&This->lock);
291 if (SUCCEEDED(hr))
292 hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count);
294 HeapFree(GetProcessHeap(), 0, wiccolors);
295 HeapFree(GetProcessHeap(), 0, bgrcolors);
296 return hr;
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);
303 HRESULT hr=S_OK;
304 UINT width, height;
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)
346 UINT bytesperrow;
347 UINT width, height;
348 UINT datasize;
349 int bottomup;
350 HRESULT hr;
351 LARGE_INTEGER offbits;
352 ULONG bytesread;
354 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
356 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
357 width = bch->bcWidth;
358 height = bch->bcHeight;
359 bottomup = 1;
361 else
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;
382 if (bottomup)
384 This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
385 This->stride = -bytesperrow;
387 else
389 This->imagedatastart = This->imagedata;
390 This->stride = bytesperrow;
392 return S_OK;
394 fail:
395 HeapFree(GetProcessHeap(), 0, This->imagedata);
396 This->imagedata = NULL;
397 if (SUCCEEDED(hr)) hr = E_FAIL;
398 return hr;
401 static HRESULT BmpFrameDecode_ReadRGB8(BmpDecoder* This)
403 HRESULT hr;
404 UINT width, height;
406 hr = IWICBitmapFrameDecode_GetSize((IWICBitmapFrameDecode*)&This->lpFrameVtbl, &width, &height);
408 if (SUCCEEDED(hr))
410 hr = BmpFrameDecode_ReadUncompressed(This);
413 if (SUCCEEDED(hr))
415 reverse_bgr8(This->bitsperpixel/8, This->imagedatastart,
416 width, height, This->stride);
419 return hr;
422 static HRESULT ReadByte(IStream *stream, BYTE *buffer, ULONG buffer_size,
423 ULONG *cursor, ULONG *bytesread, BYTE *result)
425 HRESULT hr=S_OK;
427 if (*bytesread == 0 || *cursor == *bytesread)
429 hr = IStream_Read(stream, buffer, buffer_size, bytesread);
430 *cursor = 0;
433 if (SUCCEEDED(hr))
435 if (*cursor < *bytesread)
436 *result = buffer[(*cursor)++];
437 else
438 hr = E_FAIL;
441 return hr;
444 static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
446 UINT bytesperrow;
447 UINT width, height;
448 BYTE rledata[4096];
449 UINT datasize, palettesize;
450 DWORD palette[256];
451 UINT x, y;
452 DWORD *bgrdata;
453 HRESULT hr;
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;
463 else
464 palettesize = 4 * 256;
466 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
467 if (!This->imagedata)
469 hr = E_OUTOFMEMORY;
470 goto fail;
473 /* read palette */
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;
481 /* read RLE data */
482 offbits.QuadPart = This->image_offset;
483 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
484 if (FAILED(hr)) goto fail;
486 /* decode RLE */
487 bgrdata = (DWORD*)This->imagedata;
488 x = 0;
489 y = 0;
490 cursor = 0;
491 bytesread = 0;
492 while (y < height)
494 BYTE length;
495 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
497 if (FAILED(hr))
498 goto fail;
499 else if (length == 0)
501 /* escape code */
502 BYTE escape;
503 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
504 if (FAILED(hr))
505 goto fail;
506 switch(escape)
508 case 0: /* end of line */
509 x = 0;
510 y++;
511 break;
512 case 1: /* end of bitmap */
513 goto end;
514 case 2: /* delta */
516 BYTE dx, dy;
517 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
518 if (SUCCEEDED(hr))
519 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
520 if (FAILED(hr))
521 goto fail;
522 x += dx;
523 y += dy;
524 break;
526 default: /* absolute mode */
527 length = escape;
528 while (length-- && x < width)
530 BYTE index;
531 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
532 if (FAILED(hr))
533 goto fail;
534 bgrdata[y*width + x++] = palette[index];
536 if (escape & 1)
537 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
538 if (FAILED(hr))
539 goto fail;
542 else
544 BYTE index;
545 DWORD color;
546 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
547 if (FAILED(hr))
548 goto fail;
549 color = palette[index];
550 while (length-- && x < width)
551 bgrdata[y*width + x++] = color;
555 end:
556 This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
557 This->stride = -bytesperrow;
559 return S_OK;
561 fail:
562 HeapFree(GetProcessHeap(), 0, This->imagedata);
563 This->imagedata = NULL;
564 if (SUCCEEDED(hr)) hr = E_FAIL;
565 return hr;
568 static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
570 UINT bytesperrow;
571 UINT width, height;
572 BYTE rledata[4096];
573 UINT datasize, palettesize;
574 DWORD palette[16];
575 UINT x, y;
576 DWORD *bgrdata;
577 HRESULT hr;
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;
587 else
588 palettesize = 4 * 16;
590 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
591 if (!This->imagedata)
593 hr = E_OUTOFMEMORY;
594 goto fail;
597 /* read palette */
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;
605 /* read RLE data */
606 offbits.QuadPart = This->image_offset;
607 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
608 if (FAILED(hr)) goto fail;
610 /* decode RLE */
611 bgrdata = (DWORD*)This->imagedata;
612 x = 0;
613 y = 0;
614 cursor = 0;
615 bytesread = 0;
616 while (y < height)
618 BYTE length;
619 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
621 if (FAILED(hr))
622 goto fail;
623 else if (length == 0)
625 /* escape code */
626 BYTE escape;
627 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
628 if (FAILED(hr))
629 goto fail;
630 switch(escape)
632 case 0: /* end of line */
633 x = 0;
634 y++;
635 break;
636 case 1: /* end of bitmap */
637 goto end;
638 case 2: /* delta */
640 BYTE dx, dy;
641 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
642 if (SUCCEEDED(hr))
643 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
644 if (FAILED(hr))
645 goto fail;
646 x += dx;
647 y += dy;
648 break;
650 default: /* absolute mode */
652 BYTE realsize=0;
653 length = escape;
654 while (length-- && x < width)
656 BYTE colors;
657 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
658 realsize++;
659 if (FAILED(hr))
660 goto fail;
661 bgrdata[y*width + x++] = palette[colors>>4];
662 if (length-- && x < width)
663 bgrdata[y*width + x++] = palette[colors&0xf];
664 else
665 break;
667 if (realsize & 1)
668 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
669 if (FAILED(hr))
670 goto fail;
674 else
676 BYTE colors;
677 DWORD color1;
678 DWORD color2;
679 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
680 if (FAILED(hr))
681 goto fail;
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;
689 else
690 break;
695 end:
696 This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
697 This->stride = -bytesperrow;
699 return S_OK;
701 fail:
702 HeapFree(GetProcessHeap(), 0, This->imagedata);
703 This->imagedata = NULL;
704 if (SUCCEEDED(hr)) hr = E_FAIL;
705 return hr;
708 static HRESULT BmpFrameDecode_ReadUnsupported(BmpDecoder* This)
710 return E_FAIL;
713 struct bitfields_format {
714 WORD bitcount; /* 0 for end of list */
715 DWORD redmask;
716 DWORD greenmask;
717 DWORD bluemask;
718 DWORD alphamask;
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)
748 HRESULT hr;
749 ULONG bytestoread, bytesread;
750 LARGE_INTEGER seek;
752 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
754 seek.QuadPart = 0;
755 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
756 if (FAILED(hr)) return hr;
758 if (!This->packed)
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;
782 if (This->packed)
783 This->palette_offset = This->bih.bV5Size;
784 else
785 This->palette_offset = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
787 if (This->icoframe)
789 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
791 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
792 bch->bcHeight /= 2;
794 else
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)
821 case 1:
822 This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
823 break;
824 case 2:
825 This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
826 break;
827 case 4:
828 This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
829 break;
830 case 8:
831 This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
832 break;
833 case 24:
834 This->pixelformat = &GUID_WICPixelFormat24bppBGR;
835 break;
836 default:
837 This->pixelformat = &GUID_WICPixelFormatUndefined;
838 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount);
839 break;
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)
847 case BI_RGB:
848 This->bitsperpixel = This->bih.bV5BitCount;
849 This->read_data_func = BmpFrameDecode_ReadUncompressed;
850 switch(This->bih.bV5BitCount)
852 case 1:
853 This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
854 break;
855 case 2:
856 This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
857 break;
858 case 4:
859 This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
860 break;
861 case 8:
862 This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
863 break;
864 case 16:
865 This->pixelformat = &GUID_WICPixelFormat16bppBGR555;
866 break;
867 case 24:
868 This->pixelformat = &GUID_WICPixelFormat24bppBGR;
869 break;
870 case 32:
871 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
872 break;
873 default:
874 This->pixelformat = &GUID_WICPixelFormatUndefined;
875 FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount);
877 break;
878 case BI_RLE8:
879 This->bitsperpixel = 32;
880 This->read_data_func = BmpFrameDecode_ReadRLE8;
881 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
882 break;
883 case BI_RLE4:
884 This->bitsperpixel = 32;
885 This->read_data_func = BmpFrameDecode_ReadRLE4;
886 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
887 break;
888 case BI_BITFIELDS:
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");
898 break;
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;
911 break;
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);
921 break;
923 default:
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);
928 break;
932 if (This->packed)
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;
940 else
941 palette_count = 0;
942 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
943 palette_size = sizeof(RGBTRIPLE) * palette_count;
944 else
945 palette_size = sizeof(RGBQUAD) * palette_count;
946 This->image_offset = This->palette_offset + palette_size;
949 This->initialized = TRUE;
951 return S_OK;
954 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
955 void **ppv)
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))
964 *ppv = This;
966 else
968 *ppv = NULL;
969 return E_NOINTERFACE;
972 IUnknown_AddRef((IUnknown*)*ppv);
973 return S_OK;
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);
983 return 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);
993 if (ref == 0)
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);
1002 return ref;
1005 static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
1006 DWORD *pdwCapability)
1008 HRESULT hr;
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)
1017 *pdwCapability = 0;
1018 else
1019 *pdwCapability = WICBitmapDecoderCapabilityCanDecodeAllImages;
1021 return S_OK;
1024 static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1025 WICDecodeOptions cacheOptions)
1027 HRESULT hr;
1028 BmpDecoder *This = (BmpDecoder*)iface;
1030 EnterCriticalSection(&This->lock);
1031 hr = BmpDecoder_ReadHeaders(This, pIStream);
1033 if (SUCCEEDED(hr))
1035 This->stream = pIStream;
1036 IStream_AddRef(pIStream);
1038 LeaveCriticalSection(&This->lock);
1040 return hr;
1043 static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1044 GUID *pguidContainerFormat)
1046 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
1047 return S_OK;
1050 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1051 IWICBitmapDecoderInfo **ppIDecoderInfo)
1053 HRESULT hr;
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);
1066 return hr;
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,
1106 UINT *pCount)
1108 *pCount = 1;
1109 return S_OK;
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);
1124 return S_OK;
1127 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = {
1128 BmpDecoder_QueryInterface,
1129 BmpDecoder_AddRef,
1130 BmpDecoder_Release,
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,
1141 BmpDecoder_GetFrame
1144 static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecoder)
1146 BmpDecoder *This;
1148 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder));
1149 if (!This) return E_OUTOFMEMORY;
1151 This->lpVtbl = &BmpDecoder_Vtbl;
1152 This->lpFrameVtbl = &BmpDecoder_FrameVtbl;
1153 This->ref = 1;
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;
1162 *ppDecoder = This;
1164 return S_OK;
1167 static HRESULT BmpDecoder_Construct(int packed, int icoframe, IUnknown *pUnkOuter, REFIID iid, void** ppv)
1169 BmpDecoder *This;
1170 HRESULT ret;
1172 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1174 *ppv = NULL;
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);
1184 return ret;
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;
1221 else
1222 *mask_offset = 0;
1224 *topdown = This->stride > 0;