ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

bmpdecode.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.