diff --git a/dlls/gdiplus/gdiplus.spec b/dlls/gdiplus/gdiplus.spec index e0ea275cbcc..7e533227a02 100644 --- a/dlls/gdiplus/gdiplus.spec +++ b/dlls/gdiplus/gdiplus.spec @@ -41,10 +41,10 @@ @ stub GdipBitmapGetHistogram @ stub GdipBitmapGetHistogramSize @ stdcall GdipBitmapGetPixel(ptr long long ptr) -@ stub GdipBitmapLockBits +@ stdcall GdipBitmapLockBits(ptr ptr long long ptr) @ stub GdipBitmapSetPixel @ stub GdipBitmapSetResolution -@ stub GdipBitmapUnlockBits +@ stdcall GdipBitmapUnlockBits(ptr ptr) @ stub GdipClearPathMarkers @ stub GdipCloneBitmapArea @ stub GdipCloneBitmapAreaI diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index cea667f33b6..79440a2e2a9 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -143,6 +143,9 @@ struct GpBitmap{ INT width; INT height; PixelFormat format; + ImageLockMode lockmode; + INT numlocks; + BYTE *bitmapbits; /* pointer to the buffer we passed in BitmapLockBits */ }; struct GpImageAttributes{ diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index c050fd25262..59690c59078 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -88,6 +88,147 @@ GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y, return NotImplemented; } +/* This function returns a pointer to an array of pixels that represents the + * bitmap. The *entire* bitmap is locked according to the lock mode specified by + * flags. It is correct behavior that a user who calls this function with write + * privileges can write to the whole bitmap (not just the area in rect). + * + * FIXME: only used portion of format is bits per pixel. */ +GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect, + UINT flags, PixelFormat format, BitmapData* lockeddata) +{ + BOOL bm_is_selected; + INT stride, bitspp = PIXELFORMATBPP(format); + OLE_HANDLE hbm; + HDC hdc; + HBITMAP old = NULL; + BITMAPINFO bmi; + BYTE *buff = NULL; + UINT abs_height; + + TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata); + + if(!lockeddata || !bitmap || !rect) + return InvalidParameter; + + if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) || + (rect->Y + rect->Height > bitmap->height) || !flags) + return InvalidParameter; + + if(flags & ImageLockModeUserInputBuf) + return NotImplemented; + + if((bitmap->lockmode & ImageLockModeWrite) || (bitmap->lockmode && + (flags & ImageLockModeWrite))) + return WrongState; + + IPicture_get_Handle(bitmap->image.picture, &hbm); + IPicture_get_CurDC(bitmap->image.picture, &hdc); + bm_is_selected = (hdc != 0); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biBitCount = 0; + + if(!bm_is_selected){ + hdc = GetDC(0); + old = SelectObject(hdc, (HBITMAP)hbm); + } + + /* fill out bmi */ + GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS); + + abs_height = abs(bmi.bmiHeader.biHeight); + stride = bmi.bmiHeader.biWidth * bitspp / 8; + stride = (stride + 3) & ~3; + + buff = GdipAlloc(stride * abs_height); + if(!buff) return OutOfMemory; + + bmi.bmiHeader.biBitCount = bitspp; + GetDIBits(hdc, (HBITMAP)hbm, 0, abs_height, buff, &bmi, DIB_RGB_COLORS); + + if(!bm_is_selected){ + SelectObject(hdc, old); + ReleaseDC(0, hdc); + } + + lockeddata->Width = rect->Width; + lockeddata->Height = rect->Height; + lockeddata->PixelFormat = format; + lockeddata->Reserved = flags; + + if(bmi.bmiHeader.biHeight > 0){ + lockeddata->Stride = -stride; + lockeddata->Scan0 = buff + (bitspp / 8) * rect->X + + stride * (abs_height - 1 - rect->Y); + } + else{ + lockeddata->Stride = stride; + lockeddata->Scan0 = buff + (bitspp / 8) * rect->X + stride * rect->Y; + } + + bitmap->lockmode = flags; + bitmap->numlocks++; + + if(flags & ImageLockModeWrite) + bitmap->bitmapbits = buff; + + return Ok; +} + +GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap, + BitmapData* lockeddata) +{ + OLE_HANDLE hbm; + HDC hdc; + HBITMAP old = NULL; + BOOL bm_is_selected; + BITMAPINFO bmi; + + if(!bitmap || !lockeddata) + return InvalidParameter; + + if(!bitmap->lockmode) + return WrongState; + + if(lockeddata->Reserved & ImageLockModeUserInputBuf) + return NotImplemented; + + if(lockeddata->Reserved & ImageLockModeRead){ + if(!(--bitmap->numlocks)) + bitmap->lockmode = 0; + + GdipFree(lockeddata->Scan0); + return Ok; + } + + IPicture_get_Handle(bitmap->image.picture, &hbm); + IPicture_get_CurDC(bitmap->image.picture, &hdc); + bm_is_selected = (hdc != 0); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biBitCount = 0; + + if(!bm_is_selected){ + hdc = GetDC(0); + old = SelectObject(hdc, (HBITMAP)hbm); + } + + GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS); + bmi.bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat); + SetDIBits(hdc, (HBITMAP)hbm, 0, abs(bmi.bmiHeader.biHeight), + bitmap->bitmapbits, &bmi, DIB_RGB_COLORS); + + if(!bm_is_selected){ + SelectObject(hdc, old); + ReleaseDC(0, hdc); + } + + GdipFree(bitmap->bitmapbits); + + return Ok; +} + GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride, PixelFormat format, BYTE* scan0, GpBitmap** bitmap) { diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h index 8c96a2c3048..3035f0d4ab5 100644 --- a/include/gdiplusflat.h +++ b/include/gdiplusflat.h @@ -164,6 +164,8 @@ GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath*,GpPath*,GpLineCap,REAL, GpStatus WINGDIPAPI GdipDeleteCustomLineCap(GpCustomLineCap*); GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap*,INT,INT,ARGB*); +GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap*,GDIPCONST GpRect*,UINT, + PixelFormat,BitmapData*); GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT,INT,INT,PixelFormat,BYTE*, GpBitmap**); GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream*,GpBitmap**); diff --git a/include/gdiplusgpstubs.h b/include/gdiplusgpstubs.h index 772edd9dfce..423cd9e4b68 100644 --- a/include/gdiplusgpstubs.h +++ b/include/gdiplusgpstubs.h @@ -67,5 +67,6 @@ typedef DashStyle GpDashStyle; typedef MatrixOrder GpMatrixOrder; typedef Point GpPoint; typedef WrapMode GpWrapMode; +typedef Rect GpRect; #endif diff --git a/include/gdiplusimaging.h b/include/gdiplusimaging.h index c76aba5d440..28fe28bca88 100644 --- a/include/gdiplusimaging.h +++ b/include/gdiplusimaging.h @@ -19,6 +19,13 @@ #ifndef _GDIPLUSIMAGING_H #define _GDIPLUSIMAGING_H +enum ImageLockMode +{ + ImageLockModeRead = 1, + ImageLockModeWrite = 2, + ImageLockModeUserInputBuf = 4 +}; + #ifdef __cplusplus class EncoderParameter { @@ -35,8 +42,22 @@ public: UINT Count; EncoderParameter Parameter[1]; }; + +class BitmapData +{ +public: + UINT Width; + UINT Height; + INT Stride; + PixelFormat PixelFormat; + VOID* Scan0; + UINT_PTR Reserved; +}; + #else /* end of c++ typedefs */ +typedef enum ImageLockMode ImageLockMode; + typedef struct EncoderParameter { GUID Guid; @@ -51,6 +72,16 @@ typedef struct EncoderParameters EncoderParameter Parameter[1]; } EncoderParameters; +typedef struct BitmapData +{ + UINT Width; + UINT Height; + INT Stride; + PixelFormat PixelFormat; + VOID* Scan0; + UINT_PTR Reserved; /* undocumented: stores the lock mode */ +}BitmapData; + #endif /* end of c typedefs */ #endif /* _GDIPLUSIMAGING_H */ diff --git a/include/gdiplustypes.h b/include/gdiplustypes.h index c316073c5d5..96112ea96f1 100644 --- a/include/gdiplustypes.h +++ b/include/gdiplustypes.h @@ -177,6 +177,15 @@ public: REAL Height; }; +class Rect +{ +public: + INT X; + INT Y; + INT Width; + INT Height; +}; + #else /* end of c++ typedefs */ typedef struct Point @@ -206,6 +215,14 @@ typedef struct RectF REAL Height; } RectF; +typedef struct Rect +{ + INT X; + INT Y; + INT Width; + INT Height; +} Rect; + typedef enum Status Status; #endif /* end of c typedefs */