[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
This commit is contained in:
Katayama Hirofumi MZ 2022-02-14 16:18:18 +09:00 committed by GitHub
parent 2d90919047
commit dfd06ee8fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 165 additions and 39 deletions

View file

@ -9,6 +9,7 @@
/* INCLUDES *********************************************************/
#include "precomp.h"
#include <math.h>
/* 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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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();

View file

@ -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))

View file

@ -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;

View file

@ -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);

View file

@ -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;
}