mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[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:
parent
2d90919047
commit
dfd06ee8fc
9 changed files with 165 additions and 39 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue