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