https://git.reactos.org/?p=reactos.git;a=commitdiff;h=455c1fe1b989a3c1a6731…
commit 455c1fe1b989a3c1a6731e2aa8beb2bdf05fdf2f
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sun Aug 20 16:46:18 2023 +0900
Commit: GitHub <noreply(a)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);
}