Vincent Povirk : windowscodecs: Implement CopyPixels for 8-bit ICO icons.

Alexandre Julliard julliard at winehq.org
Fri Aug 21 09:32:32 CDT 2009


Module: wine
Branch: master
Commit: 1c25ee8ce7b8d506a606d2313cd66843b6d631d3
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=1c25ee8ce7b8d506a606d2313cd66843b6d631d3

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Thu Aug 20 11:58:49 2009 -0500

windowscodecs: Implement CopyPixels for 8-bit ICO icons.

---

 dlls/windowscodecs/icoformat.c |  185 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 183 insertions(+), 2 deletions(-)

diff --git a/dlls/windowscodecs/icoformat.c b/dlls/windowscodecs/icoformat.c
index dfdf94b..cb545a1 100644
--- a/dlls/windowscodecs/icoformat.c
+++ b/dlls/windowscodecs/icoformat.c
@@ -24,6 +24,7 @@
 
 #include "windef.h"
 #include "winbase.h"
+#include "wingdi.h"
 #include "objbase.h"
 #include "wincodec.h"
 
@@ -68,6 +69,7 @@ typedef struct {
     LONG ref;
     ICONDIRENTRY entry;
     IcoDecoder *parent;
+    BYTE *bits;
 } IcoFrameDecode;
 
 static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
@@ -114,6 +116,7 @@ static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
     if (ref == 0)
     {
         IUnknown_Release((IUnknown*)This->parent);
+        HeapFree(GetProcessHeap(), 0, This->bits);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -154,11 +157,188 @@ static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
     return WINCODEC_ERR_PALETTEUNAVAILABLE;
 }
 
+static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
+{
+    if (transparent) *pixel = 0;
+    else *pixel |= 0xff000000;
+}
+
+static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This)
+{
+    BITMAPINFOHEADER bih;
+    DWORD colors[256];
+    UINT colorcount=0;
+    LARGE_INTEGER seek;
+    ULONG bytesread;
+    HRESULT hr;
+    BYTE *tempdata = NULL;
+    BYTE *bits = NULL;
+    UINT bitsStride;
+    UINT bitsSize;
+    UINT width, height;
+
+    width = This->entry.bWidth ? This->entry.bWidth : 256;
+    height = This->entry.bHeight ? This->entry.bHeight : 256;
+
+    /* read the BITMAPINFOHEADER */
+    seek.QuadPart = This->entry.dwDIBOffset;
+    hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread);
+    if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail;
+
+    if (This->entry.wBitCount <= 8)
+    {
+        /* read the palette */
+        colorcount = This->entry.bColorCount ? This->entry.bColorCount : 256;
+
+        hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread);
+        if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail;
+    }
+
+    bitsStride = width * 4;
+    bitsSize = bitsStride * height;
+
+    /* read the XOR data */
+    switch (This->entry.wBitCount)
+    {
+    case 8:
+    {
+        UINT xorBytesPerRow = (width+3)/4*4;
+        UINT xorBytes = xorBytesPerRow * height;
+        INT xorStride;
+        BYTE *xorRow;
+        BYTE *bitsRow;
+        UINT x, y;
+
+        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
+        if (!tempdata)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
+        if (FAILED(hr) || bytesread != xorBytes) goto fail;
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            xorStride = -xorBytesPerRow;
+            xorRow = tempdata + (height-1)*xorBytesPerRow;
+        }
+        else /* top-down DIB */
+        {
+            xorStride = xorBytesPerRow;
+            xorRow = tempdata;
+        }
+
+        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
+
+        /* palette-map the 8-bit data */
+        bitsRow = bits;
+        for (y=0; y<height; y++) {
+            BYTE *xorByte=xorRow;
+            DWORD *bitsPixel=(DWORD*)bitsRow;
+            for (x=0; x<width; x++)
+                *bitsPixel++ = colors[*xorByte++];
+            xorRow += xorStride;
+            bitsRow += bitsStride;
+        }
+
+        HeapFree(GetProcessHeap(), 0, tempdata);
+        break;
+    }
+    default:
+        FIXME("unsupported bitcount: %u\n", This->entry.wBitCount);
+        goto fail;
+    }
+
+    if (This->entry.wBitCount < 32)
+    {
+        /* set alpha data based on the AND mask */
+        UINT andBytesPerRow = (width+31)/32*4;
+        UINT andBytes = andBytesPerRow * height;
+        INT andStride;
+        BYTE *andRow;
+        BYTE *bitsRow;
+        UINT x, y;
+
+        tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
+        if (!tempdata)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        hr = IStream_Read(This->parent->stream, tempdata, andBytes, &bytesread);
+        if (FAILED(hr) || bytesread != andBytes) goto fail;
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            andStride = -andBytesPerRow;
+            andRow = tempdata + (height-1)*andBytesPerRow;
+        }
+        else /* top-down DIB */
+        {
+            andStride = andBytesPerRow;
+            andRow = tempdata;
+        }
+
+        bitsRow = bits;
+        for (y=0; y<height; y++) {
+            BYTE *andByte=andRow;
+            DWORD *bitsPixel=(DWORD*)bitsRow;
+            for (x=0; x<width; x+=8) {
+                BYTE andVal=*andByte++;
+                pixel_set_trans(bitsPixel++, andVal>>7&1);
+                if (x+1 < width) pixel_set_trans(bitsPixel++, andVal>>6&1);
+                if (x+2 < width) pixel_set_trans(bitsPixel++, andVal>>5&1);
+                if (x+3 < width) pixel_set_trans(bitsPixel++, andVal>>4&1);
+                if (x+4 < width) pixel_set_trans(bitsPixel++, andVal>>3&1);
+                if (x+5 < width) pixel_set_trans(bitsPixel++, andVal>>2&1);
+                if (x+6 < width) pixel_set_trans(bitsPixel++, andVal>>1&1);
+                if (x+7 < width) pixel_set_trans(bitsPixel++, andVal&1);
+            }
+            andRow += andStride;
+            bitsRow += bitsStride;
+        }
+
+        HeapFree(GetProcessHeap(), 0, tempdata);
+    }
+
+    This->bits = bits;
+
+    return S_OK;
+
+fail:
+    HeapFree(GetProcessHeap(), 0, tempdata);
+    HeapFree(GetProcessHeap(), 0, bits);
+    if (SUCCEEDED(hr)) hr = E_FAIL;
+    TRACE("<-- %x\n", hr);
+    return hr;
+}
+
 static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
-    FIXME("(%p,%p,%u,%u,%p): stub\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
-    return E_NOTIMPL;
+    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    HRESULT hr;
+    UINT width, height, stride;
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+    if (!This->bits)
+    {
+        hr = IcoFrameDecode_ReadPixels(This);
+        if (FAILED(hr)) return hr;
+    }
+
+    width = This->entry.bWidth ? This->entry.bWidth : 256;
+    height = This->entry.bHeight ? This->entry.bHeight : 256;
+    stride = width * 4;
+
+    return copy_pixels(32, This->bits, width, height, stride,
+        prc, cbStride, cbBufferSize, pbBuffer);
 }
 
 static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
@@ -362,6 +542,7 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
     result->lpVtbl = &IcoFrameDecode_Vtbl;
     result->ref = 1;
     result->parent = This;
+    result->bits = NULL;
 
     /* read the icon entry */
     seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index;




More information about the wine-cvs mailing list