Sunc with trunk revision 58971.
[reactos.git] / dll / win32 / windowscodecs / bmpdecode.c
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COM_NO_WINDOWS_H
22
23 #include <config.h>
24
25 #include <assert.h>
26 #include <stdarg.h>
27
28 #define COBJMACROS
29
30 #include <windef.h>
31 #include <winbase.h>
32 //#include "winreg.h"
33 #include <wingdi.h>
34 #include <objbase.h>
35 #include <wincodec.h>
36
37 #include "wincodecs_private.h"
38
39 #include <wine/debug.h>
40
41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
42
43 typedef struct {
44 DWORD bc2Size;
45 DWORD bc2Width;
46 DWORD bc2Height;
47 WORD bc2Planes;
48 WORD bc2BitCount;
49 DWORD bc2Compression;
50 DWORD bc2SizeImage;
51 DWORD bc2XRes;
52 DWORD bc2YRes;
53 DWORD bc2ClrUsed;
54 DWORD bc2ClrImportant;
55 /* same as BITMAPINFOHEADER until this point */
56 WORD bc2ResUnit;
57 WORD bc2Reserved;
58 WORD bc2Orientation;
59 WORD bc2Halftoning;
60 DWORD bc2HalftoneSize1;
61 DWORD bc2HalftoneSize2;
62 DWORD bc2ColorSpace;
63 DWORD bc2AppData;
64 } BITMAPCOREHEADER2;
65
66 typedef HRESULT (*ReadDataFunc)(BmpDecoder* This);
67
68 struct BmpDecoder {
69 IWICBitmapDecoder IWICBitmapDecoder_iface;
70 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
71 LONG ref;
72 BOOL initialized;
73 IStream *stream;
74 ULONG palette_offset;
75 ULONG image_offset;
76 BITMAPV5HEADER bih;
77 const WICPixelFormatGUID *pixelformat;
78 int bitsperpixel;
79 ReadDataFunc read_data_func;
80 INT stride;
81 BYTE *imagedata;
82 BYTE *imagedatastart;
83 CRITICAL_SECTION lock; /* must be held when initialized/imagedata is set or stream is accessed */
84 int packed; /* If TRUE, don't look for a file header and assume a packed DIB. */
85 int icoframe; /* If TRUE, this is a frame of a .ico file. */
86 };
87
88 static inline BmpDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
89 {
90 return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapDecoder_iface);
91 }
92
93 static inline BmpDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
94 {
95 return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapFrameDecode_iface);
96 }
97
98 static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
99 void **ppv)
100 {
101 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
102
103 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
104
105 if (!ppv) return E_INVALIDARG;
106
107 if (IsEqualIID(&IID_IUnknown, iid) ||
108 IsEqualIID(&IID_IWICBitmapSource, iid) ||
109 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
110 {
111 *ppv = &This->IWICBitmapFrameDecode_iface;
112 }
113 else
114 {
115 *ppv = NULL;
116 return E_NOINTERFACE;
117 }
118
119 IUnknown_AddRef((IUnknown*)*ppv);
120 return S_OK;
121 }
122
123 static ULONG WINAPI BmpFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
124 {
125 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
126
127 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
128 }
129
130 static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface)
131 {
132 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
133
134 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
135 }
136
137 static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
138 UINT *puiWidth, UINT *puiHeight)
139 {
140 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
141 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
142
143 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
144 {
145 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
146 *puiWidth = bch->bcWidth;
147 *puiHeight = bch->bcHeight;
148 }
149 else
150 {
151 *puiWidth = This->bih.bV5Width;
152 *puiHeight = abs(This->bih.bV5Height);
153 }
154 return S_OK;
155 }
156
157 static HRESULT WINAPI BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
158 WICPixelFormatGUID *pPixelFormat)
159 {
160 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
161 TRACE("(%p,%p)\n", iface, pPixelFormat);
162
163 memcpy(pPixelFormat, This->pixelformat, sizeof(GUID));
164
165 return S_OK;
166 }
167
168 static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, double *pDpiY)
169 {
170 switch (bih->bV5Size)
171 {
172 case sizeof(BITMAPCOREHEADER):
173 *pDpiX = 96.0;
174 *pDpiY = 96.0;
175 return S_OK;
176 case sizeof(BITMAPCOREHEADER2):
177 case sizeof(BITMAPINFOHEADER):
178 case sizeof(BITMAPV4HEADER):
179 case sizeof(BITMAPV5HEADER):
180 *pDpiX = bih->bV5XPelsPerMeter * 0.0254;
181 *pDpiY = bih->bV5YPelsPerMeter * 0.0254;
182 return S_OK;
183 default:
184 return E_FAIL;
185 }
186 }
187
188 static HRESULT WINAPI BmpFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
189 double *pDpiX, double *pDpiY)
190 {
191 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
192 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
193
194 return BmpHeader_GetResolution(&This->bih, pDpiX, pDpiY);
195 }
196
197 static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
198 IWICPalette *pIPalette)
199 {
200 HRESULT hr;
201 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
202 int count;
203 WICColor *wiccolors=NULL;
204 RGBTRIPLE *bgrcolors=NULL;
205
206 TRACE("(%p,%p)\n", iface, pIPalette);
207
208 EnterCriticalSection(&This->lock);
209
210 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
211 {
212 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
213 if (bch->bcBitCount <= 8)
214 {
215 /* 2**n colors in BGR format after the header */
216 ULONG tablesize, bytesread;
217 LARGE_INTEGER offset;
218 int i;
219
220 count = 1 << bch->bcBitCount;
221 wiccolors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count);
222 tablesize = sizeof(RGBTRIPLE) * count;
223 bgrcolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
224 if (!wiccolors || !bgrcolors)
225 {
226 hr = E_OUTOFMEMORY;
227 goto end;
228 }
229
230 offset.QuadPart = This->palette_offset;
231 hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
232 if (FAILED(hr)) goto end;
233
234 hr = IStream_Read(This->stream, bgrcolors, tablesize, &bytesread);
235 if (FAILED(hr)) goto end;
236 if (bytesread != tablesize) {
237 hr = E_FAIL;
238 goto end;
239 }
240
241 for (i=0; i<count; i++)
242 {
243 wiccolors[i] = 0xff000000|
244 (bgrcolors[i].rgbtRed<<16)|
245 (bgrcolors[i].rgbtGreen<<8)|
246 bgrcolors[i].rgbtBlue;
247 }
248 }
249 else
250 {
251 hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
252 goto end;
253 }
254 }
255 else
256 {
257 if (This->bih.bV5BitCount <= 8)
258 {
259 ULONG tablesize, bytesread;
260 LARGE_INTEGER offset;
261 int i;
262
263 if (This->bih.bV5ClrUsed == 0)
264 count = 1 << This->bih.bV5BitCount;
265 else
266 count = This->bih.bV5ClrUsed;
267
268 tablesize = sizeof(WICColor) * count;
269 wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
270 if (!wiccolors)
271 {
272 hr = E_OUTOFMEMORY;
273 goto end;
274 }
275
276 offset.QuadPart = This->palette_offset;
277 hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
278 if (FAILED(hr)) goto end;
279
280 hr = IStream_Read(This->stream, wiccolors, tablesize, &bytesread);
281 if (FAILED(hr)) goto end;
282 if (bytesread != tablesize) {
283 hr = E_FAIL;
284 goto end;
285 }
286
287 /* convert from BGR to BGRA by setting alpha to 100% */
288 for (i=0; i<count; i++)
289 wiccolors[i] |= 0xff000000;
290 }
291 else
292 {
293 hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
294 goto end;
295 }
296 }
297
298 end:
299
300 LeaveCriticalSection(&This->lock);
301
302 if (SUCCEEDED(hr))
303 hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count);
304
305 HeapFree(GetProcessHeap(), 0, wiccolors);
306 HeapFree(GetProcessHeap(), 0, bgrcolors);
307 return hr;
308 }
309
310 static HRESULT WINAPI BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
311 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
312 {
313 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
314 HRESULT hr=S_OK;
315 UINT width, height;
316 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
317
318 EnterCriticalSection(&This->lock);
319 if (!This->imagedata)
320 {
321 hr = This->read_data_func(This);
322 }
323 LeaveCriticalSection(&This->lock);
324 if (FAILED(hr)) return hr;
325
326 hr = BmpFrameDecode_GetSize(iface, &width, &height);
327 if (FAILED(hr)) return hr;
328
329 return copy_pixels(This->bitsperpixel, This->imagedatastart,
330 width, height, This->stride,
331 prc, cbStride, cbBufferSize, pbBuffer);
332 }
333
334 static HRESULT WINAPI BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
335 IWICMetadataQueryReader **ppIMetadataQueryReader)
336 {
337 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
338 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
339 }
340
341 static HRESULT WINAPI BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
342 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
343 {
344 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
345 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
346 }
347
348 static HRESULT WINAPI BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
349 IWICBitmapSource **ppIThumbnail)
350 {
351 TRACE("(%p,%p)\n", iface, ppIThumbnail);
352 return WINCODEC_ERR_CODECNOTHUMBNAIL;
353 }
354
355 static HRESULT BmpFrameDecode_ReadUncompressed(BmpDecoder* This)
356 {
357 UINT bytesperrow;
358 UINT width, height;
359 UINT datasize;
360 int bottomup;
361 HRESULT hr;
362 LARGE_INTEGER offbits;
363 ULONG bytesread;
364
365 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
366 {
367 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
368 width = bch->bcWidth;
369 height = bch->bcHeight;
370 bottomup = 1;
371 }
372 else
373 {
374 width = This->bih.bV5Width;
375 height = abs(This->bih.bV5Height);
376 bottomup = (This->bih.bV5Height > 0);
377 }
378
379 /* row sizes in BMP files must be divisible by 4 bytes */
380 bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
381 datasize = bytesperrow * height;
382
383 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
384 if (!This->imagedata) return E_OUTOFMEMORY;
385
386 offbits.QuadPart = This->image_offset;
387 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
388 if (FAILED(hr)) goto fail;
389
390 hr = IStream_Read(This->stream, This->imagedata, datasize, &bytesread);
391 if (FAILED(hr) || bytesread != datasize) goto fail;
392
393 if (bottomup)
394 {
395 This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
396 This->stride = -bytesperrow;
397 }
398 else
399 {
400 This->imagedatastart = This->imagedata;
401 This->stride = bytesperrow;
402 }
403 return S_OK;
404
405 fail:
406 HeapFree(GetProcessHeap(), 0, This->imagedata);
407 This->imagedata = NULL;
408 if (SUCCEEDED(hr)) hr = E_FAIL;
409 return hr;
410 }
411
412 static HRESULT BmpFrameDecode_ReadRGB8(BmpDecoder* This)
413 {
414 HRESULT hr;
415 UINT width, height;
416
417 hr = IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height);
418
419 if (SUCCEEDED(hr))
420 {
421 hr = BmpFrameDecode_ReadUncompressed(This);
422 }
423
424 if (SUCCEEDED(hr))
425 {
426 reverse_bgr8(This->bitsperpixel/8, This->imagedatastart,
427 width, height, This->stride);
428 }
429
430 return hr;
431 }
432
433 static HRESULT ReadByte(IStream *stream, BYTE *buffer, ULONG buffer_size,
434 ULONG *cursor, ULONG *bytesread, BYTE *result)
435 {
436 HRESULT hr=S_OK;
437
438 if (*bytesread == 0 || *cursor == *bytesread)
439 {
440 hr = IStream_Read(stream, buffer, buffer_size, bytesread);
441 *cursor = 0;
442 }
443
444 if (SUCCEEDED(hr))
445 {
446 if (*cursor < *bytesread)
447 *result = buffer[(*cursor)++];
448 else
449 hr = E_FAIL;
450 }
451
452 return hr;
453 }
454
455 static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
456 {
457 UINT bytesperrow;
458 UINT width, height;
459 BYTE rledata[4096];
460 UINT datasize, palettesize;
461 DWORD palette[256];
462 UINT x, y;
463 DWORD *bgrdata;
464 HRESULT hr;
465 LARGE_INTEGER offbits;
466 ULONG cursor=0, bytesread=0;
467
468 width = This->bih.bV5Width;
469 height = abs(This->bih.bV5Height);
470 bytesperrow = width * 4;
471 datasize = bytesperrow * height;
472 if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256)
473 palettesize = 4 * This->bih.bV5ClrUsed;
474 else
475 palettesize = 4 * 256;
476
477 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
478 if (!This->imagedata)
479 {
480 hr = E_OUTOFMEMORY;
481 goto fail;
482 }
483
484 /* read palette */
485 offbits.QuadPart = This->palette_offset;
486 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
487 if (FAILED(hr)) goto fail;
488
489 hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
490 if (FAILED(hr) || bytesread != palettesize) goto fail;
491
492 /* read RLE data */
493 offbits.QuadPart = This->image_offset;
494 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
495 if (FAILED(hr)) goto fail;
496
497 /* decode RLE */
498 bgrdata = (DWORD*)This->imagedata;
499 x = 0;
500 y = 0;
501 cursor = 0;
502 bytesread = 0;
503 while (y < height)
504 {
505 BYTE length;
506 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
507
508 if (FAILED(hr))
509 goto fail;
510 else if (length == 0)
511 {
512 /* escape code */
513 BYTE escape;
514 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
515 if (FAILED(hr))
516 goto fail;
517 switch(escape)
518 {
519 case 0: /* end of line */
520 x = 0;
521 y++;
522 break;
523 case 1: /* end of bitmap */
524 goto end;
525 case 2: /* delta */
526 {
527 BYTE dx, dy;
528 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
529 if (SUCCEEDED(hr))
530 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
531 if (FAILED(hr))
532 goto fail;
533 x += dx;
534 y += dy;
535 break;
536 }
537 default: /* absolute mode */
538 length = escape;
539 while (length-- && x < width)
540 {
541 BYTE index;
542 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
543 if (FAILED(hr))
544 goto fail;
545 bgrdata[y*width + x++] = palette[index];
546 }
547 if (escape & 1)
548 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
549 if (FAILED(hr))
550 goto fail;
551 }
552 }
553 else
554 {
555 BYTE index;
556 DWORD color;
557 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
558 if (FAILED(hr))
559 goto fail;
560 color = palette[index];
561 while (length-- && x < width)
562 bgrdata[y*width + x++] = color;
563 }
564 }
565
566 end:
567 This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
568 This->stride = -bytesperrow;
569
570 return S_OK;
571
572 fail:
573 HeapFree(GetProcessHeap(), 0, This->imagedata);
574 This->imagedata = NULL;
575 if (SUCCEEDED(hr)) hr = E_FAIL;
576 return hr;
577 }
578
579 static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
580 {
581 UINT bytesperrow;
582 UINT width, height;
583 BYTE rledata[4096];
584 UINT datasize, palettesize;
585 DWORD palette[16];
586 UINT x, y;
587 DWORD *bgrdata;
588 HRESULT hr;
589 LARGE_INTEGER offbits;
590 ULONG cursor=0, bytesread=0;
591
592 width = This->bih.bV5Width;
593 height = abs(This->bih.bV5Height);
594 bytesperrow = width * 4;
595 datasize = bytesperrow * height;
596 if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16)
597 palettesize = 4 * This->bih.bV5ClrUsed;
598 else
599 palettesize = 4 * 16;
600
601 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
602 if (!This->imagedata)
603 {
604 hr = E_OUTOFMEMORY;
605 goto fail;
606 }
607
608 /* read palette */
609 offbits.QuadPart = This->palette_offset;
610 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
611 if (FAILED(hr)) goto fail;
612
613 hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
614 if (FAILED(hr) || bytesread != palettesize) goto fail;
615
616 /* read RLE data */
617 offbits.QuadPart = This->image_offset;
618 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
619 if (FAILED(hr)) goto fail;
620
621 /* decode RLE */
622 bgrdata = (DWORD*)This->imagedata;
623 x = 0;
624 y = 0;
625 cursor = 0;
626 bytesread = 0;
627 while (y < height)
628 {
629 BYTE length;
630 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
631
632 if (FAILED(hr))
633 goto fail;
634 else if (length == 0)
635 {
636 /* escape code */
637 BYTE escape;
638 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
639 if (FAILED(hr))
640 goto fail;
641 switch(escape)
642 {
643 case 0: /* end of line */
644 x = 0;
645 y++;
646 break;
647 case 1: /* end of bitmap */
648 goto end;
649 case 2: /* delta */
650 {
651 BYTE dx, dy;
652 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
653 if (SUCCEEDED(hr))
654 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
655 if (FAILED(hr))
656 goto fail;
657 x += dx;
658 y += dy;
659 break;
660 }
661 default: /* absolute mode */
662 {
663 BYTE realsize=0;
664 length = escape;
665 while (length-- && x < width)
666 {
667 BYTE colors;
668 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
669 realsize++;
670 if (FAILED(hr))
671 goto fail;
672 bgrdata[y*width + x++] = palette[colors>>4];
673 if (length-- && x < width)
674 bgrdata[y*width + x++] = palette[colors&0xf];
675 else
676 break;
677 }
678 if (realsize & 1)
679 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
680 if (FAILED(hr))
681 goto fail;
682 }
683 }
684 }
685 else
686 {
687 BYTE colors;
688 DWORD color1;
689 DWORD color2;
690 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
691 if (FAILED(hr))
692 goto fail;
693 color1 = palette[colors>>4];
694 color2 = palette[colors&0xf];
695 while (length-- && x < width)
696 {
697 bgrdata[y*width + x++] = color1;
698 if (length-- && x < width)
699 bgrdata[y*width + x++] = color2;
700 else
701 break;
702 }
703 }
704 }
705
706 end:
707 This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
708 This->stride = -bytesperrow;
709
710 return S_OK;
711
712 fail:
713 HeapFree(GetProcessHeap(), 0, This->imagedata);
714 This->imagedata = NULL;
715 if (SUCCEEDED(hr)) hr = E_FAIL;
716 return hr;
717 }
718
719 static HRESULT BmpFrameDecode_ReadUnsupported(BmpDecoder* This)
720 {
721 return E_FAIL;
722 }
723
724 struct bitfields_format {
725 WORD bitcount; /* 0 for end of list */
726 DWORD redmask;
727 DWORD greenmask;
728 DWORD bluemask;
729 DWORD alphamask;
730 const WICPixelFormatGUID *pixelformat;
731 ReadDataFunc read_data_func;
732 };
733
734 static const struct bitfields_format bitfields_formats[] = {
735 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555,BmpFrameDecode_ReadUncompressed},
736 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565,BmpFrameDecode_ReadUncompressed},
737 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadUncompressed},
738 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA,BmpFrameDecode_ReadUncompressed},
739 {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadRGB8},
740 {0}
741 };
742
743 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl = {
744 BmpFrameDecode_QueryInterface,
745 BmpFrameDecode_AddRef,
746 BmpFrameDecode_Release,
747 BmpFrameDecode_GetSize,
748 BmpFrameDecode_GetPixelFormat,
749 BmpFrameDecode_GetResolution,
750 BmpFrameDecode_CopyPalette,
751 BmpFrameDecode_CopyPixels,
752 BmpFrameDecode_GetMetadataQueryReader,
753 BmpFrameDecode_GetColorContexts,
754 BmpFrameDecode_GetThumbnail
755 };
756
757 static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
758 {
759 HRESULT hr;
760 ULONG bytestoread, bytesread;
761 LARGE_INTEGER seek;
762
763 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
764
765 seek.QuadPart = 0;
766 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
767 if (FAILED(hr)) return hr;
768
769 if (!This->packed)
770 {
771 BITMAPFILEHEADER bfh;
772 hr = IStream_Read(stream, &bfh, sizeof(BITMAPFILEHEADER), &bytesread);
773 if (FAILED(hr)) return hr;
774 if (bytesread != sizeof(BITMAPFILEHEADER) ||
775 bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL;
776 This->image_offset = bfh.bfOffBits;
777 }
778
779 hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread);
780 if (FAILED(hr)) return hr;
781 if (bytesread != sizeof(DWORD) ||
782 (This->bih.bV5Size != sizeof(BITMAPCOREHEADER) &&
783 This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) &&
784 This->bih.bV5Size != sizeof(BITMAPINFOHEADER) &&
785 This->bih.bV5Size != sizeof(BITMAPV4HEADER) &&
786 This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL;
787
788 bytestoread = This->bih.bV5Size-sizeof(DWORD);
789 hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread);
790 if (FAILED(hr)) return hr;
791 if (bytestoread != bytesread) return E_FAIL;
792
793 if (This->packed)
794 This->palette_offset = This->bih.bV5Size;
795 else
796 This->palette_offset = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
797
798 if (This->icoframe)
799 {
800 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
801 {
802 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
803 bch->bcHeight /= 2;
804 }
805 else
806 {
807 This->bih.bV5Height /= 2;
808 }
809 }
810
811 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
812 read the extra fields */
813 if (This->bih.bV5Size == sizeof(BITMAPINFOHEADER) &&
814 This->bih.bV5Compression == BI_BITFIELDS)
815 {
816 hr = IStream_Read(stream, &This->bih.bV5RedMask, 12, &bytesread);
817 if (FAILED(hr)) return hr;
818 if (bytesread != 12) return E_FAIL;
819 This->bih.bV5AlphaMask = 0;
820 This->palette_offset += 12;
821 }
822
823 /* decide what kind of bitmap this is and how/if we can read it */
824 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
825 {
826 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
827 TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount);
828 This->bitsperpixel = bch->bcBitCount;
829 This->read_data_func = BmpFrameDecode_ReadUncompressed;
830 switch(bch->bcBitCount)
831 {
832 case 1:
833 This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
834 break;
835 case 2:
836 This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
837 break;
838 case 4:
839 This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
840 break;
841 case 8:
842 This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
843 break;
844 case 24:
845 This->pixelformat = &GUID_WICPixelFormat24bppBGR;
846 break;
847 default:
848 This->pixelformat = &GUID_WICPixelFormatUndefined;
849 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount);
850 break;
851 }
852 }
853 else /* struct is compatible with BITMAPINFOHEADER */
854 {
855 TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
856 switch(This->bih.bV5Compression)
857 {
858 case BI_RGB:
859 This->bitsperpixel = This->bih.bV5BitCount;
860 This->read_data_func = BmpFrameDecode_ReadUncompressed;
861 switch(This->bih.bV5BitCount)
862 {
863 case 1:
864 This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
865 break;
866 case 2:
867 This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
868 break;
869 case 4:
870 This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
871 break;
872 case 8:
873 This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
874 break;
875 case 16:
876 This->pixelformat = &GUID_WICPixelFormat16bppBGR555;
877 break;
878 case 24:
879 This->pixelformat = &GUID_WICPixelFormat24bppBGR;
880 break;
881 case 32:
882 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
883 break;
884 default:
885 This->pixelformat = &GUID_WICPixelFormatUndefined;
886 FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount);
887 }
888 break;
889 case BI_RLE8:
890 This->bitsperpixel = 32;
891 This->read_data_func = BmpFrameDecode_ReadRLE8;
892 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
893 break;
894 case BI_RLE4:
895 This->bitsperpixel = 32;
896 This->read_data_func = BmpFrameDecode_ReadRLE4;
897 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
898 break;
899 case BI_BITFIELDS:
900 {
901 const struct bitfields_format *format;
902 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER2))
903 {
904 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
905 This->bitsperpixel = 0;
906 This->read_data_func = BmpFrameDecode_ReadUnsupported;
907 This->pixelformat = &GUID_WICPixelFormatUndefined;
908 FIXME("Huffman 1D compression is unsupported\n");
909 break;
910 }
911 This->bitsperpixel = This->bih.bV5BitCount;
912 for (format = bitfields_formats; format->bitcount; format++)
913 {
914 if ((format->bitcount == This->bih.bV5BitCount) &&
915 (format->redmask == This->bih.bV5RedMask) &&
916 (format->greenmask == This->bih.bV5GreenMask) &&
917 (format->bluemask == This->bih.bV5BlueMask) &&
918 (format->alphamask == This->bih.bV5AlphaMask))
919 {
920 This->read_data_func = format->read_data_func;
921 This->pixelformat = format->pixelformat;
922 break;
923 }
924 }
925 if (!format->bitcount)
926 {
927 This->read_data_func = BmpFrameDecode_ReadUncompressed;
928 This->pixelformat = &GUID_WICPixelFormatUndefined;
929 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
930 This->bih.bV5BitCount, This->bih.bV5RedMask, This->bih.bV5GreenMask, This->bih.bV5BlueMask, This->bih.bV5AlphaMask);
931 }
932 break;
933 }
934 default:
935 This->bitsperpixel = 0;
936 This->read_data_func = BmpFrameDecode_ReadUnsupported;
937 This->pixelformat = &GUID_WICPixelFormatUndefined;
938 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
939 break;
940 }
941 }
942
943 if (This->packed)
944 {
945 /* In a packed DIB, the image follows the palette. */
946 ULONG palette_count, palette_size;
947 if (This->bih.bV5ClrUsed)
948 palette_count = This->bih.bV5ClrUsed;
949 else if (This->bih.bV5BitCount <= 8)
950 palette_count = 1 << This->bih.bV5BitCount;
951 else
952 palette_count = 0;
953 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
954 palette_size = sizeof(RGBTRIPLE) * palette_count;
955 else
956 palette_size = sizeof(RGBQUAD) * palette_count;
957 This->image_offset = This->palette_offset + palette_size;
958 }
959
960 This->initialized = TRUE;
961
962 return S_OK;
963 }
964
965 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
966 void **ppv)
967 {
968 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
969 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
970
971 if (!ppv) return E_INVALIDARG;
972
973 if (IsEqualIID(&IID_IUnknown, iid) ||
974 IsEqualIID(&IID_IWICBitmapDecoder, iid))
975 {
976 *ppv = &This->IWICBitmapDecoder_iface;
977 }
978 else
979 {
980 *ppv = NULL;
981 return E_NOINTERFACE;
982 }
983
984 IUnknown_AddRef((IUnknown*)*ppv);
985 return S_OK;
986 }
987
988 static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface)
989 {
990 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
991 ULONG ref = InterlockedIncrement(&This->ref);
992
993 TRACE("(%p) refcount=%u\n", iface, ref);
994
995 return ref;
996 }
997
998 static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface)
999 {
1000 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
1001 ULONG ref = InterlockedDecrement(&This->ref);
1002
1003 TRACE("(%p) refcount=%u\n", iface, ref);
1004
1005 if (ref == 0)
1006 {
1007 if (This->stream) IStream_Release(This->stream);
1008 HeapFree(GetProcessHeap(), 0, This->imagedata);
1009 This->lock.DebugInfo->Spare[0] = 0;
1010 DeleteCriticalSection(&This->lock);
1011 HeapFree(GetProcessHeap(), 0, This);
1012 }
1013
1014 return ref;
1015 }
1016
1017 static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1018 DWORD *capability)
1019 {
1020 HRESULT hr;
1021 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
1022
1023 TRACE("(%p,%p,%p)\n", iface, stream, capability);
1024
1025 if (!stream || !capability) return E_INVALIDARG;
1026
1027 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
1028 if (hr != S_OK) return hr;
1029
1030 *capability = This->read_data_func == BmpFrameDecode_ReadUnsupported ? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages;
1031 return S_OK;
1032 }
1033
1034 static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1035 WICDecodeOptions cacheOptions)
1036 {
1037 HRESULT hr;
1038 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
1039
1040 EnterCriticalSection(&This->lock);
1041 hr = BmpDecoder_ReadHeaders(This, pIStream);
1042
1043 if (SUCCEEDED(hr))
1044 {
1045 This->stream = pIStream;
1046 IStream_AddRef(pIStream);
1047 }
1048 LeaveCriticalSection(&This->lock);
1049
1050 return hr;
1051 }
1052
1053 static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1054 GUID *pguidContainerFormat)
1055 {
1056 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
1057 return S_OK;
1058 }
1059
1060 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1061 IWICBitmapDecoderInfo **ppIDecoderInfo)
1062 {
1063 HRESULT hr;
1064 IWICComponentInfo *compinfo;
1065
1066 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1067
1068 hr = CreateComponentInfo(&CLSID_WICBmpDecoder, &compinfo);
1069 if (FAILED(hr)) return hr;
1070
1071 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
1072 (void**)ppIDecoderInfo);
1073
1074 IWICComponentInfo_Release(compinfo);
1075
1076 return hr;
1077 }
1078
1079 static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface,
1080 IWICPalette *pIPalette)
1081 {
1082 TRACE("(%p,%p)\n", iface, pIPalette);
1083
1084 return WINCODEC_ERR_PALETTEUNAVAILABLE;
1085 }
1086
1087 static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1088 IWICMetadataQueryReader **ppIMetadataQueryReader)
1089 {
1090 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1091 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1092 }
1093
1094 static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface,
1095 IWICBitmapSource **ppIBitmapSource)
1096 {
1097 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1098 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1099 }
1100
1101 static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1102 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1103 {
1104 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1105 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1106 }
1107
1108 static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1109 IWICBitmapSource **ppIThumbnail)
1110 {
1111 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1112 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1113 }
1114
1115 static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1116 UINT *pCount)
1117 {
1118 if (!pCount) return E_INVALIDARG;
1119
1120 *pCount = 1;
1121 return S_OK;
1122 }
1123
1124 static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface,
1125 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1126 {
1127 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
1128
1129 if (index != 0) return E_INVALIDARG;
1130
1131 if (!This->stream) return WINCODEC_ERR_FRAMEMISSING;
1132
1133 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
1134 IWICBitmapDecoder_AddRef(iface);
1135
1136 return S_OK;
1137 }
1138
1139 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = {
1140 BmpDecoder_QueryInterface,
1141 BmpDecoder_AddRef,
1142 BmpDecoder_Release,
1143 BmpDecoder_QueryCapability,
1144 BmpDecoder_Initialize,
1145 BmpDecoder_GetContainerFormat,
1146 BmpDecoder_GetDecoderInfo,
1147 BmpDecoder_CopyPalette,
1148 BmpDecoder_GetMetadataQueryReader,
1149 BmpDecoder_GetPreview,
1150 BmpDecoder_GetColorContexts,
1151 BmpDecoder_GetThumbnail,
1152 BmpDecoder_GetFrameCount,
1153 BmpDecoder_GetFrame
1154 };
1155
1156 static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecoder)
1157 {
1158 BmpDecoder *This;
1159
1160 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder));
1161 if (!This) return E_OUTOFMEMORY;
1162
1163 This->IWICBitmapDecoder_iface.lpVtbl = &BmpDecoder_Vtbl;
1164 This->IWICBitmapFrameDecode_iface.lpVtbl = &BmpDecoder_FrameVtbl;
1165 This->ref = 1;
1166 This->initialized = FALSE;
1167 This->stream = NULL;
1168 This->imagedata = NULL;
1169 InitializeCriticalSection(&This->lock);
1170 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BmpDecoder.lock");
1171 This->packed = packed;
1172 This->icoframe = icoframe;
1173
1174 *ppDecoder = This;
1175
1176 return S_OK;
1177 }
1178
1179 static HRESULT BmpDecoder_Construct(int packed, int icoframe, IUnknown *pUnkOuter, REFIID iid, void** ppv)
1180 {
1181 BmpDecoder *This;
1182 HRESULT ret;
1183
1184 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1185
1186 *ppv = NULL;
1187
1188 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1189
1190 ret = BmpDecoder_Create(packed, icoframe, &This);
1191 if (FAILED(ret)) return ret;
1192
1193 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1194 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1195
1196 return ret;
1197 }
1198
1199 HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1200 {
1201 return BmpDecoder_Construct(FALSE, FALSE, pUnkOuter, iid, ppv);
1202 }
1203
1204 HRESULT DibDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1205 {
1206 return BmpDecoder_Construct(TRUE, FALSE, pUnkOuter, iid, ppv);
1207 }
1208
1209 HRESULT IcoDibDecoder_CreateInstance(BmpDecoder **ppDecoder)
1210 {
1211 return BmpDecoder_Create(TRUE, TRUE, ppDecoder);
1212 }
1213
1214 void BmpDecoder_GetWICDecoder(BmpDecoder *This, IWICBitmapDecoder **ppDecoder)
1215 {
1216 *ppDecoder = &This->IWICBitmapDecoder_iface;
1217 }
1218
1219 /* Return the offset where the mask of an icon might be, or 0 for failure. */
1220 void BmpDecoder_FindIconMask(BmpDecoder *This, ULONG *mask_offset, int *topdown)
1221 {
1222 assert(This->stream != NULL);
1223
1224 if (This->read_data_func == BmpFrameDecode_ReadUncompressed)
1225 {
1226 /* RGB or BITFIELDS data */
1227 ULONG width, height, bytesperrow, datasize;
1228 IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height);
1229 bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
1230 datasize = bytesperrow * height;
1231 *mask_offset = This->image_offset + datasize;
1232 }
1233 else
1234 *mask_offset = 0;
1235
1236 *topdown = This->stride > 0;
1237 }