From dfd06ee8fc53882a6ef3d7a126aff809cea811f7 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Mon, 14 Feb 2022 16:18:18 +0900 Subject: [PATCH] [MSPAINT] Implement skew (#4362) - Add SkewDIB helper function in dib.cpp. - Implement Stretch and Skew feature by SelectionModel::StretchSkew and ImageModel::StretchSkew. - Move ColorKeyedMaskBlt function. CORE-16634 --- base/applications/mspaint/dib.cpp | 56 ++++++++++++++++++++ base/applications/mspaint/dib.h | 2 + base/applications/mspaint/drawing.cpp | 33 ++++++++++++ base/applications/mspaint/drawing.h | 5 ++ base/applications/mspaint/history.cpp | 16 +++++- base/applications/mspaint/selection.cpp | 33 ------------ base/applications/mspaint/selectionmodel.cpp | 46 ++++++++++++++-- base/applications/mspaint/selectionmodel.h | 1 + base/applications/mspaint/winproc.cpp | 12 ++++- 9 files changed, 165 insertions(+), 39 deletions(-) diff --git a/base/applications/mspaint/dib.cpp b/base/applications/mspaint/dib.cpp index 711071752ad..01c23fa84bf 100644 --- a/base/applications/mspaint/dib.cpp +++ b/base/applications/mspaint/dib.cpp @@ -9,6 +9,7 @@ /* INCLUDES *********************************************************/ #include "precomp.h" +#include /* FUNCTIONS ********************************************************/ @@ -243,3 +244,58 @@ HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight) DeleteDC(hDC2); return hbm2; } + +#ifndef M_PI + #define M_PI 3.14159265 +#endif + +HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical) +{ + if (nDegree == 0) + return CopyDIBImage(hbm); + + const double eTan = tan(abs(nDegree) * M_PI / 180); + + BITMAP bm; + GetObjectW(hbm, sizeof(bm), &bm); + INT cx = bm.bmWidth, cy = bm.bmHeight, dx = 0, dy = 0; + if (bVertical) + dy = INT(cx * eTan); + else + dx = INT(cy * eTan); + + if (dx == 0 && dy == 0) + return CopyDIBImage(hbm); + + HBITMAP hbmNew = CreateColorDIB(cx + dx, cy + dy, RGB(255, 255, 255)); + if (!hbmNew) + return NULL; + + HDC hDC2 = CreateCompatibleDC(NULL); + HGDIOBJ hbm2Old = SelectObject(hDC2, hbmNew); + if (bVertical) + { + for (INT x = 0; x < cx; ++x) + { + INT delta = INT(x * eTan); + if (nDegree > 0) + BitBlt(hDC2, x, (dy - delta), 1, cy, hDC1, x, 0, SRCCOPY); + else + BitBlt(hDC2, x, delta, 1, cy, hDC1, x, 0, SRCCOPY); + } + } + else + { + for (INT y = 0; y < cy; ++y) + { + INT delta = INT(y * eTan); + if (nDegree > 0) + BitBlt(hDC2, (dx - delta), y, cx, 1, hDC1, 0, y, SRCCOPY); + else + BitBlt(hDC2, delta, y, cx, 1, hDC1, 0, y, SRCCOPY); + } + } + SelectObject(hDC2, hbm2Old); + DeleteDC(hDC2); + return hbmNew; +} diff --git a/base/applications/mspaint/dib.h b/base/applications/mspaint/dib.h index b045be15a50..e0f8d14f19a 100644 --- a/base/applications/mspaint/dib.h +++ b/base/applications/mspaint/dib.h @@ -29,3 +29,5 @@ void ShowFileLoadError(LPCTSTR name); HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, DWORD dwFileSize, BOOL isFile); HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight); + +HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical); diff --git a/base/applications/mspaint/drawing.cpp b/base/applications/mspaint/drawing.cpp index 059559252b9..490ff9a0a62 100644 --- a/base/applications/mspaint/drawing.cpp +++ b/base/applications/mspaint/drawing.cpp @@ -307,3 +307,36 @@ Text(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LPCT RestoreDC(hdc, iSaveDC); // Restore } + +BOOL +ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, + HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask, + DWORD dwRop, COLORREF keyColor) +{ + HDC hTempDC; + HDC hTempDC2; + HBITMAP hTempBm; + HBRUSH hTempBrush; + HBITMAP hTempMask; + + hTempDC = CreateCompatibleDC(hdcSrc); + hTempDC2 = CreateCompatibleDC(hdcSrc); + hTempBm = CreateCompatibleBitmap(hTempDC, nWidth, nHeight); + SelectObject(hTempDC, hTempBm); + hTempBrush = CreateSolidBrush(keyColor); + SelectObject(hTempDC, hTempBrush); + BitBlt(hTempDC, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY); + PatBlt(hTempDC, 0, 0, nWidth, nHeight, PATINVERT); + hTempMask = CreateBitmap(nWidth, nHeight, 1, 1, NULL); + SelectObject(hTempDC2, hTempMask); + BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, 0, 0, SRCCOPY); + SelectObject(hTempDC, hbmMask); + BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, xMask, yMask, SRCAND); + MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, hTempMask, xMask, yMask, dwRop); + DeleteDC(hTempDC); + DeleteDC(hTempDC2); + DeleteObject(hTempBm); + DeleteObject(hTempBrush); + DeleteObject(hTempMask); + return TRUE; +} diff --git a/base/applications/mspaint/drawing.h b/base/applications/mspaint/drawing.h index 017b71f6ddb..26178a83395 100644 --- a/base/applications/mspaint/drawing.h +++ b/base/applications/mspaint/drawing.h @@ -35,3 +35,8 @@ void RectSel(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2); void SelectionFrame(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF system_selection_color); void Text(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LPCTSTR lpchText, HFONT font, LONG style); + +extern BOOL +ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, + HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask, + DWORD dwRop, COLORREF keyColor); diff --git a/base/applications/mspaint/history.cpp b/base/applications/mspaint/history.cpp index d771fd37225..f0a3691ed5e 100644 --- a/base/applications/mspaint/history.cpp +++ b/base/applications/mspaint/history.cpp @@ -192,7 +192,21 @@ void ImageModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSk int oldHeight = GetHeight(); INT newWidth = oldWidth * nStretchPercentX / 100; INT newHeight = oldHeight * nStretchPercentY / 100; - Insert(CopyDIBImage(hBms[currInd], newWidth, newHeight)); + if (oldWidth != newWidth || oldHeight != newHeight) + { + HBITMAP hbm0 = CopyDIBImage(hBms[currInd], newWidth, newHeight); + Insert(hbm0); + } + if (nSkewDegX) + { + HBITMAP hbm1 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegX, FALSE); + Insert(hbm1); + } + if (nSkewDegY) + { + HBITMAP hbm2 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegY, TRUE); + Insert(hbm2); + } if (GetWidth() != oldWidth || GetHeight() != oldHeight) NotifyDimensionsChanged(); NotifyImageChanged(); diff --git a/base/applications/mspaint/selection.cpp b/base/applications/mspaint/selection.cpp index 992b946a28a..3a87a21f19d 100644 --- a/base/applications/mspaint/selection.cpp +++ b/base/applications/mspaint/selection.cpp @@ -21,39 +21,6 @@ const LPCTSTR CSelectionWindow::m_lpszCursorLUT[9] = { /* action to mouse cursor IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE }; -BOOL -ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, - HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask, - DWORD dwRop, COLORREF keyColor) -{ - HDC hTempDC; - HDC hTempDC2; - HBITMAP hTempBm; - HBRUSH hTempBrush; - HBITMAP hTempMask; - - hTempDC = CreateCompatibleDC(hdcSrc); - hTempDC2 = CreateCompatibleDC(hdcSrc); - hTempBm = CreateCompatibleBitmap(hTempDC, nWidth, nHeight); - SelectObject(hTempDC, hTempBm); - hTempBrush = CreateSolidBrush(keyColor); - SelectObject(hTempDC, hTempBrush); - BitBlt(hTempDC, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY); - PatBlt(hTempDC, 0, 0, nWidth, nHeight, PATINVERT); - hTempMask = CreateBitmap(nWidth, nHeight, 1, 1, NULL); - SelectObject(hTempDC2, hTempMask); - BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, 0, 0, SRCCOPY); - SelectObject(hTempDC, hbmMask); - BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, xMask, yMask, SRCAND); - MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, hTempMask, xMask, yMask, dwRop); - DeleteDC(hTempDC); - DeleteDC(hTempDC2); - DeleteObject(hTempBm); - DeleteObject(hTempBrush); - DeleteObject(hTempMask); - return TRUE; -} - void CSelectionWindow::ForceRefreshSelectionContents() { if (::IsWindowVisible(selectionWindow)) diff --git a/base/applications/mspaint/selectionmodel.cpp b/base/applications/mspaint/selectionmodel.cpp index c65ae21ac84..3cd41e1f64f 100644 --- a/base/applications/mspaint/selectionmodel.cpp +++ b/base/applications/mspaint/selectionmodel.cpp @@ -124,9 +124,6 @@ void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg) Rect(hDCImage, m_rcSrc.left, m_rcSrc.top, m_rcSrc.right, m_rcSrc.bottom, crBg, crBg, 0, 1); } -extern BOOL -ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask, DWORD dwRop, COLORREF keyColor); - void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent) { if (!bBgTransparent) @@ -239,6 +236,49 @@ void SelectionModel::RotateNTimes90Degrees(int iN) NotifyRefreshNeeded(); } +void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY) +{ + if (nStretchPercentX == 100 && nStretchPercentY == 100 && nSkewDegX == 0 && nSkewDegY == 0) + return; + + imageModel.DeleteSelection(); + imageModel.CopyPrevious(); + + INT oldWidth = RECT_WIDTH(m_rcDest); + INT oldHeight = RECT_HEIGHT(m_rcDest); + INT newWidth = oldWidth * nStretchPercentX / 100; + INT newHeight = oldHeight * nStretchPercentY / 100; + + if (oldWidth != newWidth || oldHeight != newHeight) + { + SelectObject(m_hDC, m_hBm); + HBITMAP hbm0 = CopyDIBImage(m_hBm, newWidth, newHeight); + InsertFromHBITMAP(hbm0, m_rcDest.left, m_rcDest.top); + DeleteObject(hbm0); + } + + if (nSkewDegX) + { + SelectObject(m_hDC, m_hBm); + HBITMAP hbm1 = SkewDIB(m_hDC, m_hBm, nSkewDegX, FALSE); + InsertFromHBITMAP(hbm1, m_rcDest.left, m_rcDest.top); + DeleteObject(hbm1); + } + + if (nSkewDegY) + { + SelectObject(m_hDC, m_hBm); + HBITMAP hbm2 = SkewDIB(m_hDC, m_hBm, nSkewDegY, TRUE); + InsertFromHBITMAP(hbm2, m_rcDest.left, m_rcDest.top); + DeleteObject(hbm2); + } + + selectionWindow.ShowWindow(SW_SHOWNOACTIVATE); + selectionWindow.ForceRefreshSelectionContents(); + placeSelWin(); + NotifyRefreshNeeded(); +} + HBITMAP SelectionModel::GetBitmap() const { return m_hBm; diff --git a/base/applications/mspaint/selectionmodel.h b/base/applications/mspaint/selectionmodel.h index b3a6982dffe..fbb208fed4b 100644 --- a/base/applications/mspaint/selectionmodel.h +++ b/base/applications/mspaint/selectionmodel.h @@ -54,6 +54,7 @@ public: void FlipHorizontally(); void FlipVertically(); void RotateNTimes90Degrees(int iN); + void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX = 0, int nSkewDegY = 0); HBITMAP GetBitmap() const; int PtStackSize() const; void DrawFramePoly(HDC hDCImage); diff --git a/base/applications/mspaint/winproc.cpp b/base/applications/mspaint/winproc.cpp index 3bc14f6ae72..74e27a67661 100644 --- a/base/applications/mspaint/winproc.cpp +++ b/base/applications/mspaint/winproc.cpp @@ -695,8 +695,16 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH { if (stretchSkewDialog.DoModal(mainWindow.m_hWnd)) { - imageModel.StretchSkew(stretchSkewDialog.percentage.x, stretchSkewDialog.percentage.y, - stretchSkewDialog.angle.x, stretchSkewDialog.angle.y); + if (::IsWindowVisible(selectionWindow)) + { + selectionModel.StretchSkew(stretchSkewDialog.percentage.x, stretchSkewDialog.percentage.y, + stretchSkewDialog.angle.x, stretchSkewDialog.angle.y); + } + else + { + imageModel.StretchSkew(stretchSkewDialog.percentage.x, stretchSkewDialog.percentage.y, + stretchSkewDialog.angle.x, stretchSkewDialog.angle.y); + } } break; }