- Update to trunk
[reactos.git] / dll / win32 / gdiplus / image.c
index d72ae8d..69f5865 100644 (file)
@@ -1626,11 +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;
-    int i;
+    BYTE *bits=NULL, *own_bits=NULL;
     REAL xres, yres;
     GpStatus stat;
 
@@ -1655,46 +1654,62 @@ 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 && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
+    {
+        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;
 
-    DeleteDC(hdc);
-    GdipFree(pbmi);
+        stride = dib_stride;
+    }
+    else
+    {
+        /* Not a GDI format; don't try to make an HBITMAP. */
+        if (scan0)
+            bits = scan0;
+        else
+        {
+            INT size = abs(stride) * height;
 
-    if (!hbitmap) return GenericError;
+            own_bits = bits = GdipAlloc(size);
+            if (!own_bits) return OutOfMemory;
 
-    /* copy bits to the dib if necessary */
-    /* FIXME: should reference the bits instead of copying them */
-    if (scan0)
-        for (i=0; i<height; i++)
-            memcpy(bits+i*dib_stride, scan0+i*stride, row_size);
+            if (stride < 0)
+                bits += stride * (1 - height);
+        }
+    }
 
     *bitmap = GdipAlloc(sizeof(GpBitmap));
     if(!*bitmap)
     {
         DeleteObject(hbitmap);
+        GdipFree(own_bits);
         return OutOfMemory;
     }
 
@@ -1714,7 +1729,12 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->hbitmap = hbitmap;
     (*bitmap)->hdc = NULL;
     (*bitmap)->bits = bits;
-    (*bitmap)->stride = dib_stride;
+    (*bitmap)->stride = stride;
+    (*bitmap)->own_bits = own_bits;
+
+    /* set format-related flags */
+    if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed))
+        (*bitmap)->image.flags |= ImageFlagsHasAlpha;
 
     if (format == PixelFormat1bppIndexed ||
         format == PixelFormat4bppIndexed ||
@@ -1916,6 +1936,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);
 }
@@ -1927,15 +1948,22 @@ GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
     if(!image)
         return InvalidParameter;
 
-    if (image->picture)
-        IPicture_Release(image->picture);
     if (image->type == ImageTypeBitmap)
     {
         GdipFree(((GpBitmap*)image)->bitmapbits);
+        GdipFree(((GpBitmap*)image)->own_bits);
         DeleteDC(((GpBitmap*)image)->hdc);
         DeleteObject(((GpBitmap*)image)->hbitmap);
     }
+    else if (image->type != ImageTypeMetafile)
+    {
+        WARN("invalid image: %p\n", image);
+        return ObjectBusy;
+    }
+    if (image->picture)
+        IPicture_Release(image->picture);
     GdipFree(image->palette_entries);
+    image->type = ~0;
     GdipFree(image);
 
     return Ok;
@@ -2008,14 +2036,15 @@ GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
 
     if(image->type == ImageTypeMetafile){
         HDC hdc = GetDC(0);
+        REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
 
-        *height = convert_unit(hdc, ((GpMetafile*)image)->unit) *
+        ReleaseDC(0, hdc);
+
+        *height = convert_unit(res, ((GpMetafile*)image)->unit) *
                         ((GpMetafile*)image)->bounds.Height;
 
-        *width = convert_unit(hdc, ((GpMetafile*)image)->unit) *
+        *width = convert_unit(res, ((GpMetafile*)image)->unit) *
                         ((GpMetafile*)image)->bounds.Width;
-
-        ReleaseDC(0, hdc);
     }
 
     else if(image->type == ImageTypeBitmap){
@@ -2047,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;
 }
@@ -2072,11 +2106,12 @@ GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
 
     if(image->type == ImageTypeMetafile){
         HDC hdc = GetDC(0);
-
-        *height = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
-                        ((GpMetafile*)image)->bounds.Height);
+        REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
 
         ReleaseDC(0, hdc);
+
+        *height = roundr(convert_unit(res, ((GpMetafile*)image)->unit) *
+                        ((GpMetafile*)image)->bounds.Height);
     }
     else if(image->type == ImageTypeBitmap)
         *height = ((GpBitmap*)image)->height;
@@ -2178,11 +2213,12 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
 
     if(image->type == ImageTypeMetafile){
         HDC hdc = GetDC(0);
-
-        *width = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
-                        ((GpMetafile*)image)->bounds.Width);
+        REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
 
         ReleaseDC(0, hdc);
+
+        *width = roundr(convert_unit(res, ((GpMetafile*)image)->unit) *
+                        ((GpMetafile*)image)->bounds.Width);
     }
     else if(image->type == ImageTypeBitmap)
         *width = ((GpBitmap*)image)->width;
@@ -2566,6 +2602,18 @@ static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **imag
                     *image = NULL;
                     GdipDisposeImage((GpImage*)bitmap);
                 }
+
+                if (SUCCEEDED(hr) && status == Ok)
+                {
+                    double dpix, dpiy;
+                    hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy);
+                    if (SUCCEEDED(hr))
+                    {
+                        bitmap->image.xres = dpix;
+                        bitmap->image.yres = dpiy;
+                    }
+                    hr = S_OK;
+                }
             }
 
             IWICBitmapSource_Release(source);
@@ -2581,6 +2629,12 @@ end:
 
     if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
 
+    if (status == Ok)
+    {
+        /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
+        bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB;
+    }
+
     return status;
 }
 
@@ -3756,3 +3810,16 @@ GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
 
     return stat;
 }
+
+/*****************************************************************************
+ * GdipConvertToEmfPlusToFile [GDIPLUS.@]
+ */
+
+GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
+                                               GpMetafile* metafile, BOOL* conversionSuccess,
+                                               const WCHAR* filename, EmfType emfType,
+                                               const WCHAR* description, GpMetafile** out_metafile)
+{
+    FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
+    return NotImplemented;
+}