diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 908a1b721c7..f3393d4325b 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -49,6 +49,8 @@ extern REAL gdiplus_atan2(REAL dy, REAL dx); extern GpStatus hresult_to_status(HRESULT res); extern REAL convert_unit(REAL logpixels, GpUnit unit); +extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics); + extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1, REAL *y1, REAL *x2, REAL *y2); extern void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj, @@ -269,6 +271,7 @@ struct GpBitmap{ HDC hdc; BYTE *bits; /* actual image bits if this is a DIB */ INT stride; /* stride of bits if this is a DIB */ + BYTE *own_bits; /* image bits that need to be freed with this object */ }; struct GpCachedBitmap{ diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 79290b59676..e748477ee33 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -1254,6 +1254,45 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra return Ok; } +GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) +{ + GpStatus retval; + + *graphics = GdipAlloc(sizeof(GpGraphics)); + if(!*graphics) return OutOfMemory; + + if((retval = GdipCreateMatrix(&(*graphics)->worldtrans)) != Ok){ + GdipFree(*graphics); + return retval; + } + + if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){ + GdipFree((*graphics)->worldtrans); + GdipFree(*graphics); + return retval; + } + + (*graphics)->hdc = NULL; + (*graphics)->hwnd = NULL; + (*graphics)->owndc = FALSE; + (*graphics)->image = image; + (*graphics)->smoothing = SmoothingModeDefault; + (*graphics)->compqual = CompositingQualityDefault; + (*graphics)->interpolation = InterpolationModeDefault; + (*graphics)->pixeloffset = PixelOffsetModeDefault; + (*graphics)->compmode = CompositingModeSourceOver; + (*graphics)->unit = UnitDisplay; + (*graphics)->scale = 1.0; + (*graphics)->busy = FALSE; + (*graphics)->textcontrast = 4; + list_init(&(*graphics)->containers); + (*graphics)->contid = 0; + + TRACE("<-- %p\n", *graphics); + + return Ok; +} + GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics) { GpStatus ret; diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 57c9f83161b..536eebbc415 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -1626,10 +1626,10 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride, PixelFormat format, BYTE* scan0, GpBitmap** bitmap) { BITMAPINFO* pbmi; - HBITMAP hbitmap; + HBITMAP hbitmap=NULL; INT row_size, dib_stride; HDC hdc; - BYTE *bits; + BYTE *bits=NULL, *own_bits=NULL; int i; REAL xres, yres; GpStatus stat; @@ -1655,39 +1655,63 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride, if(stride == 0) stride = dib_stride; - pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - if (!pbmi) - return OutOfMemory; + if (format & PixelFormatGDI) + { + pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + if (!pbmi) + return OutOfMemory; - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biWidth = width; - pbmi->bmiHeader.biHeight = -height; - pbmi->bmiHeader.biPlanes = 1; - /* FIXME: use the rest of the data from format */ - pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format); - pbmi->bmiHeader.biCompression = BI_RGB; - pbmi->bmiHeader.biSizeImage = 0; - pbmi->bmiHeader.biXPelsPerMeter = 0; - pbmi->bmiHeader.biYPelsPerMeter = 0; - pbmi->bmiHeader.biClrUsed = 0; - pbmi->bmiHeader.biClrImportant = 0; + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = width; + pbmi->bmiHeader.biHeight = -height; + pbmi->bmiHeader.biPlanes = 1; + /* FIXME: use the rest of the data from format */ + pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format); + pbmi->bmiHeader.biCompression = BI_RGB; + pbmi->bmiHeader.biSizeImage = 0; + pbmi->bmiHeader.biXPelsPerMeter = 0; + pbmi->bmiHeader.biYPelsPerMeter = 0; + pbmi->bmiHeader.biClrUsed = 0; + pbmi->bmiHeader.biClrImportant = 0; - hdc = CreateCompatibleDC(NULL); - if (!hdc) { + hdc = CreateCompatibleDC(NULL); + if (!hdc) { + GdipFree(pbmi); + return GenericError; + } + + hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + + DeleteDC(hdc); GdipFree(pbmi); - return GenericError; + + if (!hbitmap) return GenericError; } + else + { + /* Not a GDI format; don't try to make an HBITMAP. */ + if (scan0) + { + /* FIXME: We should do this with GDI formats too when scan0 is + * provided, but for now we need the HDC for most drawing + * operations. */ + bits = scan0; + } + else + { + INT size = abs(stride) * height; - hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + own_bits = bits = GdipAlloc(size); + if (!own_bits) return OutOfMemory; - DeleteDC(hdc); - GdipFree(pbmi); - - if (!hbitmap) return GenericError; + if (stride < 0) + bits += stride * (1 - height); + } + } /* copy bits to the dib if necessary */ /* FIXME: should reference the bits instead of copying them */ - if (scan0) + if (scan0 && bits != scan0) for (i=0; ihdc = NULL; (*bitmap)->bits = bits; (*bitmap)->stride = dib_stride; + (*bitmap)->own_bits = own_bits; if (format == PixelFormat1bppIndexed || format == PixelFormat4bppIndexed || @@ -1916,6 +1942,7 @@ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette) dst->hdc = src->hdc; dst->bits = src->bits; dst->stride = src->stride; + dst->own_bits = src->own_bits; GdipFree(src); } @@ -1932,6 +1959,7 @@ GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image) if (image->type == ImageTypeBitmap) { GdipFree(((GpBitmap*)image)->bitmapbits); + GdipFree(((GpBitmap*)image)->own_bits); DeleteDC(((GpBitmap*)image)->hdc); DeleteObject(((GpBitmap*)image)->hbitmap); } @@ -2048,18 +2076,23 @@ GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image, return NotImplemented; } - hdc = ((GpBitmap*)image)->hdc; + if (((GpBitmap*)image)->hbitmap) + { + hdc = ((GpBitmap*)image)->hdc; - if(!hdc){ - hdc = CreateCompatibleDC(0); - SelectObject(hdc, ((GpBitmap*)image)->hbitmap); - ((GpBitmap*)image)->hdc = hdc; + if(!hdc){ + hdc = CreateCompatibleDC(0); + SelectObject(hdc, ((GpBitmap*)image)->hbitmap); + ((GpBitmap*)image)->hdc = hdc; + } + + stat = GdipCreateFromHDC(hdc, graphics); + + if (stat == Ok) + (*graphics)->image = image; } - - stat = GdipCreateFromHDC(hdc, graphics); - - if (stat == Ok) - (*graphics)->image = image; + else + stat = graphics_from_image(image, graphics); return stat; } diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index 441367e0732..609f426ae8c 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -2616,7 +2616,7 @@ static void test_GdipGetNearestColor(void) GdipDisposeImage((GpImage*)bitmap); status = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat48bppRGB, NULL, &bitmap); - todo_wine expect(Ok, status); + expect(Ok, status); if (status == Ok) { status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); @@ -2629,7 +2629,7 @@ static void test_GdipGetNearestColor(void) } status = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat64bppARGB, NULL, &bitmap); - todo_wine expect(Ok, status); + expect(Ok, status); if (status == Ok) { status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); @@ -2642,7 +2642,7 @@ static void test_GdipGetNearestColor(void) } status = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat64bppPARGB, NULL, &bitmap); - todo_wine expect(Ok, status); + expect(Ok, status); if (status == Ok) { status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);