Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenbmpdecode.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2009 Vincent Povirk for CodeWeavers 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include "config.h" 00020 00021 #include <stdarg.h> 00022 00023 #define COBJMACROS 00024 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "winreg.h" 00028 #include "wingdi.h" 00029 #include "objbase.h" 00030 #include "wincodec.h" 00031 00032 #include "wincodecs_private.h" 00033 00034 #include "wine/debug.h" 00035 00036 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 00037 00038 typedef struct { 00039 DWORD bc2Size; 00040 DWORD bc2Width; 00041 DWORD bc2Height; 00042 WORD bc2Planes; 00043 WORD bc2BitCount; 00044 DWORD bc2Compression; 00045 DWORD bc2SizeImage; 00046 DWORD bc2XRes; 00047 DWORD bc2YRes; 00048 DWORD bc2ClrUsed; 00049 DWORD bc2ClrImportant; 00050 /* same as BITMAPINFOHEADER until this point */ 00051 WORD bc2ResUnit; 00052 WORD bc2Reserved; 00053 WORD bc2Orientation; 00054 WORD bc2Halftoning; 00055 DWORD bc2HalftoneSize1; 00056 DWORD bc2HalftoneSize2; 00057 DWORD bc2ColorSpace; 00058 DWORD bc2AppData; 00059 } BITMAPCOREHEADER2; 00060 00061 struct BmpDecoder; 00062 typedef HRESULT (*ReadDataFunc)(struct BmpDecoder* This); 00063 00064 typedef struct BmpDecoder { 00065 const IWICBitmapDecoderVtbl *lpVtbl; 00066 const IWICBitmapFrameDecodeVtbl *lpFrameVtbl; 00067 LONG ref; 00068 BOOL initialized; 00069 IStream *stream; 00070 BITMAPFILEHEADER bfh; 00071 BITMAPV5HEADER bih; 00072 const WICPixelFormatGUID *pixelformat; 00073 int bitsperpixel; 00074 ReadDataFunc read_data_func; 00075 INT stride; 00076 BYTE *imagedata; 00077 BYTE *imagedatastart; 00078 CRITICAL_SECTION lock; /* must be held when initialized/imagedata is set or stream is accessed */ 00079 } BmpDecoder; 00080 00081 static inline BmpDecoder *impl_from_frame(IWICBitmapFrameDecode *iface) 00082 { 00083 return CONTAINING_RECORD(iface, BmpDecoder, lpFrameVtbl); 00084 } 00085 00086 static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 00087 void **ppv) 00088 { 00089 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 00090 00091 if (!ppv) return E_INVALIDARG; 00092 00093 if (IsEqualIID(&IID_IUnknown, iid) || 00094 IsEqualIID(&IID_IWICBitmapSource, iid) || 00095 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 00096 { 00097 *ppv = iface; 00098 } 00099 else 00100 { 00101 *ppv = NULL; 00102 return E_NOINTERFACE; 00103 } 00104 00105 IUnknown_AddRef((IUnknown*)*ppv); 00106 return S_OK; 00107 } 00108 00109 static ULONG WINAPI BmpFrameDecode_AddRef(IWICBitmapFrameDecode *iface) 00110 { 00111 BmpDecoder *This = impl_from_frame(iface); 00112 00113 return IUnknown_AddRef((IUnknown*)This); 00114 } 00115 00116 static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface) 00117 { 00118 BmpDecoder *This = impl_from_frame(iface); 00119 00120 return IUnknown_Release((IUnknown*)This); 00121 } 00122 00123 static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface, 00124 UINT *puiWidth, UINT *puiHeight) 00125 { 00126 BmpDecoder *This = impl_from_frame(iface); 00127 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); 00128 00129 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 00130 { 00131 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 00132 *puiWidth = bch->bcWidth; 00133 *puiHeight = bch->bcHeight; 00134 } 00135 else 00136 { 00137 *puiWidth = This->bih.bV5Width; 00138 *puiHeight = abs(This->bih.bV5Height); 00139 } 00140 return S_OK; 00141 } 00142 00143 static HRESULT WINAPI BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, 00144 WICPixelFormatGUID *pPixelFormat) 00145 { 00146 BmpDecoder *This = impl_from_frame(iface); 00147 TRACE("(%p,%p)\n", iface, pPixelFormat); 00148 00149 memcpy(pPixelFormat, This->pixelformat, sizeof(GUID)); 00150 00151 return S_OK; 00152 } 00153 00154 static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, double *pDpiY) 00155 { 00156 switch (bih->bV5Size) 00157 { 00158 case sizeof(BITMAPCOREHEADER): 00159 *pDpiX = 96.0; 00160 *pDpiY = 96.0; 00161 return S_OK; 00162 case sizeof(BITMAPCOREHEADER2): 00163 case sizeof(BITMAPINFOHEADER): 00164 case sizeof(BITMAPV4HEADER): 00165 case sizeof(BITMAPV5HEADER): 00166 *pDpiX = bih->bV5XPelsPerMeter * 0.0254; 00167 *pDpiY = bih->bV5YPelsPerMeter * 0.0254; 00168 return S_OK; 00169 default: 00170 return E_FAIL; 00171 } 00172 } 00173 00174 static HRESULT WINAPI BmpFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, 00175 double *pDpiX, double *pDpiY) 00176 { 00177 BmpDecoder *This = impl_from_frame(iface); 00178 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); 00179 00180 return BmpHeader_GetResolution(&This->bih, pDpiX, pDpiY); 00181 } 00182 00183 static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, 00184 IWICPalette *pIPalette) 00185 { 00186 HRESULT hr; 00187 BmpDecoder *This = impl_from_frame(iface); 00188 int count; 00189 WICColor *wiccolors=NULL; 00190 RGBTRIPLE *bgrcolors=NULL; 00191 00192 TRACE("(%p,%p)\n", iface, pIPalette); 00193 00194 EnterCriticalSection(&This->lock); 00195 00196 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 00197 { 00198 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 00199 if (bch->bcBitCount <= 8) 00200 { 00201 /* 2**n colors in BGR format after the header */ 00202 ULONG tablesize, bytesread; 00203 LARGE_INTEGER offset; 00204 int i; 00205 00206 count = 1 << bch->bcBitCount; 00207 wiccolors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count); 00208 tablesize = sizeof(RGBTRIPLE) * count; 00209 bgrcolors = HeapAlloc(GetProcessHeap(), 0, tablesize); 00210 if (!wiccolors || !bgrcolors) 00211 { 00212 hr = E_OUTOFMEMORY; 00213 goto end; 00214 } 00215 00216 offset.QuadPart = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPCOREHEADER); 00217 hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL); 00218 if (FAILED(hr)) goto end; 00219 00220 hr = IStream_Read(This->stream, bgrcolors, tablesize, &bytesread); 00221 if (FAILED(hr)) goto end; 00222 if (bytesread != tablesize) { 00223 hr = E_FAIL; 00224 goto end; 00225 } 00226 00227 for (i=0; i<count; i++) 00228 { 00229 wiccolors[i] = 0xff000000| 00230 (bgrcolors[i].rgbtRed<<16)| 00231 (bgrcolors[i].rgbtGreen<<8)| 00232 bgrcolors[i].rgbtBlue; 00233 } 00234 } 00235 else 00236 { 00237 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 00238 goto end; 00239 } 00240 } 00241 else 00242 { 00243 if (This->bih.bV5BitCount <= 8) 00244 { 00245 ULONG tablesize, bytesread; 00246 LARGE_INTEGER offset; 00247 int i; 00248 00249 if (This->bih.bV5ClrUsed == 0) 00250 count = 1 << This->bih.bV5BitCount; 00251 else 00252 count = This->bih.bV5ClrUsed; 00253 00254 tablesize = sizeof(WICColor) * count; 00255 wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize); 00256 if (!wiccolors) 00257 { 00258 hr = E_OUTOFMEMORY; 00259 goto end; 00260 } 00261 00262 offset.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size; 00263 hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL); 00264 if (FAILED(hr)) goto end; 00265 00266 hr = IStream_Read(This->stream, wiccolors, tablesize, &bytesread); 00267 if (FAILED(hr)) goto end; 00268 if (bytesread != tablesize) { 00269 hr = E_FAIL; 00270 goto end; 00271 } 00272 00273 /* convert from BGR to BGRA by setting alpha to 100% */ 00274 for (i=0; i<count; i++) 00275 wiccolors[i] |= 0xff000000; 00276 } 00277 else 00278 { 00279 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 00280 goto end; 00281 } 00282 } 00283 00284 end: 00285 00286 LeaveCriticalSection(&This->lock); 00287 00288 if (SUCCEEDED(hr)) 00289 hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count); 00290 00291 HeapFree(GetProcessHeap(), 0, wiccolors); 00292 HeapFree(GetProcessHeap(), 0, bgrcolors); 00293 return hr; 00294 } 00295 00296 static HRESULT WINAPI BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 00297 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 00298 { 00299 BmpDecoder *This = impl_from_frame(iface); 00300 HRESULT hr=S_OK; 00301 UINT width, height; 00302 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 00303 00304 EnterCriticalSection(&This->lock); 00305 if (!This->imagedata) 00306 { 00307 hr = This->read_data_func(This); 00308 } 00309 LeaveCriticalSection(&This->lock); 00310 if (FAILED(hr)) return hr; 00311 00312 hr = BmpFrameDecode_GetSize(iface, &width, &height); 00313 if (FAILED(hr)) return hr; 00314 00315 return copy_pixels(This->bitsperpixel, This->imagedatastart, 00316 width, height, This->stride, 00317 prc, cbStride, cbBufferSize, pbBuffer); 00318 } 00319 00320 static HRESULT WINAPI BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 00321 IWICMetadataQueryReader **ppIMetadataQueryReader) 00322 { 00323 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 00324 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 00325 } 00326 00327 static HRESULT WINAPI BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 00328 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 00329 { 00330 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 00331 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 00332 } 00333 00334 static HRESULT WINAPI BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 00335 IWICBitmapSource **ppIThumbnail) 00336 { 00337 TRACE("(%p,%p)\n", iface, ppIThumbnail); 00338 return WINCODEC_ERR_CODECNOTHUMBNAIL; 00339 } 00340 00341 static HRESULT BmpFrameDecode_ReadUncompressed(BmpDecoder* This) 00342 { 00343 UINT bytesperrow; 00344 UINT width, height; 00345 UINT datasize; 00346 int bottomup; 00347 HRESULT hr; 00348 LARGE_INTEGER offbits; 00349 ULONG bytesread; 00350 00351 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 00352 { 00353 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 00354 width = bch->bcWidth; 00355 height = bch->bcHeight; 00356 bottomup = 1; 00357 } 00358 else 00359 { 00360 width = This->bih.bV5Width; 00361 height = abs(This->bih.bV5Height); 00362 bottomup = (This->bih.bV5Height > 0); 00363 } 00364 00365 /* row sizes in BMP files must be divisible by 4 bytes */ 00366 bytesperrow = (((width * This->bitsperpixel)+31)/32)*4; 00367 datasize = bytesperrow * height; 00368 00369 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); 00370 if (!This->imagedata) return E_OUTOFMEMORY; 00371 00372 offbits.QuadPart = This->bfh.bfOffBits; 00373 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 00374 if (FAILED(hr)) goto fail; 00375 00376 hr = IStream_Read(This->stream, This->imagedata, datasize, &bytesread); 00377 if (FAILED(hr) || bytesread != datasize) goto fail; 00378 00379 if (bottomup) 00380 { 00381 This->imagedatastart = This->imagedata + (height-1) * bytesperrow; 00382 This->stride = -bytesperrow; 00383 } 00384 else 00385 { 00386 This->imagedatastart = This->imagedata; 00387 This->stride = bytesperrow; 00388 } 00389 return S_OK; 00390 00391 fail: 00392 HeapFree(GetProcessHeap(), 0, This->imagedata); 00393 This->imagedata = NULL; 00394 if (SUCCEEDED(hr)) hr = E_FAIL; 00395 return hr; 00396 } 00397 00398 static HRESULT ReadByte(IStream *stream, BYTE *buffer, ULONG buffer_size, 00399 ULONG *cursor, ULONG *bytesread, BYTE *result) 00400 { 00401 HRESULT hr=S_OK; 00402 00403 if (*bytesread == 0 || *cursor == *bytesread) 00404 { 00405 hr = IStream_Read(stream, buffer, buffer_size, bytesread); 00406 *cursor = 0; 00407 } 00408 00409 if (SUCCEEDED(hr)) 00410 { 00411 if (*cursor < *bytesread) 00412 *result = buffer[(*cursor)++]; 00413 else 00414 hr = E_FAIL; 00415 } 00416 00417 return hr; 00418 } 00419 00420 static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This) 00421 { 00422 UINT bytesperrow; 00423 UINT width, height; 00424 BYTE rledata[4096]; 00425 UINT datasize, palettesize; 00426 DWORD palette[256]; 00427 UINT x, y; 00428 DWORD *bgrdata; 00429 HRESULT hr; 00430 LARGE_INTEGER offbits; 00431 ULONG cursor=0, bytesread=0; 00432 00433 width = This->bih.bV5Width; 00434 height = abs(This->bih.bV5Height); 00435 bytesperrow = width * 4; 00436 datasize = bytesperrow * height; 00437 if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256) 00438 palettesize = 4 * This->bih.bV5ClrUsed; 00439 else 00440 palettesize = 4 * 256; 00441 00442 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); 00443 if (!This->imagedata) 00444 { 00445 hr = E_OUTOFMEMORY; 00446 goto fail; 00447 } 00448 00449 /* read palette */ 00450 offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size; 00451 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 00452 if (FAILED(hr)) goto fail; 00453 00454 hr = IStream_Read(This->stream, palette, palettesize, &bytesread); 00455 if (FAILED(hr) || bytesread != palettesize) goto fail; 00456 00457 /* read RLE data */ 00458 offbits.QuadPart = This->bfh.bfOffBits; 00459 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 00460 if (FAILED(hr)) goto fail; 00461 00462 /* decode RLE */ 00463 bgrdata = (DWORD*)This->imagedata; 00464 x = 0; 00465 y = 0; 00466 cursor = 0; 00467 bytesread = 0; 00468 while (y < height) 00469 { 00470 BYTE length; 00471 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); 00472 00473 if (FAILED(hr)) 00474 goto fail; 00475 else if (length == 0) 00476 { 00477 /* escape code */ 00478 BYTE escape; 00479 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape); 00480 if (FAILED(hr)) 00481 goto fail; 00482 switch(escape) 00483 { 00484 case 0: /* end of line */ 00485 x = 0; 00486 y++; 00487 break; 00488 case 1: /* end of bitmap */ 00489 goto end; 00490 case 2: /* delta */ 00491 { 00492 BYTE dx, dy; 00493 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx); 00494 if (SUCCEEDED(hr)) 00495 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy); 00496 if (FAILED(hr)) 00497 goto fail; 00498 x += dx; 00499 y += dy; 00500 break; 00501 } 00502 default: /* absolute mode */ 00503 length = escape; 00504 while (length-- && x < width) 00505 { 00506 BYTE index; 00507 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index); 00508 if (FAILED(hr)) 00509 goto fail; 00510 bgrdata[y*width + x++] = palette[index]; 00511 } 00512 if (escape & 1) 00513 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */ 00514 if (FAILED(hr)) 00515 goto fail; 00516 } 00517 } 00518 else 00519 { 00520 BYTE index; 00521 DWORD color; 00522 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index); 00523 if (FAILED(hr)) 00524 goto fail; 00525 color = palette[index]; 00526 while (length-- && x < width) 00527 bgrdata[y*width + x++] = color; 00528 } 00529 } 00530 00531 end: 00532 This->imagedatastart = This->imagedata + (height-1) * bytesperrow; 00533 This->stride = -bytesperrow; 00534 00535 return S_OK; 00536 00537 fail: 00538 HeapFree(GetProcessHeap(), 0, This->imagedata); 00539 This->imagedata = NULL; 00540 if (SUCCEEDED(hr)) hr = E_FAIL; 00541 return hr; 00542 } 00543 00544 static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This) 00545 { 00546 UINT bytesperrow; 00547 UINT width, height; 00548 BYTE rledata[4096]; 00549 UINT datasize, palettesize; 00550 DWORD palette[16]; 00551 UINT x, y; 00552 DWORD *bgrdata; 00553 HRESULT hr; 00554 LARGE_INTEGER offbits; 00555 ULONG cursor=0, bytesread=0; 00556 00557 width = This->bih.bV5Width; 00558 height = abs(This->bih.bV5Height); 00559 bytesperrow = width * 4; 00560 datasize = bytesperrow * height; 00561 if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16) 00562 palettesize = 4 * This->bih.bV5ClrUsed; 00563 else 00564 palettesize = 4 * 16; 00565 00566 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); 00567 if (!This->imagedata) 00568 { 00569 hr = E_OUTOFMEMORY; 00570 goto fail; 00571 } 00572 00573 /* read palette */ 00574 offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size; 00575 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 00576 if (FAILED(hr)) goto fail; 00577 00578 hr = IStream_Read(This->stream, palette, palettesize, &bytesread); 00579 if (FAILED(hr) || bytesread != palettesize) goto fail; 00580 00581 /* read RLE data */ 00582 offbits.QuadPart = This->bfh.bfOffBits; 00583 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 00584 if (FAILED(hr)) goto fail; 00585 00586 /* decode RLE */ 00587 bgrdata = (DWORD*)This->imagedata; 00588 x = 0; 00589 y = 0; 00590 cursor = 0; 00591 bytesread = 0; 00592 while (y < height) 00593 { 00594 BYTE length; 00595 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); 00596 00597 if (FAILED(hr)) 00598 goto fail; 00599 else if (length == 0) 00600 { 00601 /* escape code */ 00602 BYTE escape; 00603 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape); 00604 if (FAILED(hr)) 00605 goto fail; 00606 switch(escape) 00607 { 00608 case 0: /* end of line */ 00609 x = 0; 00610 y++; 00611 break; 00612 case 1: /* end of bitmap */ 00613 goto end; 00614 case 2: /* delta */ 00615 { 00616 BYTE dx, dy; 00617 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx); 00618 if (SUCCEEDED(hr)) 00619 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy); 00620 if (FAILED(hr)) 00621 goto fail; 00622 x += dx; 00623 y += dy; 00624 break; 00625 } 00626 default: /* absolute mode */ 00627 { 00628 BYTE realsize=0; 00629 length = escape; 00630 while (length-- && x < width) 00631 { 00632 BYTE colors; 00633 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors); 00634 realsize++; 00635 if (FAILED(hr)) 00636 goto fail; 00637 bgrdata[y*width + x++] = palette[colors>>4]; 00638 if (length-- && x < width) 00639 bgrdata[y*width + x++] = palette[colors&0xf]; 00640 else 00641 break; 00642 } 00643 if (realsize & 1) 00644 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */ 00645 if (FAILED(hr)) 00646 goto fail; 00647 } 00648 } 00649 } 00650 else 00651 { 00652 BYTE colors; 00653 DWORD color1; 00654 DWORD color2; 00655 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors); 00656 if (FAILED(hr)) 00657 goto fail; 00658 color1 = palette[colors>>4]; 00659 color2 = palette[colors&0xf]; 00660 while (length-- && x < width) 00661 { 00662 bgrdata[y*width + x++] = color1; 00663 if (length-- && x < width) 00664 bgrdata[y*width + x++] = color2; 00665 else 00666 break; 00667 } 00668 } 00669 } 00670 00671 end: 00672 This->imagedatastart = This->imagedata + (height-1) * bytesperrow; 00673 This->stride = -bytesperrow; 00674 00675 return S_OK; 00676 00677 fail: 00678 HeapFree(GetProcessHeap(), 0, This->imagedata); 00679 This->imagedata = NULL; 00680 if (SUCCEEDED(hr)) hr = E_FAIL; 00681 return hr; 00682 } 00683 00684 static HRESULT BmpFrameDecode_ReadUnsupported(BmpDecoder* This) 00685 { 00686 return E_FAIL; 00687 } 00688 00689 struct bitfields_format { 00690 WORD bitcount; /* 0 for end of list */ 00691 DWORD redmask; 00692 DWORD greenmask; 00693 DWORD bluemask; 00694 DWORD alphamask; 00695 const WICPixelFormatGUID *pixelformat; 00696 ReadDataFunc read_data_func; 00697 }; 00698 00699 static const struct bitfields_format bitfields_formats[] = { 00700 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555,BmpFrameDecode_ReadUncompressed}, 00701 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565,BmpFrameDecode_ReadUncompressed}, 00702 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadUncompressed}, 00703 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA,BmpFrameDecode_ReadUncompressed}, 00704 {0} 00705 }; 00706 00707 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl = { 00708 BmpFrameDecode_QueryInterface, 00709 BmpFrameDecode_AddRef, 00710 BmpFrameDecode_Release, 00711 BmpFrameDecode_GetSize, 00712 BmpFrameDecode_GetPixelFormat, 00713 BmpFrameDecode_GetResolution, 00714 BmpFrameDecode_CopyPalette, 00715 BmpFrameDecode_CopyPixels, 00716 BmpFrameDecode_GetMetadataQueryReader, 00717 BmpFrameDecode_GetColorContexts, 00718 BmpFrameDecode_GetThumbnail 00719 }; 00720 00721 static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream) 00722 { 00723 HRESULT hr; 00724 ULONG bytestoread, bytesread; 00725 LARGE_INTEGER seek; 00726 00727 if (This->initialized) return WINCODEC_ERR_WRONGSTATE; 00728 00729 seek.QuadPart = 0; 00730 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 00731 if (FAILED(hr)) return hr; 00732 00733 hr = IStream_Read(stream, &This->bfh, sizeof(BITMAPFILEHEADER), &bytesread); 00734 if (FAILED(hr)) return hr; 00735 if (bytesread != sizeof(BITMAPFILEHEADER) || 00736 This->bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL; 00737 00738 hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread); 00739 if (FAILED(hr)) return hr; 00740 if (bytesread != sizeof(DWORD) || 00741 (This->bih.bV5Size != sizeof(BITMAPCOREHEADER) && 00742 This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) && 00743 This->bih.bV5Size != sizeof(BITMAPINFOHEADER) && 00744 This->bih.bV5Size != sizeof(BITMAPV4HEADER) && 00745 This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL; 00746 00747 bytestoread = This->bih.bV5Size-sizeof(DWORD); 00748 hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread); 00749 if (FAILED(hr)) return hr; 00750 if (bytestoread != bytesread) return E_FAIL; 00751 00752 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to 00753 read the extra fields */ 00754 if (This->bih.bV5Size == sizeof(BITMAPINFOHEADER) && 00755 This->bih.bV5Compression == BI_BITFIELDS) 00756 { 00757 hr = IStream_Read(stream, &This->bih.bV5RedMask, 12, &bytesread); 00758 if (FAILED(hr)) return hr; 00759 if (bytesread != 12) return E_FAIL; 00760 This->bih.bV5AlphaMask = 0; 00761 } 00762 00763 /* decide what kind of bitmap this is and how/if we can read it */ 00764 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 00765 { 00766 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 00767 TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount); 00768 This->bitsperpixel = bch->bcBitCount; 00769 This->read_data_func = BmpFrameDecode_ReadUncompressed; 00770 switch(bch->bcBitCount) 00771 { 00772 case 1: 00773 This->pixelformat = &GUID_WICPixelFormat1bppIndexed; 00774 break; 00775 case 2: 00776 This->pixelformat = &GUID_WICPixelFormat2bppIndexed; 00777 break; 00778 case 4: 00779 This->pixelformat = &GUID_WICPixelFormat4bppIndexed; 00780 break; 00781 case 8: 00782 This->pixelformat = &GUID_WICPixelFormat8bppIndexed; 00783 break; 00784 case 24: 00785 This->pixelformat = &GUID_WICPixelFormat24bppBGR; 00786 break; 00787 default: 00788 This->pixelformat = &GUID_WICPixelFormatUndefined; 00789 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount); 00790 break; 00791 } 00792 } 00793 else /* struct is compatible with BITMAPINFOHEADER */ 00794 { 00795 TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); 00796 switch(This->bih.bV5Compression) 00797 { 00798 case BI_RGB: 00799 This->bitsperpixel = This->bih.bV5BitCount; 00800 This->read_data_func = BmpFrameDecode_ReadUncompressed; 00801 switch(This->bih.bV5BitCount) 00802 { 00803 case 1: 00804 This->pixelformat = &GUID_WICPixelFormat1bppIndexed; 00805 break; 00806 case 2: 00807 This->pixelformat = &GUID_WICPixelFormat2bppIndexed; 00808 break; 00809 case 4: 00810 This->pixelformat = &GUID_WICPixelFormat4bppIndexed; 00811 break; 00812 case 8: 00813 This->pixelformat = &GUID_WICPixelFormat8bppIndexed; 00814 break; 00815 case 16: 00816 This->pixelformat = &GUID_WICPixelFormat16bppBGR555; 00817 break; 00818 case 24: 00819 This->pixelformat = &GUID_WICPixelFormat24bppBGR; 00820 break; 00821 case 32: 00822 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 00823 break; 00824 default: 00825 This->pixelformat = &GUID_WICPixelFormatUndefined; 00826 FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount); 00827 } 00828 break; 00829 case BI_RLE8: 00830 This->bitsperpixel = 32; 00831 This->read_data_func = BmpFrameDecode_ReadRLE8; 00832 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 00833 break; 00834 case BI_RLE4: 00835 This->bitsperpixel = 32; 00836 This->read_data_func = BmpFrameDecode_ReadRLE4; 00837 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 00838 break; 00839 case BI_BITFIELDS: 00840 { 00841 const struct bitfields_format *format; 00842 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER2)) 00843 { 00844 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */ 00845 This->bitsperpixel = 0; 00846 This->read_data_func = BmpFrameDecode_ReadUnsupported; 00847 This->pixelformat = &GUID_WICPixelFormatUndefined; 00848 FIXME("Huffman 1D compression is unsupported\n"); 00849 break; 00850 } 00851 This->bitsperpixel = This->bih.bV5BitCount; 00852 for (format = bitfields_formats; format->bitcount; format++) 00853 { 00854 if ((format->bitcount == This->bih.bV5BitCount) && 00855 (format->redmask == This->bih.bV5RedMask) && 00856 (format->greenmask == This->bih.bV5GreenMask) && 00857 (format->bluemask == This->bih.bV5BlueMask) && 00858 (format->alphamask == This->bih.bV5AlphaMask)) 00859 { 00860 This->read_data_func = format->read_data_func; 00861 This->pixelformat = format->pixelformat; 00862 break; 00863 } 00864 } 00865 if (!format->bitcount) 00866 { 00867 This->read_data_func = BmpFrameDecode_ReadUncompressed; 00868 This->pixelformat = &GUID_WICPixelFormatUndefined; 00869 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n", 00870 This->bih.bV5BitCount, This->bih.bV5RedMask, This->bih.bV5GreenMask, This->bih.bV5BlueMask, This->bih.bV5AlphaMask); 00871 } 00872 break; 00873 } 00874 default: 00875 This->bitsperpixel = 0; 00876 This->read_data_func = BmpFrameDecode_ReadUnsupported; 00877 This->pixelformat = &GUID_WICPixelFormatUndefined; 00878 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); 00879 break; 00880 } 00881 } 00882 00883 This->initialized = TRUE; 00884 00885 return S_OK; 00886 } 00887 00888 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 00889 void **ppv) 00890 { 00891 BmpDecoder *This = (BmpDecoder*)iface; 00892 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 00893 00894 if (!ppv) return E_INVALIDARG; 00895 00896 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) 00897 { 00898 *ppv = This; 00899 } 00900 else 00901 { 00902 *ppv = NULL; 00903 return E_NOINTERFACE; 00904 } 00905 00906 IUnknown_AddRef((IUnknown*)*ppv); 00907 return S_OK; 00908 } 00909 00910 static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface) 00911 { 00912 BmpDecoder *This = (BmpDecoder*)iface; 00913 ULONG ref = InterlockedIncrement(&This->ref); 00914 00915 TRACE("(%p) refcount=%u\n", iface, ref); 00916 00917 return ref; 00918 } 00919 00920 static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface) 00921 { 00922 BmpDecoder *This = (BmpDecoder*)iface; 00923 ULONG ref = InterlockedDecrement(&This->ref); 00924 00925 TRACE("(%p) refcount=%u\n", iface, ref); 00926 00927 if (ref == 0) 00928 { 00929 if (This->stream) IStream_Release(This->stream); 00930 HeapFree(GetProcessHeap(), 0, This->imagedata); 00931 This->lock.DebugInfo->Spare[0] = 0; 00932 DeleteCriticalSection(&This->lock); 00933 HeapFree(GetProcessHeap(), 0, This); 00934 } 00935 00936 return ref; 00937 } 00938 00939 static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream, 00940 DWORD *pdwCapability) 00941 { 00942 HRESULT hr; 00943 BmpDecoder *This = (BmpDecoder*)iface; 00944 00945 EnterCriticalSection(&This->lock); 00946 hr = BmpDecoder_ReadHeaders(This, pIStream); 00947 LeaveCriticalSection(&This->lock); 00948 if (FAILED(hr)) return hr; 00949 00950 if (This->read_data_func == BmpFrameDecode_ReadUnsupported) 00951 *pdwCapability = 0; 00952 else 00953 *pdwCapability = WICBitmapDecoderCapabilityCanDecodeAllImages; 00954 00955 return S_OK; 00956 } 00957 00958 static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 00959 WICDecodeOptions cacheOptions) 00960 { 00961 HRESULT hr; 00962 BmpDecoder *This = (BmpDecoder*)iface; 00963 00964 EnterCriticalSection(&This->lock); 00965 hr = BmpDecoder_ReadHeaders(This, pIStream); 00966 00967 if (SUCCEEDED(hr)) 00968 { 00969 This->stream = pIStream; 00970 IStream_AddRef(pIStream); 00971 } 00972 LeaveCriticalSection(&This->lock); 00973 00974 return hr; 00975 } 00976 00977 static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 00978 GUID *pguidContainerFormat) 00979 { 00980 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID)); 00981 return S_OK; 00982 } 00983 00984 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 00985 IWICBitmapDecoderInfo **ppIDecoderInfo) 00986 { 00987 HRESULT hr; 00988 IWICComponentInfo *compinfo; 00989 00990 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 00991 00992 hr = CreateComponentInfo(&CLSID_WICBmpDecoder, &compinfo); 00993 if (FAILED(hr)) return hr; 00994 00995 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 00996 (void**)ppIDecoderInfo); 00997 00998 IWICComponentInfo_Release(compinfo); 00999 01000 return hr; 01001 } 01002 01003 static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface, 01004 IWICPalette *pIPalette) 01005 { 01006 TRACE("(%p,%p)\n", iface, pIPalette); 01007 01008 return WINCODEC_ERR_PALETTEUNAVAILABLE; 01009 } 01010 01011 static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 01012 IWICMetadataQueryReader **ppIMetadataQueryReader) 01013 { 01014 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 01015 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 01016 } 01017 01018 static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface, 01019 IWICBitmapSource **ppIBitmapSource) 01020 { 01021 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 01022 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 01023 } 01024 01025 static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface, 01026 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 01027 { 01028 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 01029 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 01030 } 01031 01032 static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface, 01033 IWICBitmapSource **ppIThumbnail) 01034 { 01035 TRACE("(%p,%p)\n", iface, ppIThumbnail); 01036 return WINCODEC_ERR_CODECNOTHUMBNAIL; 01037 } 01038 01039 static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface, 01040 UINT *pCount) 01041 { 01042 *pCount = 1; 01043 return S_OK; 01044 } 01045 01046 static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface, 01047 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 01048 { 01049 BmpDecoder *This = (BmpDecoder*)iface; 01050 01051 if (index != 0) return E_INVALIDARG; 01052 01053 if (!This->stream) return WINCODEC_ERR_WRONGSTATE; 01054 01055 *ppIBitmapFrame = (IWICBitmapFrameDecode*)&This->lpFrameVtbl; 01056 IWICBitmapDecoder_AddRef(iface); 01057 01058 return S_OK; 01059 } 01060 01061 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = { 01062 BmpDecoder_QueryInterface, 01063 BmpDecoder_AddRef, 01064 BmpDecoder_Release, 01065 BmpDecoder_QueryCapability, 01066 BmpDecoder_Initialize, 01067 BmpDecoder_GetContainerFormat, 01068 BmpDecoder_GetDecoderInfo, 01069 BmpDecoder_CopyPalette, 01070 BmpDecoder_GetMetadataQueryReader, 01071 BmpDecoder_GetPreview, 01072 BmpDecoder_GetColorContexts, 01073 BmpDecoder_GetThumbnail, 01074 BmpDecoder_GetFrameCount, 01075 BmpDecoder_GetFrame 01076 }; 01077 01078 HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) 01079 { 01080 BmpDecoder *This; 01081 HRESULT ret; 01082 01083 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv); 01084 01085 *ppv = NULL; 01086 01087 if (pUnkOuter) return CLASS_E_NOAGGREGATION; 01088 01089 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder)); 01090 if (!This) return E_OUTOFMEMORY; 01091 01092 This->lpVtbl = &BmpDecoder_Vtbl; 01093 This->lpFrameVtbl = &BmpDecoder_FrameVtbl; 01094 This->ref = 1; 01095 This->initialized = FALSE; 01096 This->stream = NULL; 01097 This->imagedata = NULL; 01098 InitializeCriticalSection(&This->lock); 01099 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BmpDecoder.lock"); 01100 01101 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv); 01102 IUnknown_Release((IUnknown*)This); 01103 01104 return ret; 01105 } Generated on Sat May 26 2012 04:25:23 for ReactOS by
1.7.6.1
|