Skip to content

Commit

Permalink
[MSPAINT] Speed up for black and white (reactos#5563)
Browse files Browse the repository at this point in the history
Follow-up to reactos#5554.
- Speed up ImageModel::PushBlackAndWhite
  by using GetDIBits and SetDIBits.
CORE-19094
  • Loading branch information
katahiromz authored Aug 20, 2023
1 parent 49dbc8f commit 455c1fe
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 35 deletions.
93 changes: 93 additions & 0 deletions base/applications/mspaint/dib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions base/applications/mspaint/dib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
44 changes: 9 additions & 35 deletions base/applications/mspaint/history.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 455c1fe

Please sign in to comment.