Vincent Povirk : gdiplus: Use WIC to encode images.
Alexandre Julliard
julliard at winehq.org
Wed Sep 2 09:30:32 CDT 2009
Module: wine
Branch: master
Commit: e4a3ad81bef7a03eaade11e9a02acd03b44f0701
URL: http://source.winehq.org/git/wine.git/?a=commit;h=e4a3ad81bef7a03eaade11e9a02acd03b44f0701
Author: Vincent Povirk <vincent at codeweavers.com>
Date: Mon Aug 24 15:15:31 2009 -0500
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; i<lockeddata.Height; i++)
+ {
+ hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
+ if (FAILED(hr)) break;
+ row += lockeddata.Stride;
+ }
+
+ GdipBitmapUnlockBits(bitmap, &lockeddata);
+ }
+ else
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapFrameEncode_Commit(frameencode);
+
+ IWICBitmapFrameEncode_Release(frameencode);
+ IPropertyBag2_Release(encoderoptions);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapEncoder_Commit(encoder);
+
+ IWICBitmapEncoder_Release(encoder);
+
+ if (SUCCEEDED(initresult)) CoUninitialize();
+
+ return hresult_to_status(hr);
+}
+
+static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
+ GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+{
+ return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
}
/*****************************************************************************
@@ -1822,30 +1912,14 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
{
GpStatus stat;
- HBITMAP hbmp;
- HBITMAP old_hbmp;
- HDC hdc;
- int bm_is_selected;
- BITMAPINFO bmp_info;
- LPVOID bmp_bits;
encode_image_func encode_image;
- LPVOID output;
- unsigned int output_size;
- unsigned int dummy;
int i;
- old_hbmp = 0;
- output = NULL;
- output_size = 0;
-
TRACE("%p %p %p %p\n", image, stream, clsid, params);
if(!image || !stream)
return InvalidParameter;
- if (image->type != 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;
}
More information about the wine-cvs
mailing list