2009-08-22 19:03:09 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2009 Vincent Povirk for CodeWeavers
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2018-03-04 23:19:05 +00:00
|
|
|
#include "config.h"
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
#include <assert.h>
|
2018-03-04 23:19:05 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winreg.h"
|
|
|
|
#include "wingdi.h"
|
|
|
|
#include "objbase.h"
|
|
|
|
|
|
|
|
#include "wincodecs_private.h"
|
|
|
|
|
|
|
|
#include "wine/debug.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
DWORD bc2Size;
|
|
|
|
DWORD bc2Width;
|
|
|
|
DWORD bc2Height;
|
|
|
|
WORD bc2Planes;
|
|
|
|
WORD bc2BitCount;
|
|
|
|
DWORD bc2Compression;
|
|
|
|
DWORD bc2SizeImage;
|
|
|
|
DWORD bc2XRes;
|
|
|
|
DWORD bc2YRes;
|
|
|
|
DWORD bc2ClrUsed;
|
|
|
|
DWORD bc2ClrImportant;
|
|
|
|
/* same as BITMAPINFOHEADER until this point */
|
|
|
|
WORD bc2ResUnit;
|
|
|
|
WORD bc2Reserved;
|
|
|
|
WORD bc2Orientation;
|
|
|
|
WORD bc2Halftoning;
|
|
|
|
DWORD bc2HalftoneSize1;
|
|
|
|
DWORD bc2HalftoneSize2;
|
|
|
|
DWORD bc2ColorSpace;
|
|
|
|
DWORD bc2AppData;
|
|
|
|
} BITMAPCOREHEADER2;
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
typedef HRESULT (*ReadDataFunc)(BmpDecoder* This);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
struct BmpDecoder {
|
|
|
|
IWICBitmapDecoder IWICBitmapDecoder_iface;
|
|
|
|
IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
|
2009-08-22 19:03:09 +00:00
|
|
|
LONG ref;
|
2010-04-20 21:18:54 +00:00
|
|
|
BOOL initialized;
|
2009-08-22 19:03:09 +00:00
|
|
|
IStream *stream;
|
2012-12-11 21:17:47 +00:00
|
|
|
ULONG palette_offset;
|
|
|
|
ULONG image_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
BITMAPV5HEADER bih;
|
|
|
|
const WICPixelFormatGUID *pixelformat;
|
|
|
|
int bitsperpixel;
|
|
|
|
ReadDataFunc read_data_func;
|
|
|
|
INT stride;
|
|
|
|
BYTE *imagedata;
|
|
|
|
BYTE *imagedatastart;
|
2010-04-20 21:18:54 +00:00
|
|
|
CRITICAL_SECTION lock; /* must be held when initialized/imagedata is set or stream is accessed */
|
2012-12-11 21:17:47 +00:00
|
|
|
int packed; /* If TRUE, don't look for a file header and assume a packed DIB. */
|
|
|
|
int icoframe; /* If TRUE, this is a frame of a .ico file. */
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline BmpDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapDecoder_iface);
|
|
|
|
}
|
2010-04-20 21:18:54 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
static inline BmpDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
|
2010-04-20 21:18:54 +00:00
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapFrameDecode_iface);
|
2010-04-20 21:18:54 +00:00
|
|
|
}
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
|
|
|
|
void **ppv)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
|
|
|
|
|
|
|
|
if (!ppv) return E_INVALIDARG;
|
|
|
|
|
|
|
|
if (IsEqualIID(&IID_IUnknown, iid) ||
|
|
|
|
IsEqualIID(&IID_IWICBitmapSource, iid) ||
|
|
|
|
IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
*ppv = &This->IWICBitmapFrameDecode_iface;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ppv = NULL;
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
IUnknown_AddRef((IUnknown*)*ppv);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI BmpFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
|
|
|
|
UINT *puiWidth, UINT *puiHeight)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
|
|
|
|
|
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
|
|
|
|
{
|
|
|
|
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
|
|
|
|
*puiWidth = bch->bcWidth;
|
|
|
|
*puiHeight = bch->bcHeight;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*puiWidth = This->bih.bV5Width;
|
|
|
|
*puiHeight = abs(This->bih.bV5Height);
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
|
|
|
|
WICPixelFormatGUID *pPixelFormat)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
TRACE("(%p,%p)\n", iface, pPixelFormat);
|
|
|
|
|
|
|
|
memcpy(pPixelFormat, This->pixelformat, sizeof(GUID));
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, double *pDpiY)
|
|
|
|
{
|
2013-05-23 16:39:54 +00:00
|
|
|
LONG resx = 0, resy = 0;
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
switch (bih->bV5Size)
|
|
|
|
{
|
2013-05-23 16:39:54 +00:00
|
|
|
default:
|
2009-08-22 19:03:09 +00:00
|
|
|
case sizeof(BITMAPCOREHEADER):
|
2013-05-23 16:39:54 +00:00
|
|
|
break;
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
case sizeof(BITMAPCOREHEADER2):
|
|
|
|
case sizeof(BITMAPINFOHEADER):
|
|
|
|
case sizeof(BITMAPV4HEADER):
|
|
|
|
case sizeof(BITMAPV5HEADER):
|
2013-05-23 16:39:54 +00:00
|
|
|
resx = bih->bV5XPelsPerMeter;
|
|
|
|
resy = bih->bV5YPelsPerMeter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!resx || !resy)
|
|
|
|
{
|
|
|
|
*pDpiX = 96.0;
|
|
|
|
*pDpiY = 96.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pDpiX = resx * 0.0254;
|
|
|
|
*pDpiY = resy * 0.0254;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
2013-05-23 16:39:54 +00:00
|
|
|
|
|
|
|
return S_OK;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
|
|
|
|
double *pDpiX, double *pDpiY)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
|
|
|
|
|
|
|
|
return BmpHeader_GetResolution(&This->bih, pDpiX, pDpiY);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
|
|
|
|
IWICPalette *pIPalette)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
int count;
|
|
|
|
WICColor *wiccolors=NULL;
|
|
|
|
RGBTRIPLE *bgrcolors=NULL;
|
|
|
|
|
|
|
|
TRACE("(%p,%p)\n", iface, pIPalette);
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
EnterCriticalSection(&This->lock);
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
|
|
|
|
{
|
|
|
|
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
|
|
|
|
if (bch->bcBitCount <= 8)
|
|
|
|
{
|
|
|
|
/* 2**n colors in BGR format after the header */
|
|
|
|
ULONG tablesize, bytesread;
|
|
|
|
LARGE_INTEGER offset;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
count = 1 << bch->bcBitCount;
|
|
|
|
wiccolors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count);
|
|
|
|
tablesize = sizeof(RGBTRIPLE) * count;
|
|
|
|
bgrcolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
|
|
|
|
if (!wiccolors || !bgrcolors)
|
|
|
|
{
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
offset.QuadPart = This->palette_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) goto end;
|
|
|
|
|
|
|
|
hr = IStream_Read(This->stream, bgrcolors, tablesize, &bytesread);
|
|
|
|
if (FAILED(hr)) goto end;
|
|
|
|
if (bytesread != tablesize) {
|
|
|
|
hr = E_FAIL;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<count; i++)
|
|
|
|
{
|
|
|
|
wiccolors[i] = 0xff000000|
|
|
|
|
(bgrcolors[i].rgbtRed<<16)|
|
|
|
|
(bgrcolors[i].rgbtGreen<<8)|
|
|
|
|
bgrcolors[i].rgbtBlue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-04-20 21:18:54 +00:00
|
|
|
hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
|
|
|
|
goto end;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (This->bih.bV5BitCount <= 8)
|
|
|
|
{
|
|
|
|
ULONG tablesize, bytesread;
|
|
|
|
LARGE_INTEGER offset;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (This->bih.bV5ClrUsed == 0)
|
|
|
|
count = 1 << This->bih.bV5BitCount;
|
|
|
|
else
|
2018-03-04 23:19:05 +00:00
|
|
|
count = min(This->bih.bV5ClrUsed, 1 << This->bih.bV5BitCount);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
tablesize = sizeof(WICColor) * count;
|
|
|
|
wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
|
2010-04-20 21:18:54 +00:00
|
|
|
if (!wiccolors)
|
|
|
|
{
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto end;
|
|
|
|
}
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
offset.QuadPart = This->palette_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) goto end;
|
|
|
|
|
|
|
|
hr = IStream_Read(This->stream, wiccolors, tablesize, &bytesread);
|
|
|
|
if (FAILED(hr)) goto end;
|
|
|
|
if (bytesread != tablesize) {
|
|
|
|
hr = E_FAIL;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert from BGR to BGRA by setting alpha to 100% */
|
|
|
|
for (i=0; i<count; i++)
|
|
|
|
wiccolors[i] |= 0xff000000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-04-20 21:18:54 +00:00
|
|
|
hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
|
|
|
|
goto end;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
2010-04-20 21:18:54 +00:00
|
|
|
|
|
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count);
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, wiccolors);
|
|
|
|
HeapFree(GetProcessHeap(), 0, bgrcolors);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
|
|
|
|
const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
|
2010-04-20 21:18:54 +00:00
|
|
|
HRESULT hr=S_OK;
|
2009-08-22 19:03:09 +00:00
|
|
|
UINT width, height;
|
|
|
|
TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
EnterCriticalSection(&This->lock);
|
2009-08-22 19:03:09 +00:00
|
|
|
if (!This->imagedata)
|
|
|
|
{
|
|
|
|
hr = This->read_data_func(This);
|
|
|
|
}
|
2010-04-20 21:18:54 +00:00
|
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
if (FAILED(hr)) return hr;
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
hr = BmpFrameDecode_GetSize(iface, &width, &height);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
|
|
|
|
return copy_pixels(This->bitsperpixel, This->imagedatastart,
|
|
|
|
width, height, This->stride,
|
|
|
|
prc, cbStride, cbBufferSize, pbBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
|
|
|
|
IWICMetadataQueryReader **ppIMetadataQueryReader)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
|
|
|
|
return WINCODEC_ERR_UNSUPPORTEDOPERATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
|
|
|
|
UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
|
|
|
|
return WINCODEC_ERR_UNSUPPORTEDOPERATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
|
|
|
|
IWICBitmapSource **ppIThumbnail)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%p)\n", iface, ppIThumbnail);
|
|
|
|
return WINCODEC_ERR_CODECNOTHUMBNAIL;
|
|
|
|
}
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
static HRESULT BmpFrameDecode_ReadUncompressed(BmpDecoder* This)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
UINT bytesperrow;
|
|
|
|
UINT width, height;
|
|
|
|
UINT datasize;
|
|
|
|
int bottomup;
|
|
|
|
HRESULT hr;
|
|
|
|
LARGE_INTEGER offbits;
|
|
|
|
ULONG bytesread;
|
|
|
|
|
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
|
|
|
|
{
|
|
|
|
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
|
|
|
|
width = bch->bcWidth;
|
|
|
|
height = bch->bcHeight;
|
|
|
|
bottomup = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
width = This->bih.bV5Width;
|
|
|
|
height = abs(This->bih.bV5Height);
|
|
|
|
bottomup = (This->bih.bV5Height > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* row sizes in BMP files must be divisible by 4 bytes */
|
|
|
|
bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
|
|
|
|
datasize = bytesperrow * height;
|
|
|
|
|
|
|
|
This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
|
|
|
|
if (!This->imagedata) return E_OUTOFMEMORY;
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
offbits.QuadPart = This->image_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) goto fail;
|
|
|
|
|
|
|
|
hr = IStream_Read(This->stream, This->imagedata, datasize, &bytesread);
|
|
|
|
if (FAILED(hr) || bytesread != datasize) goto fail;
|
|
|
|
|
|
|
|
if (bottomup)
|
|
|
|
{
|
|
|
|
This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
|
|
|
|
This->stride = -bytesperrow;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
This->imagedatastart = This->imagedata;
|
|
|
|
This->stride = bytesperrow;
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
HeapFree(GetProcessHeap(), 0, This->imagedata);
|
|
|
|
This->imagedata = NULL;
|
|
|
|
if (SUCCEEDED(hr)) hr = E_FAIL;
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
static HRESULT BmpFrameDecode_ReadRGB8(BmpDecoder* This)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
UINT width, height;
|
|
|
|
|
|
|
|
hr = IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
hr = BmpFrameDecode_ReadUncompressed(This);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
reverse_bgr8(This->bitsperpixel/8, This->imagedatastart,
|
|
|
|
width, height, This->stride);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
static HRESULT ReadByte(IStream *stream, BYTE *buffer, ULONG buffer_size,
|
|
|
|
ULONG *cursor, ULONG *bytesread, BYTE *result)
|
|
|
|
{
|
|
|
|
HRESULT hr=S_OK;
|
|
|
|
|
|
|
|
if (*bytesread == 0 || *cursor == *bytesread)
|
|
|
|
{
|
|
|
|
hr = IStream_Read(stream, buffer, buffer_size, bytesread);
|
|
|
|
*cursor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
if (*cursor < *bytesread)
|
|
|
|
*result = buffer[(*cursor)++];
|
|
|
|
else
|
|
|
|
hr = E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
UINT bytesperrow;
|
|
|
|
UINT width, height;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE rledata[4096];
|
|
|
|
UINT datasize, palettesize;
|
2009-08-22 19:03:09 +00:00
|
|
|
DWORD palette[256];
|
|
|
|
UINT x, y;
|
|
|
|
DWORD *bgrdata;
|
|
|
|
HRESULT hr;
|
|
|
|
LARGE_INTEGER offbits;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
ULONG cursor=0, bytesread=0;
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
width = This->bih.bV5Width;
|
|
|
|
height = abs(This->bih.bV5Height);
|
|
|
|
bytesperrow = width * 4;
|
|
|
|
datasize = bytesperrow * height;
|
|
|
|
if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256)
|
|
|
|
palettesize = 4 * This->bih.bV5ClrUsed;
|
|
|
|
else
|
|
|
|
palettesize = 4 * 256;
|
|
|
|
|
|
|
|
This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!This->imagedata)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read palette */
|
2012-12-11 21:17:47 +00:00
|
|
|
offbits.QuadPart = This->palette_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) goto fail;
|
|
|
|
|
|
|
|
hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
|
|
|
|
if (FAILED(hr) || bytesread != palettesize) goto fail;
|
|
|
|
|
|
|
|
/* read RLE data */
|
2012-12-11 21:17:47 +00:00
|
|
|
offbits.QuadPart = This->image_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) goto fail;
|
|
|
|
|
|
|
|
/* decode RLE */
|
|
|
|
bgrdata = (DWORD*)This->imagedata;
|
|
|
|
x = 0;
|
|
|
|
y = 0;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
cursor = 0;
|
|
|
|
bytesread = 0;
|
|
|
|
while (y < height)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE length;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
|
|
|
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
else if (length == 0)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
/* escape code */
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE escape;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
2009-08-22 19:03:09 +00:00
|
|
|
switch(escape)
|
|
|
|
{
|
|
|
|
case 0: /* end of line */
|
|
|
|
x = 0;
|
|
|
|
y++;
|
|
|
|
break;
|
|
|
|
case 1: /* end of bitmap */
|
|
|
|
goto end;
|
|
|
|
case 2: /* delta */
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
{
|
|
|
|
BYTE dx, dy;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
x += dx;
|
|
|
|
y += dy;
|
2009-08-22 19:03:09 +00:00
|
|
|
break;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
}
|
2009-08-22 19:03:09 +00:00
|
|
|
default: /* absolute mode */
|
|
|
|
length = escape;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
while (length-- && x < width)
|
|
|
|
{
|
|
|
|
BYTE index;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
bgrdata[y*width + x++] = palette[index];
|
|
|
|
}
|
|
|
|
if (escape & 1)
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE index;
|
|
|
|
DWORD color;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index);
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
color = palette[index];
|
2009-08-22 19:03:09 +00:00
|
|
|
while (length-- && x < width)
|
|
|
|
bgrdata[y*width + x++] = color;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
|
|
|
|
This->stride = -bytesperrow;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
HeapFree(GetProcessHeap(), 0, This->imagedata);
|
|
|
|
This->imagedata = NULL;
|
|
|
|
if (SUCCEEDED(hr)) hr = E_FAIL;
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
UINT bytesperrow;
|
|
|
|
UINT width, height;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE rledata[4096];
|
|
|
|
UINT datasize, palettesize;
|
2009-08-22 19:03:09 +00:00
|
|
|
DWORD palette[16];
|
|
|
|
UINT x, y;
|
|
|
|
DWORD *bgrdata;
|
|
|
|
HRESULT hr;
|
|
|
|
LARGE_INTEGER offbits;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
ULONG cursor=0, bytesread=0;
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
width = This->bih.bV5Width;
|
|
|
|
height = abs(This->bih.bV5Height);
|
|
|
|
bytesperrow = width * 4;
|
|
|
|
datasize = bytesperrow * height;
|
|
|
|
if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16)
|
|
|
|
palettesize = 4 * This->bih.bV5ClrUsed;
|
|
|
|
else
|
|
|
|
palettesize = 4 * 16;
|
|
|
|
|
|
|
|
This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!This->imagedata)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read palette */
|
2012-12-11 21:17:47 +00:00
|
|
|
offbits.QuadPart = This->palette_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) goto fail;
|
|
|
|
|
|
|
|
hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
|
|
|
|
if (FAILED(hr) || bytesread != palettesize) goto fail;
|
|
|
|
|
|
|
|
/* read RLE data */
|
2012-12-11 21:17:47 +00:00
|
|
|
offbits.QuadPart = This->image_offset;
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) goto fail;
|
|
|
|
|
|
|
|
/* decode RLE */
|
|
|
|
bgrdata = (DWORD*)This->imagedata;
|
|
|
|
x = 0;
|
|
|
|
y = 0;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
cursor = 0;
|
|
|
|
bytesread = 0;
|
|
|
|
while (y < height)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE length;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length);
|
|
|
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
else if (length == 0)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
/* escape code */
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE escape;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape);
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
2009-08-22 19:03:09 +00:00
|
|
|
switch(escape)
|
|
|
|
{
|
|
|
|
case 0: /* end of line */
|
|
|
|
x = 0;
|
|
|
|
y++;
|
|
|
|
break;
|
|
|
|
case 1: /* end of bitmap */
|
|
|
|
goto end;
|
|
|
|
case 2: /* delta */
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
{
|
|
|
|
BYTE dx, dy;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy);
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
x += dx;
|
|
|
|
y += dy;
|
2009-08-22 19:03:09 +00:00
|
|
|
break;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
}
|
2009-08-22 19:03:09 +00:00
|
|
|
default: /* absolute mode */
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
{
|
|
|
|
BYTE realsize=0;
|
2009-08-22 19:03:09 +00:00
|
|
|
length = escape;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
while (length-- && x < width)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE colors;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
|
|
|
|
realsize++;
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
2009-08-22 19:03:09 +00:00
|
|
|
bgrdata[y*width + x++] = palette[colors>>4];
|
|
|
|
if (length-- && x < width)
|
|
|
|
bgrdata[y*width + x++] = palette[colors&0xf];
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (realsize & 1)
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
}
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
BYTE colors;
|
|
|
|
DWORD color1;
|
|
|
|
DWORD color2;
|
|
|
|
hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors);
|
|
|
|
if (FAILED(hr))
|
|
|
|
goto fail;
|
|
|
|
color1 = palette[colors>>4];
|
|
|
|
color2 = palette[colors&0xf];
|
2009-08-22 19:03:09 +00:00
|
|
|
while (length-- && x < width)
|
|
|
|
{
|
|
|
|
bgrdata[y*width + x++] = color1;
|
|
|
|
if (length-- && x < width)
|
|
|
|
bgrdata[y*width + x++] = color2;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
|
|
|
|
This->stride = -bytesperrow;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
HeapFree(GetProcessHeap(), 0, This->imagedata);
|
|
|
|
This->imagedata = NULL;
|
|
|
|
if (SUCCEEDED(hr)) hr = E_FAIL;
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
static HRESULT BmpFrameDecode_ReadUnsupported(BmpDecoder* This)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bitfields_format {
|
|
|
|
WORD bitcount; /* 0 for end of list */
|
|
|
|
DWORD redmask;
|
|
|
|
DWORD greenmask;
|
|
|
|
DWORD bluemask;
|
|
|
|
DWORD alphamask;
|
|
|
|
const WICPixelFormatGUID *pixelformat;
|
|
|
|
ReadDataFunc read_data_func;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct bitfields_format bitfields_formats[] = {
|
|
|
|
{16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555,BmpFrameDecode_ReadUncompressed},
|
|
|
|
{16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565,BmpFrameDecode_ReadUncompressed},
|
|
|
|
{32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadUncompressed},
|
|
|
|
{32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA,BmpFrameDecode_ReadUncompressed},
|
2012-12-11 21:17:47 +00:00
|
|
|
{32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadRGB8},
|
2009-08-22 19:03:09 +00:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl = {
|
2009-08-22 19:03:09 +00:00
|
|
|
BmpFrameDecode_QueryInterface,
|
|
|
|
BmpFrameDecode_AddRef,
|
|
|
|
BmpFrameDecode_Release,
|
|
|
|
BmpFrameDecode_GetSize,
|
|
|
|
BmpFrameDecode_GetPixelFormat,
|
|
|
|
BmpFrameDecode_GetResolution,
|
|
|
|
BmpFrameDecode_CopyPalette,
|
|
|
|
BmpFrameDecode_CopyPixels,
|
|
|
|
BmpFrameDecode_GetMetadataQueryReader,
|
|
|
|
BmpFrameDecode_GetColorContexts,
|
|
|
|
BmpFrameDecode_GetThumbnail
|
|
|
|
};
|
|
|
|
|
|
|
|
static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
ULONG bytestoread, bytesread;
|
|
|
|
LARGE_INTEGER seek;
|
|
|
|
|
|
|
|
if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
|
|
|
|
|
|
|
|
seek.QuadPart = 0;
|
|
|
|
hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
if (!This->packed)
|
|
|
|
{
|
|
|
|
BITMAPFILEHEADER bfh;
|
|
|
|
hr = IStream_Read(stream, &bfh, sizeof(BITMAPFILEHEADER), &bytesread);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
if (bytesread != sizeof(BITMAPFILEHEADER) ||
|
|
|
|
bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL;
|
|
|
|
This->image_offset = bfh.bfOffBits;
|
|
|
|
}
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
if (bytesread != sizeof(DWORD) ||
|
|
|
|
(This->bih.bV5Size != sizeof(BITMAPCOREHEADER) &&
|
|
|
|
This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) &&
|
|
|
|
This->bih.bV5Size != sizeof(BITMAPINFOHEADER) &&
|
|
|
|
This->bih.bV5Size != sizeof(BITMAPV4HEADER) &&
|
|
|
|
This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL;
|
|
|
|
|
|
|
|
bytestoread = This->bih.bV5Size-sizeof(DWORD);
|
|
|
|
hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
if (bytestoread != bytesread) return E_FAIL;
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
if (This->packed)
|
|
|
|
This->palette_offset = This->bih.bV5Size;
|
|
|
|
else
|
|
|
|
This->palette_offset = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
|
|
|
|
|
|
|
|
if (This->icoframe)
|
|
|
|
{
|
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
|
|
|
|
{
|
|
|
|
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
|
|
|
|
bch->bcHeight /= 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
This->bih.bV5Height /= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
/* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
|
|
|
|
read the extra fields */
|
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPINFOHEADER) &&
|
|
|
|
This->bih.bV5Compression == BI_BITFIELDS)
|
|
|
|
{
|
|
|
|
hr = IStream_Read(stream, &This->bih.bV5RedMask, 12, &bytesread);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
if (bytesread != 12) return E_FAIL;
|
|
|
|
This->bih.bV5AlphaMask = 0;
|
2012-12-11 21:17:47 +00:00
|
|
|
This->palette_offset += 12;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* decide what kind of bitmap this is and how/if we can read it */
|
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
|
|
|
|
{
|
|
|
|
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
|
|
|
|
TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount);
|
|
|
|
This->bitsperpixel = bch->bcBitCount;
|
|
|
|
This->read_data_func = BmpFrameDecode_ReadUncompressed;
|
|
|
|
switch(bch->bcBitCount)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
|
|
|
|
break;
|
|
|
|
case 24:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat24bppBGR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormatUndefined;
|
|
|
|
WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* struct is compatible with BITMAPINFOHEADER */
|
|
|
|
{
|
|
|
|
TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
|
|
|
|
switch(This->bih.bV5Compression)
|
|
|
|
{
|
|
|
|
case BI_RGB:
|
|
|
|
This->bitsperpixel = This->bih.bV5BitCount;
|
|
|
|
This->read_data_func = BmpFrameDecode_ReadUncompressed;
|
|
|
|
switch(This->bih.bV5BitCount)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat16bppBGR555;
|
|
|
|
break;
|
|
|
|
case 24:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat24bppBGR;
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat32bppBGR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
This->pixelformat = &GUID_WICPixelFormatUndefined;
|
|
|
|
FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BI_RLE8:
|
|
|
|
This->bitsperpixel = 32;
|
|
|
|
This->read_data_func = BmpFrameDecode_ReadRLE8;
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat32bppBGR;
|
|
|
|
break;
|
|
|
|
case BI_RLE4:
|
|
|
|
This->bitsperpixel = 32;
|
|
|
|
This->read_data_func = BmpFrameDecode_ReadRLE4;
|
|
|
|
This->pixelformat = &GUID_WICPixelFormat32bppBGR;
|
|
|
|
break;
|
|
|
|
case BI_BITFIELDS:
|
|
|
|
{
|
|
|
|
const struct bitfields_format *format;
|
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER2))
|
|
|
|
{
|
|
|
|
/* BCH2 doesn't support bitfields; this is Huffman 1D compression */
|
|
|
|
This->bitsperpixel = 0;
|
|
|
|
This->read_data_func = BmpFrameDecode_ReadUnsupported;
|
|
|
|
This->pixelformat = &GUID_WICPixelFormatUndefined;
|
|
|
|
FIXME("Huffman 1D compression is unsupported\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
This->bitsperpixel = This->bih.bV5BitCount;
|
|
|
|
for (format = bitfields_formats; format->bitcount; format++)
|
|
|
|
{
|
|
|
|
if ((format->bitcount == This->bih.bV5BitCount) &&
|
|
|
|
(format->redmask == This->bih.bV5RedMask) &&
|
|
|
|
(format->greenmask == This->bih.bV5GreenMask) &&
|
|
|
|
(format->bluemask == This->bih.bV5BlueMask) &&
|
|
|
|
(format->alphamask == This->bih.bV5AlphaMask))
|
|
|
|
{
|
|
|
|
This->read_data_func = format->read_data_func;
|
|
|
|
This->pixelformat = format->pixelformat;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!format->bitcount)
|
|
|
|
{
|
|
|
|
This->read_data_func = BmpFrameDecode_ReadUncompressed;
|
|
|
|
This->pixelformat = &GUID_WICPixelFormatUndefined;
|
|
|
|
FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
|
|
|
|
This->bih.bV5BitCount, This->bih.bV5RedMask, This->bih.bV5GreenMask, This->bih.bV5BlueMask, This->bih.bV5AlphaMask);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
This->bitsperpixel = 0;
|
|
|
|
This->read_data_func = BmpFrameDecode_ReadUnsupported;
|
|
|
|
This->pixelformat = &GUID_WICPixelFormatUndefined;
|
|
|
|
FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
if (This->packed)
|
|
|
|
{
|
|
|
|
/* In a packed DIB, the image follows the palette. */
|
|
|
|
ULONG palette_count, palette_size;
|
|
|
|
if (This->bih.bV5ClrUsed)
|
|
|
|
palette_count = This->bih.bV5ClrUsed;
|
|
|
|
else if (This->bih.bV5BitCount <= 8)
|
|
|
|
palette_count = 1 << This->bih.bV5BitCount;
|
|
|
|
else
|
|
|
|
palette_count = 0;
|
|
|
|
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
|
|
|
|
palette_size = sizeof(RGBTRIPLE) * palette_count;
|
|
|
|
else
|
|
|
|
palette_size = sizeof(RGBQUAD) * palette_count;
|
|
|
|
This->image_offset = This->palette_offset + palette_size;
|
|
|
|
}
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
This->initialized = TRUE;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
|
|
|
|
void **ppv)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
|
|
|
|
|
|
|
|
if (!ppv) return E_INVALIDARG;
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
if (IsEqualIID(&IID_IUnknown, iid) ||
|
|
|
|
IsEqualIID(&IID_IWICBitmapDecoder, iid))
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
*ppv = &This->IWICBitmapDecoder_iface;
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ppv = NULL;
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
IUnknown_AddRef((IUnknown*)*ppv);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
ULONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
|
|
|
|
TRACE("(%p) refcount=%u\n", iface, ref);
|
|
|
|
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
ULONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
|
|
|
|
TRACE("(%p) refcount=%u\n", iface, ref);
|
|
|
|
|
|
|
|
if (ref == 0)
|
|
|
|
{
|
|
|
|
if (This->stream) IStream_Release(This->stream);
|
2010-04-20 21:18:54 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, This->imagedata);
|
|
|
|
This->lock.DebugInfo->Spare[0] = 0;
|
|
|
|
DeleteCriticalSection(&This->lock);
|
2009-08-22 19:03:09 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
|
|
|
|
DWORD *capability)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
TRACE("(%p,%p,%p)\n", iface, stream, capability);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
if (!stream || !capability) return E_INVALIDARG;
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
|
|
|
|
if (hr != S_OK) return hr;
|
|
|
|
|
|
|
|
*capability = This->read_data_func == BmpFrameDecode_ReadUnsupported ? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages;
|
2009-08-22 19:03:09 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
|
|
|
|
WICDecodeOptions cacheOptions)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
EnterCriticalSection(&This->lock);
|
2009-08-22 19:03:09 +00:00
|
|
|
hr = BmpDecoder_ReadHeaders(This, pIStream);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
This->stream = pIStream;
|
|
|
|
IStream_AddRef(pIStream);
|
|
|
|
}
|
2010-04-20 21:18:54 +00:00
|
|
|
LeaveCriticalSection(&This->lock);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
|
|
|
|
GUID *pguidContainerFormat)
|
|
|
|
{
|
|
|
|
memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
|
|
|
|
IWICBitmapDecoderInfo **ppIDecoderInfo)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
|
|
|
|
|
2018-06-04 02:55:39 +00:00
|
|
|
return get_decoder_info(&CLSID_WICBmpDecoder, ppIDecoderInfo);
|
2009-08-22 19:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface,
|
|
|
|
IWICPalette *pIPalette)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%p)\n", iface, pIPalette);
|
|
|
|
|
|
|
|
return WINCODEC_ERR_PALETTEUNAVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
|
|
|
|
IWICMetadataQueryReader **ppIMetadataQueryReader)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
|
|
|
|
return WINCODEC_ERR_UNSUPPORTEDOPERATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface,
|
|
|
|
IWICBitmapSource **ppIBitmapSource)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%p)\n", iface, ppIBitmapSource);
|
|
|
|
return WINCODEC_ERR_UNSUPPORTEDOPERATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface,
|
|
|
|
UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
|
|
|
|
return WINCODEC_ERR_UNSUPPORTEDOPERATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface,
|
|
|
|
IWICBitmapSource **ppIThumbnail)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%p)\n", iface, ppIThumbnail);
|
|
|
|
return WINCODEC_ERR_CODECNOTHUMBNAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface,
|
|
|
|
UINT *pCount)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
if (!pCount) return E_INVALIDARG;
|
|
|
|
|
2009-08-22 19:03:09 +00:00
|
|
|
*pCount = 1;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface,
|
|
|
|
UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
|
|
|
|
{
|
2012-12-11 21:17:47 +00:00
|
|
|
BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
if (index != 0) return E_INVALIDARG;
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
if (!This->stream) return WINCODEC_ERR_FRAMEMISSING;
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
*ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
|
2010-04-20 21:18:54 +00:00
|
|
|
IWICBitmapDecoder_AddRef(iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = {
|
|
|
|
BmpDecoder_QueryInterface,
|
|
|
|
BmpDecoder_AddRef,
|
|
|
|
BmpDecoder_Release,
|
|
|
|
BmpDecoder_QueryCapability,
|
|
|
|
BmpDecoder_Initialize,
|
|
|
|
BmpDecoder_GetContainerFormat,
|
|
|
|
BmpDecoder_GetDecoderInfo,
|
|
|
|
BmpDecoder_CopyPalette,
|
|
|
|
BmpDecoder_GetMetadataQueryReader,
|
|
|
|
BmpDecoder_GetPreview,
|
|
|
|
BmpDecoder_GetColorContexts,
|
|
|
|
BmpDecoder_GetThumbnail,
|
|
|
|
BmpDecoder_GetFrameCount,
|
|
|
|
BmpDecoder_GetFrame
|
|
|
|
};
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecoder)
|
2009-08-22 19:03:09 +00:00
|
|
|
{
|
|
|
|
BmpDecoder *This;
|
|
|
|
|
|
|
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder));
|
|
|
|
if (!This) return E_OUTOFMEMORY;
|
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
This->IWICBitmapDecoder_iface.lpVtbl = &BmpDecoder_Vtbl;
|
|
|
|
This->IWICBitmapFrameDecode_iface.lpVtbl = &BmpDecoder_FrameVtbl;
|
2009-08-22 19:03:09 +00:00
|
|
|
This->ref = 1;
|
|
|
|
This->initialized = FALSE;
|
|
|
|
This->stream = NULL;
|
2010-04-20 21:18:54 +00:00
|
|
|
This->imagedata = NULL;
|
|
|
|
InitializeCriticalSection(&This->lock);
|
|
|
|
This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BmpDecoder.lock");
|
2012-12-11 21:17:47 +00:00
|
|
|
This->packed = packed;
|
|
|
|
This->icoframe = icoframe;
|
|
|
|
|
|
|
|
*ppDecoder = This;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2014-04-24 12:12:56 +00:00
|
|
|
static HRESULT BmpDecoder_Construct(int packed, int icoframe, REFIID iid, void** ppv)
|
2012-12-11 21:17:47 +00:00
|
|
|
{
|
|
|
|
BmpDecoder *This;
|
|
|
|
HRESULT ret;
|
|
|
|
|
2014-04-24 12:12:56 +00:00
|
|
|
TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
|
2012-12-11 21:17:47 +00:00
|
|
|
|
|
|
|
*ppv = NULL;
|
|
|
|
|
|
|
|
ret = BmpDecoder_Create(packed, icoframe, &This);
|
|
|
|
if (FAILED(ret)) return ret;
|
2009-08-22 19:03:09 +00:00
|
|
|
|
2012-12-11 21:17:47 +00:00
|
|
|
ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
|
|
|
|
IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
|
2009-08-22 19:03:09 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2012-12-11 21:17:47 +00:00
|
|
|
|
2014-04-24 12:12:56 +00:00
|
|
|
HRESULT BmpDecoder_CreateInstance(REFIID iid, void** ppv)
|
2012-12-11 21:17:47 +00:00
|
|
|
{
|
2014-04-24 12:12:56 +00:00
|
|
|
return BmpDecoder_Construct(FALSE, FALSE, iid, ppv);
|
2012-12-11 21:17:47 +00:00
|
|
|
}
|
|
|
|
|
2014-04-24 12:12:56 +00:00
|
|
|
HRESULT DibDecoder_CreateInstance(REFIID iid, void** ppv)
|
2012-12-11 21:17:47 +00:00
|
|
|
{
|
2014-04-24 12:12:56 +00:00
|
|
|
return BmpDecoder_Construct(TRUE, FALSE, iid, ppv);
|
2012-12-11 21:17:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT IcoDibDecoder_CreateInstance(BmpDecoder **ppDecoder)
|
|
|
|
{
|
|
|
|
return BmpDecoder_Create(TRUE, TRUE, ppDecoder);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BmpDecoder_GetWICDecoder(BmpDecoder *This, IWICBitmapDecoder **ppDecoder)
|
|
|
|
{
|
|
|
|
*ppDecoder = &This->IWICBitmapDecoder_iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the offset where the mask of an icon might be, or 0 for failure. */
|
|
|
|
void BmpDecoder_FindIconMask(BmpDecoder *This, ULONG *mask_offset, int *topdown)
|
|
|
|
{
|
|
|
|
assert(This->stream != NULL);
|
|
|
|
|
|
|
|
if (This->read_data_func == BmpFrameDecode_ReadUncompressed)
|
|
|
|
{
|
|
|
|
/* RGB or BITFIELDS data */
|
|
|
|
ULONG width, height, bytesperrow, datasize;
|
|
|
|
IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height);
|
|
|
|
bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
|
|
|
|
datasize = bytesperrow * height;
|
|
|
|
*mask_offset = This->image_offset + datasize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*mask_offset = 0;
|
|
|
|
|
|
|
|
*topdown = This->stride > 0;
|
|
|
|
}
|