[SHELL32] CDrivesFolder: Implement the eject and disconnect menu items. CORE-13841
[reactos.git] / dll / win32 / windowscodecs / bmpencode.c
index 682939f..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
@@ -23,6 +24,7 @@
 struct bmp_pixelformat {
     const WICPixelFormatGUID *guid;
     UINT bpp;
+    UINT colors; /* palette size */
     DWORD compression;
     DWORD redmask;
     DWORD greenmask;
@@ -31,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}
 };
@@ -53,6 +60,8 @@ typedef struct BmpFrameEncode {
     double xres, yres;
     UINT lineswritten;
     UINT stride;
+    WICColor palette[256];
+    UINT colors;
     BOOL committed;
 } BmpFrameEncode;
 
@@ -163,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));
@@ -183,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,
@@ -268,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);
 
@@ -284,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)
     {
@@ -309,6 +337,7 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
 
     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);
@@ -322,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;
 
@@ -437,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,
@@ -451,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)
@@ -504,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;