gdiplus: Create HBITMAP-less bitmap objects for exotic pixel formats.
authorVincent Povirk <vincent@codeweavers.com>
Sun, 8 Aug 2010 21:18:40 +0000 (16:18 -0500)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 17 Aug 2010 09:55:33 +0000 (11:55 +0200)
dlls/gdiplus/gdiplus_private.h
dlls/gdiplus/graphics.c
dlls/gdiplus/image.c
dlls/gdiplus/tests/graphics.c

index 908a1b721c7faf6c3e8c946937d3002c648f9847..f3393d4325b4ecb8c1819c51d1f181399f2da16a 100644 (file)
@@ -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{
index 79290b5967638ccb8d504705efef9cfda84cd5bb..e748477ee33767d05c932f806787735bf4bc2d20 100644 (file)
@@ -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;
index 57c9f83161bd08fb4a6a3314d2a3e7bc7fdd1782..536eebbc4158401c0c73ed52c48efb430aaa0850 100644 (file)
@@ -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) {
+            GdipFree(pbmi);
+            return GenericError;
+        }
 
-    hdc = CreateCompatibleDC(NULL);
-    if (!hdc) {
+        hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+
+        DeleteDC(hdc);
         GdipFree(pbmi);
-        return GenericError;
-    }
 
-    hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+        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;
 
-    DeleteDC(hdc);
-    GdipFree(pbmi);
+            own_bits = bits = GdipAlloc(size);
+            if (!own_bits) return OutOfMemory;
 
-    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; i<height; i++)
             memcpy(bits+i*dib_stride, scan0+i*stride, row_size);
 
@@ -1695,6 +1719,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     if(!*bitmap)
     {
         DeleteObject(hbitmap);
+        GdipFree(own_bits);
         return OutOfMemory;
     }
 
@@ -1715,6 +1740,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->hdc = 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);
+        stat = GdipCreateFromHDC(hdc, graphics);
 
-    if (stat == Ok)
-        (*graphics)->image = image;
+        if (stat == Ok)
+            (*graphics)->image = image;
+    }
+    else
+        stat = graphics_from_image(image, graphics);
 
     return stat;
 }
index 441367e07320f328c2cd7d8a766b7f8f31482041..609f426ae8c1d887615049acdb9c741259042ac0 100644 (file)
@@ -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);