[SHELL32] CDrivesFolder: Implement the eject and disconnect menu items. CORE-13841
[reactos.git] / dll / win32 / windowscodecs / bmpencode.c
index 27922e7..5bc043a 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2009 Vincent Povirk for CodeWeavers
+ * Copyright 2016 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include "config.h"
-
-#include <stdarg.h>
-
-#define COBJMACROS
-
-#include "windef.h"
-#include "winbase.h"
-#include "winreg.h"
-#include "wingdi.h"
-#include "objbase.h"
-#include "wincodec.h"
-
 #include "wincodecs_private.h"
 
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+#include <wingdi.h>
 
 struct bmp_pixelformat {
     const WICPixelFormatGUID *guid;
     UINT bpp;
+    UINT colors; /* palette size */
     DWORD compression;
     DWORD redmask;
     DWORD greenmask;
@@ -46,13 +33,18 @@ struct bmp_pixelformat {
 };
 
 static const struct bmp_pixelformat formats[] = {
-    {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
-    {&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB},
-    {&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
-    {&GUID_WICPixelFormat32bppBGR, 32, BI_RGB},
+    {&GUID_WICPixelFormat24bppBGR, 24, 0, BI_RGB},
+    {&GUID_WICPixelFormatBlackWhite, 1, 2, BI_RGB},
+    {&GUID_WICPixelFormat1bppIndexed, 1, 2, BI_RGB},
+    {&GUID_WICPixelFormat2bppIndexed, 2, 4, BI_RGB},
+    {&GUID_WICPixelFormat4bppIndexed, 4, 16, BI_RGB},
+    {&GUID_WICPixelFormat8bppIndexed, 8, 256, BI_RGB},
+    {&GUID_WICPixelFormat16bppBGR555, 16, 0, BI_RGB},
+    {&GUID_WICPixelFormat16bppBGR565, 16, 0, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
+    {&GUID_WICPixelFormat32bppBGR, 32, 0, BI_RGB},
 #if 0
     /* Windows doesn't seem to support this one. */
-    {&GUID_WICPixelFormat32bppBGRA, 32, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
+    {&GUID_WICPixelFormat32bppBGRA, 32, 0, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
 #endif
     {NULL}
 };
@@ -68,6 +60,8 @@ typedef struct BmpFrameEncode {
     double xres, yres;
     UINT lineswritten;
     UINT stride;
+    WICColor palette[256];
+    UINT colors;
     BOOL committed;
 } BmpFrameEncode;
 
@@ -178,11 +172,13 @@ static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface
 
     for (i=0; formats[i].guid; i++)
     {
-        if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
+        if (IsEqualGUID(formats[i].guid, pPixelFormat))
             break;
     }
 
     if (!formats[i].guid) i = 0;
+    else if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormatBlackWhite))
+        i = 2; /* GUID_WICPixelFormat1bppIndexed */
 
     This->format = &formats[i];
     memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
@@ -198,10 +194,26 @@ static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *ifa
 }
 
 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
-    IWICPalette *pIPalette)
+    IWICPalette *palette)
 {
-    FIXME("(%p,%p): stub\n", iface, pIPalette);
-    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr;
+
+    TRACE("(%p,%p)\n", iface, palette);
+
+    if (!palette) return E_INVALIDARG;
+
+    if (!This->initialized)
+        return WINCODEC_ERR_NOTINITIALIZED;
+
+    hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
+    if (hr == S_OK)
+    {
+        UINT i;
+        for (i = 0; i < This->colors; i++)
+            This->palette[i] |= 0xff000000; /* BMP palette has no alpha */
+    }
+    return hr;
 }
 
 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
@@ -260,63 +272,22 @@ static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
 {
     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     HRESULT hr;
-    WICRect rc;
-    WICPixelFormatGUID guid;
     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
 
-    if (!This->initialized || !This->width || !This->height)
+    if (!This->initialized)
         return WINCODEC_ERR_WRONGSTATE;
 
-    if (!This->format)
-    {
-        hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
-        if (FAILED(hr)) return hr;
-        hr = BmpFrameEncode_SetPixelFormat(iface, &guid);
-        if (FAILED(hr)) return hr;
-    }
+    hr = configure_write_source(iface, pIBitmapSource, prc,
+        This->format ? This->format->guid : NULL, This->width, This->height,
+        This->xres, This->yres);
 
-    hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
-    if (FAILED(hr)) return hr;
-    if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
-    {
-        /* should use WICConvertBitmapSource to convert, but that's unimplemented */
-        ERR("format %s unsupported\n", debugstr_guid(&guid));
-        return E_FAIL;
-    }
-
-    if (This->xres == 0.0 || This->yres == 0.0)
-    {
-        double xres, yres;
-        hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
-        if (FAILED(hr)) return hr;
-        hr = BmpFrameEncode_SetResolution(iface, xres, yres);
-        if (FAILED(hr)) return hr;
-    }
-
-    if (!prc)
+    if (SUCCEEDED(hr))
     {
-        UINT width, height;
-        hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
-        if (FAILED(hr)) return hr;
-        rc.X = 0;
-        rc.Y = 0;
-        rc.Width = width;
-        rc.Height = height;
-        prc = &rc;
+        hr = write_source(iface, pIBitmapSource, prc,
+            This->format->guid, This->format->bpp, This->width, This->height);
     }
 
-    if (prc->Width != This->width) return E_INVALIDARG;
-
-    hr = BmpFrameEncode_AllocateBits(This);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, This->stride,
-        This->stride*(This->height-This->lineswritten),
-        This->bits + This->stride*This->lineswritten);
-
-    This->lineswritten += prc->Height;
-
-    return S_OK;
+    return hr;
 }
 
 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
@@ -324,10 +295,11 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     BITMAPFILEHEADER bfh;
     BITMAPV5HEADER bih;
-    UINT info_size;
+    UINT info_size, i;
     LARGE_INTEGER pos;
     ULONG byteswritten;
     HRESULT hr;
+    const BYTE *bits;
 
     TRACE("(%p)\n", iface);
 
@@ -340,15 +312,15 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
 
     bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
     bih.bV5Width = This->width;
-    bih.bV5Height = -This->height; /* top-down bitmap */
+    bih.bV5Height = This->height; /* bottom-top bitmap */
     bih.bV5Planes = 1;
     bih.bV5BitCount = This->format->bpp;
     bih.bV5Compression = This->format->compression;
     bih.bV5SizeImage = This->stride*This->height;
     bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
     bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
-    bih.bV5ClrUsed = 0;
-    bih.bV5ClrImportant = 0;
+    bih.bV5ClrUsed = (This->format->bpp <= 8) ? This->colors : 0;
+    bih.bV5ClrImportant = bih.bV5ClrUsed;
 
     if (This->format->compression == BI_BITFIELDS)
     {
@@ -360,11 +332,12 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
         bih.bV5GreenMask = This->format->greenmask;
         bih.bV5BlueMask = This->format->bluemask;
         bih.bV5AlphaMask = This->format->alphamask;
-        bih.bV5AlphaMask = LCS_DEVICE_RGB;
+        bih.bV5CSType = LCS_DEVICE_RGB;
     }
 
     bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
     bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
+    bfh.bfOffBits += bih.bV5ClrUsed * sizeof(WICColor);
 
     pos.QuadPart = 0;
     hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
@@ -378,9 +351,23 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
     if (FAILED(hr)) return hr;
     if (byteswritten != info_size) return E_FAIL;
 
-    hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
-    if (FAILED(hr)) return hr;
-    if (byteswritten != bih.bV5SizeImage) return E_FAIL;
+    /* write the palette */
+    if (This->format->colors)
+    {
+        hr = IStream_Write(This->stream, This->palette, This->colors * sizeof(WICColor), &byteswritten);
+        if (FAILED(hr)) return hr;
+        if (byteswritten != This->colors * sizeof(WICColor)) return E_FAIL;
+    }
+
+    /* write the image bits as a bottom-top array */
+    bits = This->bits + bih.bV5SizeImage;
+    for (i = 0; i < This->height; i++)
+    {
+        bits -= This->stride;
+        hr = IStream_Write(This->stream, bits, This->stride, &byteswritten);
+        if (FAILED(hr)) return hr;
+        if (byteswritten != This->stride) return E_FAIL;
+    }
 
     This->committed = TRUE;
 
@@ -493,11 +480,22 @@ static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
     return S_OK;
 }
 
-static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
-    IWICBitmapEncoderInfo **ppIEncoderInfo)
+static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
 {
-    FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
-    return E_NOTIMPL;
+    IWICComponentInfo *comp_info;
+    HRESULT hr;
+
+    TRACE("%p,%p\n", iface, info);
+
+    if (!info) return E_INVALIDARG;
+
+    hr = CreateComponentInfo(&CLSID_WICBmpEncoder, &comp_info);
+    if (hr == S_OK)
+    {
+        hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
+        IWICComponentInfo_Release(comp_info);
+    }
+    return hr;
 }
 
 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
@@ -507,10 +505,12 @@ static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
+static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
 {
-    TRACE("(%p,%p)\n", iface, pIPalette);
-    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+    BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
+
+    TRACE("(%p,%p)\n", iface, palette);
+    return This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
 }
 
 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
@@ -538,7 +538,7 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
 
     if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
 
-    hr = CreatePropertyBag2(ppIEncoderOptions);
+    hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions);
     if (FAILED(hr)) return hr;
 
     encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
@@ -560,6 +560,7 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
     encode->xres = 0.0;
     encode->yres = 0.0;
     encode->lineswritten = 0;
+    encode->colors = 0;
     encode->committed = FALSE;
 
     *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
@@ -601,17 +602,15 @@ static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
     BmpEncoder_GetMetadataQueryWriter
 };
 
-HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv)
 {
     BmpEncoder *This;
     HRESULT ret;
 
-    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+    TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
 
     *ppv = NULL;
 
-    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
-
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
     if (!This) return E_OUTOFMEMORY;