From 46431d73e36904c2206d1dc6e0e320636744aa64 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Mon, 24 Aug 2009 15:15:31 -0500 Subject: [PATCH] gdiplus: use WIC to encode images --- dlls/gdiplus/image.c | 217 +++++++++++++++++++++++++++----------------------- 1 files changed, 118 insertions(+), 99 deletions(-) diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 7fb76b0..236b29f 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -31,6 +31,7 @@ #include "ole2.h" #include "initguid.h" +#include "wincodec.h" #include "gdiplus.h" #include "gdiplus_private.h" #include "wine/debug.h" @@ -1310,52 +1311,128 @@ GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filenam #define BITMAP_FORMAT_PNG 0x5089 #define BITMAP_FORMAT_APM 0xcdd7 -static GpStatus encode_image_BMP(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info, - void **output, unsigned int *output_size) +static GpStatus encode_image_WIC(GpImage *image, IStream* stream, + GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params) { - int num_palette_entries; - BITMAPFILEHEADER *bmp_file_hdr; - BITMAPINFO *bmp_info_hdr; + GpStatus stat; + GpBitmap *bitmap; + IWICBitmapEncoder *encoder; + IWICBitmapFrameEncode *frameencode; + IPropertyBag2 *encoderoptions; + HRESULT hr; + UINT width, height; + PixelFormat gdipformat; + WICPixelFormatGUID wicformat; + GpRect rc; + BitmapData lockeddata; + HRESULT initresult; + + if (image->type != ImageTypeBitmap) + return GenericError; - if (bitmap_info->bmiHeader.biClrUsed) { - num_palette_entries = bitmap_info->bmiHeader.biClrUsed; - if (num_palette_entries > 256) num_palette_entries = 256; - } else { - if (bitmap_info->bmiHeader.biBitCount <= 8) - num_palette_entries = 1 << bitmap_info->bmiHeader.biBitCount; - else - num_palette_entries = 0; + bitmap = (GpBitmap*)image; + + GdipGetImageWidth(image, &width); + GdipGetImageHeight(image, &height); + + rc.X = 0; + rc.Y = 0; + rc.Width = width; + rc.Height = height; + + initresult = CoInitialize(NULL); + + hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICBitmapEncoder, (void**)&encoder); + if (FAILED(hr)) + { + if (SUCCEEDED(initresult)) CoUninitialize(); + return hresult_to_status(hr); } - *output_size = - sizeof(BITMAPFILEHEADER) + - sizeof(BITMAPINFOHEADER) + - num_palette_entries * sizeof(RGBQUAD) + - bitmap_info->bmiHeader.biSizeImage; - - *output = GdipAlloc(*output_size); - - bmp_file_hdr = *output; - bmp_file_hdr->bfType = BITMAP_FORMAT_BMP; - bmp_file_hdr->bfSize = *output_size; - bmp_file_hdr->bfOffBits = - sizeof(BITMAPFILEHEADER) + - sizeof(BITMAPINFOHEADER) + - num_palette_entries * sizeof (RGBQUAD); - - bmp_info_hdr = (BITMAPINFO*) ((unsigned char*)(*output) + sizeof(BITMAPFILEHEADER)); - memcpy(bmp_info_hdr, bitmap_info, sizeof(BITMAPINFOHEADER) + num_palette_entries * sizeof(RGBQUAD)); - memcpy((unsigned char *)(*output) + - sizeof(BITMAPFILEHEADER) + - sizeof(BITMAPINFOHEADER) + - num_palette_entries * sizeof(RGBQUAD), - bitmap_bits, bitmap_info->bmiHeader.biSizeImage); + hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); - return Ok; + if (SUCCEEDED(hr)) + { + hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions); + } + + if (SUCCEEDED(hr)) /* created frame */ + { + hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions); + + if (SUCCEEDED(hr)) + hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height); + + if (SUCCEEDED(hr)) + /* FIXME: use the resolution from the image */ + hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0); + + if (SUCCEEDED(hr)) + { + /* FIXME: use the format from the image */ + memcpy(&wicformat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID)); + + hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat); + + if (IsEqualGUID(&wicformat, &GUID_WICPixelFormat24bppBGR)) + gdipformat = PixelFormat24bppRGB; + else + /* FIXME: allow other formats */ + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat, + &lockeddata); + + if (stat == Ok) + { + UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8; + BYTE *row; + UINT i; + + /* write one row at a time in case stride is negative */ + row = lockeddata.Scan0; + for (i=0; ipicture) - return GenericError; - - hr = IPicture_get_Type(image->picture, &type); - if (FAILED(hr) || type != PICTYPE_BITMAP) - return GenericError; - /* select correct encoder */ encode_image = NULL; for (i = 0; i < NUM_CODECS; i++) { @@ -1421,43 +1476,7 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream, if (encode_image == NULL) return UnknownImageFormat; - /* extract underlying hbitmap representation from the IPicture */ - hr = IPicture_get_Handle(image->picture, (OLE_HANDLE*)&hbmp); - if (FAILED(hr) || !hbmp) - return GenericError; - hr = IPicture_get_CurDC(image->picture, &hdc); - if (FAILED(hr)) - return GenericError; - bm_is_selected = (hdc != 0); - if (!bm_is_selected) { - hdc = CreateCompatibleDC(0); - old_hbmp = SelectObject(hdc, hbmp); - } - - /* get bits from HBITMAP */ - bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader); - bmp_info.bmiHeader.biBitCount = 0; - GetDIBits(hdc, hbmp, 0, 0, NULL, &bmp_info, DIB_RGB_COLORS); - - bmp_bits = GdipAlloc(bmp_info.bmiHeader.biSizeImage); - - if (bmp_bits) - GetDIBits(hdc, hbmp, 0, abs(bmp_info.bmiHeader.biHeight), bmp_bits, &bmp_info, DIB_RGB_COLORS); - - if (!bm_is_selected) { - SelectObject(hdc, old_hbmp); - DeleteDC(hdc); - } - - if (!bmp_bits) - return OutOfMemory; - - stat = encode_image(bmp_bits, &bmp_info, &output, &output_size); - if (stat == Ok) - IStream_Write(stream, output, output_size, &dummy); - - GdipFree(output); - GdipFree(bmp_bits); + stat = encode_image(image, stream, clsid, params); return stat; } -- 1.5.4.3