From b97083fb43a4d6fb1ab68b7660b919b46ba64182 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Thu, 4 Feb 2010 19:05:54 -0600 Subject: [PATCH 1/4] gdiplus: Don't use gdi32 to do pixel format conversion. --- dlls/gdiplus/gdiplus_private.h | 4 + dlls/gdiplus/image.c | 521 ++++++++++++++++++++++++++++++++++------ 2 files changed, 455 insertions(+), 70 deletions(-) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index d82eec1..75dc8c6 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -85,6 +85,10 @@ extern const char *debugstr_pointf(CONST PointF* pt); extern void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height, BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride); +extern GpStatus convert_pixels(UINT width, UINT height, + INT dst_stride, BYTE *dst_bits, PixelFormat dst_format, + INT src_stride, const BYTE *src_bits, PixelFormat src_format, ARGB *src_palette); + struct GpPen{ UINT style; GpUnit unit; diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 4fd593f..1d48a0b 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -442,6 +442,412 @@ GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y, return Ok; } +GpStatus convert_pixels(UINT width, UINT height, + INT dst_stride, BYTE *dst_bits, PixelFormat dst_format, + INT src_stride, const BYTE *src_bits, PixelFormat src_format, ARGB *src_palette) +{ + UINT x, y; + + if (src_format == dst_format || + (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32)) + { + UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8; + for (y=0; ylockmode) + { + WARN("bitmap is already locked and cannot be locked again\n"); return WrongState; + } if (bitmap->bits && bitmap->format == format) { @@ -501,66 +911,55 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect, return Ok; } - hbm = bitmap->hbitmap; - hdc = bitmap->hdc; - bm_is_selected = (hdc != 0); - - pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - if (!pbmi) - return OutOfMemory; - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biBitCount = 0; - - if(!bm_is_selected){ - hdc = CreateCompatibleDC(0); - old = SelectObject(hdc, hbm); + /* Make sure we can convert to the requested format. */ + stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL); + if (stat == NotImplemented) + { + FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format); + return NotImplemented; } - /* fill out bmi */ - GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS); + /* If we're opening for writing, make sure we'll be able to write back in + * the original format. */ + if (flags & ImageLockModeWrite) + { + stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL); + if (stat == NotImplemented) + { + FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format); + return NotImplemented; + } + } - abs_height = abs(pbmi->bmiHeader.biHeight); - stride = pbmi->bmiHeader.biWidth * bitspp / 8; + abs_height = bitmap->height; + stride = (bitmap->width * bitspp + 7) / 8; stride = (stride + 3) & ~3; buff = GdipAlloc(stride * abs_height); - pbmi->bmiHeader.biBitCount = bitspp; - - if(buff) - GetDIBits(hdc, hbm, 0, abs_height, buff, pbmi, DIB_RGB_COLORS); + if (!buff) return OutOfMemory; - if(!bm_is_selected){ - SelectObject(hdc, old); - DeleteDC(hdc); - } + stat = convert_pixels(bitmap->width, bitmap->height, + stride, buff, format, + bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries); - if(!buff){ - GdipFree(pbmi); - return OutOfMemory; + if (stat != Ok) + { + GdipFree(buff); + return stat; } lockeddata->Width = act_rect.Width; lockeddata->Height = act_rect.Height; lockeddata->PixelFormat = format; lockeddata->Reserved = flags; - - if(pbmi->bmiHeader.biHeight > 0){ - lockeddata->Stride = -stride; - lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X + - stride * (abs_height - 1 - act_rect.Y); - } - else{ - lockeddata->Stride = stride; - lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y; - } + lockeddata->Stride = stride; + lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y; bitmap->lockmode = flags; bitmap->numlocks++; - bitmap->bitmapbits = buff; - GdipFree(pbmi); return Ok; } @@ -580,10 +979,7 @@ GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL yd GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap, BitmapData* lockeddata) { - HDC hdc; - HBITMAP hbm, old = NULL; - BOOL bm_is_selected; - BITMAPINFO *pbmi; + GpStatus stat; TRACE("(%p,%p)\n", bitmap, lockeddata); @@ -613,36 +1009,21 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap, return Ok; } - hbm = bitmap->hbitmap; - hdc = bitmap->hdc; - bm_is_selected = (hdc != 0); + stat = convert_pixels(bitmap->width, bitmap->height, + bitmap->stride, bitmap->bits, bitmap->format, + lockeddata->Stride, bitmap->bitmapbits, lockeddata->PixelFormat, NULL); - pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biBitCount = 0; - - if(!bm_is_selected){ - hdc = CreateCompatibleDC(0); - old = SelectObject(hdc, hbm); - } - - GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS); - pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat); - SetDIBits(hdc, hbm, 0, abs(pbmi->bmiHeader.biHeight), - bitmap->bitmapbits, pbmi, DIB_RGB_COLORS); - - if(!bm_is_selected){ - SelectObject(hdc, old); - DeleteDC(hdc); + if (stat != Ok) + { + ERR("failed to convert pixels; this should never happen\n"); } - GdipFree(pbmi); GdipFree(bitmap->bitmapbits); bitmap->bitmapbits = NULL; bitmap->lockmode = 0; bitmap->numlocks = 0; - return Ok; + return stat; } GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height, -- 1.6.3.3