User32 bitmap.c:
authorJames Tabor <james.tabor@reactos.org>
Mon, 4 Sep 2006 03:08:18 +0000 (03:08 +0000)
committerJames Tabor <james.tabor@reactos.org>
Mon, 4 Sep 2006 03:08:18 +0000 (03:08 +0000)
 - Patch by Michael Kaufmann
  - CopyImage: Handle the flags LR_COPYDELETEORG, LR_CREATEDIBSECTION, and LR_MONOCHROME.

svn path=/trunk/; revision=23906

reactos/dll/win32/user32/windows/bitmap.c

index e748a2f..bdee738 100644 (file)
@@ -562,36 +562,200 @@ CopyImage(
    IN INT desiredy,
    IN UINT flags)
 {
-   HBITMAP res;
-   BITMAP bm;
-
+/*
+ * BUGS
+ *    Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
+ *    all other versions (95/2000/XP have been tested) ignore it.
+ *
+ * NOTES
+ *    If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
+ *    a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
+ *    the copy will have the same depth as the screen.
+ *    The content of the image will only be copied if the bit depth of the
+ *    original image is compatible with the bit depth of the screen, or
+ *    if the source is a DIB section.
+ *    The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
+ */
    switch (type)
    {
       case IMAGE_BITMAP:
          {
-            DPRINT("WARNING:  Incomplete implementation of CopyImage!\n");
-            /*
-             * FIXME: Support flags LR_COPYDELETEORG, LR_COPYFROMRESOURCE,
-             * LR_COPYRETURNORG, LR_CREATEDIBSECTION and LR_MONOCHROME.
-             */
-            if (!GetObjectW(hnd, sizeof(bm), &bm))
-                return NULL;
-            bm.bmBits = NULL;
-            if ((res = CreateBitmapIndirect(&bm)))
+            HBITMAP res = NULL;
+            DIBSECTION ds;
+            int objSize;
+            BITMAPINFO * bi;
+
+            objSize = GetObjectW( hnd, sizeof(ds), &ds );
+            if (!objSize) return 0;
+            if ((desiredx < 0) || (desiredy < 0)) return 0;
+
+            if (flags & LR_COPYFROMRESOURCE)
             {
-               char *buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight);
-               if (buf == NULL)
-               {
-                  DeleteObject(res);
-                  return NULL;
-               }
-               GetBitmapBits(hnd, bm.bmWidthBytes * bm.bmHeight, buf);
-               SetBitmapBits(res, bm.bmWidthBytes * bm.bmHeight, buf);
-               HeapFree(GetProcessHeap(), 0, buf);
+                DPRINT1("FIXME: The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
             }
-            return res;
-         }
 
+            if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
+            if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
+
+            /* Allocate memory for a BITMAPINFOHEADER structure and a
+               color table. The maximum number of colors in a color table
+               is 256 which corresponds to a bitmap with depth 8.
+               Bitmaps with higher depths don't have color tables. */
+            bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+            if (!bi) return 0;
+
+            bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
+            bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
+            bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
+            bi->bmiHeader.biCompression = BI_RGB;
+
+            if (flags & LR_CREATEDIBSECTION)
+            {
+                /* Create a DIB section. LR_MONOCHROME is ignored */
+                void * bits;
+                HDC dc = CreateCompatibleDC(NULL);
+
+                if (objSize == sizeof(DIBSECTION))
+                {
+                    /* The source bitmap is a DIB.
+                       Get its attributes to create an exact copy */
+                    memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
+                }
+
+                /* Get the color table or the color masks */
+                GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+
+                bi->bmiHeader.biWidth  = desiredx;
+                bi->bmiHeader.biHeight = desiredy;
+                bi->bmiHeader.biSizeImage = 0;
+
+                res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
+                DeleteDC(dc);
+            }
+            else
+            {
+                /* Create a device-dependent bitmap */
+
+                BOOL monochrome = (flags & LR_MONOCHROME);
+
+                if (objSize == sizeof(DIBSECTION))
+                {
+                    /* The source bitmap is a DIB section.
+                       Get its attributes */
+                    HDC dc = CreateCompatibleDC(NULL);
+                    bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
+                    bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
+                    GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+                    DeleteDC(dc);
+
+                    if (!monochrome && ds.dsBm.bmBitsPixel == 1)
+                    {
+                        /* Look if the colors of the DIB are black and white */
+
+                        monochrome = 
+                              (bi->bmiColors[0].rgbRed == 0xff
+                            && bi->bmiColors[0].rgbGreen == 0xff
+                            && bi->bmiColors[0].rgbBlue == 0xff
+                            && bi->bmiColors[0].rgbReserved == 0
+                            && bi->bmiColors[1].rgbRed == 0
+                            && bi->bmiColors[1].rgbGreen == 0
+                            && bi->bmiColors[1].rgbBlue == 0
+                            && bi->bmiColors[1].rgbReserved == 0)
+                            ||
+                              (bi->bmiColors[0].rgbRed == 0
+                            && bi->bmiColors[0].rgbGreen == 0
+                            && bi->bmiColors[0].rgbBlue == 0
+                            && bi->bmiColors[0].rgbReserved == 0
+                            && bi->bmiColors[1].rgbRed == 0xff
+                            && bi->bmiColors[1].rgbGreen == 0xff
+                            && bi->bmiColors[1].rgbBlue == 0xff
+                            && bi->bmiColors[1].rgbReserved == 0);
+                    }
+                }
+                else if (!monochrome)
+                {
+                    monochrome = ds.dsBm.bmBitsPixel == 1;
+                }
+
+                if (monochrome)
+                {
+                    res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
+                }
+                else
+                {
+                    HDC screenDC = GetDC(NULL);
+                    res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
+                    ReleaseDC(NULL, screenDC);
+                }
+            }
+
+            if (res)
+            {
+                /* Only copy the bitmap if it's a DIB section or if it's
+                   compatible to the screen */
+                BOOL copyContents;
+
+                if (objSize == sizeof(DIBSECTION))
+                {
+                    copyContents = TRUE;
+                }
+                else
+                {
+                    HDC screenDC = GetDC(NULL);
+                    int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
+                    ReleaseDC(NULL, screenDC);
+
+                    copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
+                }
+
+                if (copyContents)
+                {
+                    /* The source bitmap may already be selected in a device context,
+                       use GetDIBits/StretchDIBits and not StretchBlt  */
+
+                    HDC dc;
+                    void * bits;
+
+                    dc = CreateCompatibleDC(NULL);
+
+                    bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
+                    bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
+                    bi->bmiHeader.biSizeImage = 0;
+                    bi->bmiHeader.biClrUsed = 0;
+                    bi->bmiHeader.biClrImportant = 0;
+
+                    /* Fill in biSizeImage */
+                    GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+                    bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
+
+                    if (bits)
+                    {
+                        HBITMAP oldBmp;
+
+                        /* Get the image bits of the source bitmap */
+                        GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
+
+                        /* Copy it to the destination bitmap */
+                        oldBmp = SelectObject(dc, res);
+                        StretchDIBits(dc, 0, 0, desiredx, desiredy,
+                                      0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
+                                      bits, bi, DIB_RGB_COLORS, SRCCOPY);
+                        SelectObject(dc, oldBmp);
+
+                        HeapFree(GetProcessHeap(), 0, bits);
+                    }
+
+                    DeleteDC(dc);
+                }
+
+                if (flags & LR_COPYDELETEORG)
+                {
+                    DeleteObject(hnd);
+                }
+            }
+            HeapFree(GetProcessHeap(), 0, bi);
+            return (HICON)res;
+         }
       case IMAGE_ICON:
          {
             static BOOL IconMsgDisplayed = FALSE;
@@ -602,6 +766,7 @@ CopyImage(
                IconMsgDisplayed = TRUE;
             }
             return CopyIcon(hnd);
+//            return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
          }
 
       case IMAGE_CURSOR:
@@ -613,9 +778,13 @@ CopyImage(
                DPRINT("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
                IconMsgDisplayed = TRUE;
             }
+            /* Should call CURSORICON_ExtCopy but more testing
+             * needs to be done before we change this
+             */
+            if (flags) DPRINT1("FIXME: Flags are ignored\n");
             return CopyCursor(hnd);
          }
    }
-
    return NULL;
 }
+