https://git.reactos.org/?p=reactos.git;a=commitdiff;h=455c1fe1b989a3c1a6731e2aa8beb2bdf05fdf2f

commit 455c1fe1b989a3c1a6731e2aa8beb2bdf05fdf2f
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Sun Aug 20 16:46:18 2023 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Sun Aug 20 16:46:18 2023 +0900

    [MSPAINT] Speed up for black and white (#5563)
    
    Follow-up to #5554.
    - Speed up ImageModel::PushBlackAndWhite
      by using GetDIBits and SetDIBits.
    CORE-19094
---
 base/applications/mspaint/dib.cpp     | 93 +++++++++++++++++++++++++++++++++++
 base/applications/mspaint/dib.h       |  2 +
 base/applications/mspaint/history.cpp | 44 ++++-------------
 3 files changed, 104 insertions(+), 35 deletions(-)

diff --git a/base/applications/mspaint/dib.cpp 
b/base/applications/mspaint/dib.cpp
index c12a2f013a8..e770f5494d0 100644
--- a/base/applications/mspaint/dib.cpp
+++ b/base/applications/mspaint/dib.cpp
@@ -13,6 +13,13 @@ float g_xDpi = 96;
 float g_yDpi = 96;
 SYSTEMTIME g_fileTime;
 
+#define WIDTHBYTES(i) (((i) + 31) / 32 * 4)
+
+struct BITMAPINFOEX : BITMAPINFO
+{
+    RGBQUAD bmiColorsExtra[256 - 1];
+};
+
 /* FUNCTIONS ********************************************************/
 
 // Convert DPI (dots per inch) into PPCM (pixels per centimeter)
@@ -519,3 +526,89 @@ HBITMAP BitmapFromHEMF(HENHMETAFILE hEMF)
 
     return hbm;
 }
+
+BOOL IsBitmapBlackAndWhite(HBITMAP hbm)
+{
+    BITMAP bm;
+    if (!::GetObjectW(hbm, sizeof(bm), &bm))
+        return FALSE;
+
+    if (bm.bmBitsPixel == 1)
+        return TRUE;
+
+    BITMAPINFOEX bmi;
+    ZeroMemory(&bmi, sizeof(bmi));
+    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+    bmi.bmiHeader.biWidth = bm.bmWidth;
+    bmi.bmiHeader.biHeight = bm.bmHeight;
+    bmi.bmiHeader.biPlanes = 1;
+    bmi.bmiHeader.biBitCount = 24;
+
+    DWORD widthbytes = WIDTHBYTES(24 * bm.bmWidth);
+    DWORD cbBits = widthbytes * bm.bmHeight;
+    LPBYTE pbBits = new BYTE[cbBits];
+
+    HDC hdc = ::CreateCompatibleDC(NULL);
+    ::GetDIBits(hdc, hbm, 0, bm.bmHeight, pbBits, &bmi, DIB_RGB_COLORS);
+    ::DeleteDC(hdc);
+
+    BOOL bBlackAndWhite = TRUE;
+    for (LONG y = 0; y < bm.bmHeight; ++y)
+    {
+        LPBYTE pbLine = &pbBits[widthbytes * y];
+        for (LONG x = 0; x < bm.bmWidth; ++x)
+        {
+            BYTE Blue = *pbLine++;
+            BYTE Green = *pbLine++;
+            BYTE Red = *pbLine++;
+            COLORREF rgbColor = RGB(Red, Green, Blue);
+            if (rgbColor != RGB(0, 0, 0) && rgbColor != RGB(255, 255, 255))
+            {
+                bBlackAndWhite = FALSE;
+                goto Finish;
+            }
+        }
+    }
+
+Finish:
+    delete[] pbBits;
+
+    return bBlackAndWhite;
+}
+
+HBITMAP ConvertToBlackAndWhite(HBITMAP hbm)
+{
+    BITMAP bm;
+    if (!::GetObject(hbm, sizeof(bm), &bm))
+        return NULL;
+
+    BITMAPINFOEX bmi;
+    ZeroMemory(&bmi, sizeof(bmi));
+    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    bmi.bmiHeader.biWidth = bm.bmWidth;
+    bmi.bmiHeader.biHeight = bm.bmHeight;
+    bmi.bmiHeader.biPlanes = 1;
+    bmi.bmiHeader.biBitCount = 1;
+    bmi.bmiColors[1].rgbBlue = 255;
+    bmi.bmiColors[1].rgbGreen = 255;
+    bmi.bmiColors[1].rgbRed = 255;
+    HDC hdc = ::CreateCompatibleDC(NULL);
+    LPVOID pvMonoBits;
+    HBITMAP hMonoBitmap = ::CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, 
&pvMonoBits, NULL, 0);
+    if (!hMonoBitmap)
+    {
+        ::DeleteDC(hdc);
+        return NULL;
+    }
+
+    HBITMAP hNewBitmap = CreateDIBWithProperties(bm.bmWidth, bm.bmHeight);
+    if (hNewBitmap)
+    {
+        ::GetDIBits(hdc, hbm, 0, bm.bmHeight, pvMonoBits, &bmi, 
DIB_RGB_COLORS);
+        ::SetDIBits(hdc, hNewBitmap, 0, bm.bmHeight, pvMonoBits, &bmi, 
DIB_RGB_COLORS);
+    }
+    ::DeleteObject(hMonoBitmap);
+    ::DeleteDC(hdc);
+
+    return hNewBitmap;
+}
diff --git a/base/applications/mspaint/dib.h b/base/applications/mspaint/dib.h
index cefdb6e42b5..bb9d933a14a 100644
--- a/base/applications/mspaint/dib.h
+++ b/base/applications/mspaint/dib.h
@@ -7,10 +7,12 @@
 
 #pragma once
 
+BOOL IsBitmapBlackAndWhite(HBITMAP hbm);
 HBITMAP CreateDIBWithProperties(int width, int height);
 HBITMAP CreateMonoBitmap(int width, int height, BOOL bWhite);
 HBITMAP CreateColorDIB(int width, int height, COLORREF rgb);
 HBITMAP CachedBufferDIB(HBITMAP hbm, int minimalWidth, int minimalHeight);
+HBITMAP ConvertToBlackAndWhite(HBITMAP hbm);
 
 HBITMAP CopyMonoImage(HBITMAP hbm, INT cx = 0, INT cy = 0);
 
diff --git a/base/applications/mspaint/history.cpp 
b/base/applications/mspaint/history.cpp
index 8867a53025a..4451b06f927 100644
--- a/base/applications/mspaint/history.cpp
+++ b/base/applications/mspaint/history.cpp
@@ -270,44 +270,18 @@ HBITMAP ImageModel::CopyBitmap()
 
 BOOL ImageModel::IsBlackAndWhite()
 {
-    LONG cxWidth = GetWidth(), cyHeight = GetHeight();
-    for (LONG y = 0; y < cyHeight; ++y)
-    {
-        for (LONG x = 0; x < cxWidth; ++x)
-        {
-            COLORREF rgbColor = ::GetPixel(m_hDrawingDC, x, y);
-            if (rgbColor != RGB(0, 0, 0) && rgbColor != RGB(255, 255, 255))
-                return FALSE;
-        }
-    }
-    return TRUE;
+    ::SelectObject(m_hDrawingDC, m_hbmOld); // De-select
+    BOOL bBlackAndWhite = IsBitmapBlackAndWhite(m_hBms[m_currInd]);
+    m_hbmOld = ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]); // Re-select
+    return bBlackAndWhite;
 }
 
 void ImageModel::PushBlackAndWhite()
 {
-    HBITMAP hNewBitmap = CopyBitmap();
-    if (!hNewBitmap)
-        return;
-
-    HDC hdc2 = ::CreateCompatibleDC(NULL);
-    HGDIOBJ hbm2Old = ::SelectObject(hdc2, hNewBitmap);
-    LONG cxWidth = GetWidth(), cyHeight = GetHeight();
-    for (LONG y = 0; y < cyHeight; ++y)
-    {
-        for (LONG x = 0; x < cxWidth; ++x)
-        {
-            COLORREF rgbColor = ::GetPixel(m_hDrawingDC, x, y);
-            BYTE Red = GetRValue(rgbColor);
-            BYTE Green = GetGValue(rgbColor);
-            BYTE Blue = GetBValue(rgbColor);
-            if ((Red + Green + Blue) / 3 >= 255 / 2)
-                ::SetPixelV(hdc2, x, y, RGB(255, 255, 255)); // White
-            else
-                ::SetPixelV(hdc2, x, y, RGB(0, 0, 0)); // Black
-        }
-    }
-    ::SelectObject(hdc2, hbm2Old);
-    ::DeleteDC(hdc2);
+    ::SelectObject(m_hDrawingDC, m_hbmOld); // De-select
+    HBITMAP hNewBitmap = ConvertToBlackAndWhite(m_hBms[m_currInd]);
+    m_hbmOld = ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]); // Re-select
 
-    PushImageForUndo(hNewBitmap);
+    if (hNewBitmap)
+        PushImageForUndo(hNewBitmap);
 }

Reply via email to