From 50e9172b9be7aa90be3197d84b629d9139c53e21 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 | 219 +++++++++++++++++++++++++++++-------------------- 1 files changed, 130 insertions(+), 89 deletions(-) diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 6c48663..61e7b03 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -1623,8 +1623,8 @@ static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid return Ok; } -typedef GpStatus (*encode_image_func)(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info, - void **output, unsigned int *output_size); +typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream, + GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params); typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, GpImage** image); @@ -1771,48 +1771,138 @@ 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=0; + WICPixelFormatGUID wicformat; + GpRect rc; + BitmapData lockeddata; + HRESULT initresult; + UINT i; - 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; + if (image->type != ImageTypeBitmap) + return GenericError; + + 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; + hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); - *output = GdipAlloc(*output_size); + if (SUCCEEDED(hr)) + { + hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions); + } - 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); + if (SUCCEEDED(hr)) /* created frame */ + { + hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions); - 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); + if (SUCCEEDED(hr)) + hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height); - return Ok; + if (SUCCEEDED(hr)) + /* FIXME: use the resolution from the image */ + hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0); + + if (SUCCEEDED(hr)) + { + for (i=0; wic_pixel_formats[i]; i++) + { + if (wic_gdip_formats[i] == bitmap->format) + break; + } + if (wic_pixel_formats[i]) + memcpy(&wicformat, wic_pixel_formats[i], sizeof(GUID)); + else + memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID)); + + hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat); + + for (i=0; wic_pixel_formats[i]; i++) + { + if (IsEqualGUID(&wicformat, wic_pixel_formats[i])) + break; + } + if (wic_pixel_formats[i]) + gdipformat = wic_gdip_formats[i]; + else + { + ERR("cannot provide pixel format %s\n", debugstr_guid(&wicformat)); + 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; + + /* write one row at a time in case stride is negative */ + row = lockeddata.Scan0; + for (i=0; itype != ImageTypeBitmap) - return GenericError; - /* select correct encoder */ encode_image = NULL; for (i = 0; i < NUM_CODECS; i++) { @@ -1856,40 +1930,7 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream, if (encode_image == NULL) return UnknownImageFormat; - hbmp = ((GpBitmap*)image)->hbitmap; - if (!hbmp) - return GenericError; - hdc = ((GpBitmap*)image)->hdc; - 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