reactos/base/applications/mspaint/drawing.cpp
Katayama Hirofumi MZ dfd06ee8fc
[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
2022-02-14 16:18:18 +09:00

343 lines
12 KiB
C++

/*
* PROJECT: PAINT for ReactOS
* LICENSE: LGPL
* FILE: base/applications/mspaint/drawing.cpp
* PURPOSE: The drawing functions used by the tools
* PROGRAMMERS: Benedikt Freisen
*/
/* INCLUDES *********************************************************/
#include "precomp.h"
/* FUNCTIONS ********************************************************/
void
Line(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, int thickness)
{
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, color));
MoveToEx(hdc, x1, y1, NULL);
LineTo(hdc, x2, y2);
DeleteObject(SelectObject(hdc, oldPen));
}
void
Rect(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, int thickness, int style)
{
HBRUSH oldBrush;
LOGBRUSH logbrush;
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
logbrush.lbColor = (style == 2) ? fg : bg;
logbrush.lbHatch = 0;
oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
Rectangle(hdc, x1, y1, x2, y2);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
}
void
Ellp(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, int thickness, int style)
{
HBRUSH oldBrush;
LOGBRUSH logbrush;
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
logbrush.lbColor = (style == 2) ? fg : bg;
logbrush.lbHatch = 0;
oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
Ellipse(hdc, x1, y1, x2, y2);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
}
void
RRect(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, int thickness, int style)
{
LOGBRUSH logbrush;
HBRUSH oldBrush;
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
logbrush.lbColor = (style == 2) ? fg : bg;
logbrush.lbHatch = 0;
oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
RoundRect(hdc, x1, y1, x2, y2, 16, 16);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
}
void
Poly(HDC hdc, POINT * lpPoints, int nCount, COLORREF fg, COLORREF bg, int thickness, int style, BOOL closed, BOOL inverted)
{
LOGBRUSH logbrush;
HBRUSH oldBrush;
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
UINT oldRop = GetROP2(hdc);
if (inverted)
SetROP2(hdc, R2_NOTXORPEN);
logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
logbrush.lbColor = (style == 2) ? fg : bg;
logbrush.lbHatch = 0;
oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
if (closed)
Polygon(hdc, lpPoints, nCount);
else
Polyline(hdc, lpPoints, nCount);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
SetROP2(hdc, oldRop);
}
void
Bezier(HDC hdc, POINT p1, POINT p2, POINT p3, POINT p4, COLORREF color, int thickness)
{
HPEN oldPen;
POINT fourPoints[4];
fourPoints[0] = p1;
fourPoints[1] = p2;
fourPoints[2] = p3;
fourPoints[3] = p4;
oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, color));
PolyBezier(hdc, fourPoints, 4);
DeleteObject(SelectObject(hdc, oldPen));
}
void
Fill(HDC hdc, LONG x, LONG y, COLORREF color)
{
HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(color));
ExtFloodFill(hdc, x, y, GetPixel(hdc, x, y), FLOODFILLSURFACE);
DeleteObject(SelectObject(hdc, oldBrush));
}
void
Erase(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, LONG radius)
{
LONG a, b;
HPEN oldPen;
HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(color));
b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, color));
for(a = 0; a <= b; a++)
Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - radius + 1,
(y1 * (b - a) + y2 * a) / b - radius + 1, (x1 * (b - a) + x2 * a) / b + radius + 1,
(y1 * (b - a) + y2 * a) / b + radius + 1);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
}
void
Replace(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LONG radius)
{
LONG a, b, x, y;
b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
for(a = 0; a <= b; a++)
for(y = (y1 * (b - a) + y2 * a) / b - radius + 1;
y < (y1 * (b - a) + y2 * a) / b + radius + 1; y++)
for(x = (x1 * (b - a) + x2 * a) / b - radius + 1;
x < (x1 * (b - a) + x2 * a) / b + radius + 1; x++)
if (GetPixel(hdc, x, y) == fg)
SetPixel(hdc, x, y, bg);
}
void
Airbrush(HDC hdc, LONG x, LONG y, COLORREF color, LONG r)
{
LONG a, b;
for(b = -r; b <= r; b++)
for(a = -r; a <= r; a++)
if ((a * a + b * b <= r * r) && (rand() % 4 == 0))
SetPixel(hdc, x + a, y + b, color);
}
void
Brush(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, LONG style)
{
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, color));
HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(color));
LONG a, b;
b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
switch (style)
{
case 0:
for(a = 0; a <= b; a++)
Ellipse(hdc, (x1 * (b - a) + x2 * a) / b - 3, (y1 * (b - a) + y2 * a) / b - 3,
(x1 * (b - a) + x2 * a) / b + 4, (y1 * (b - a) + y2 * a) / b + 4);
break;
case 1:
for(a = 0; a <= b; a++)
Ellipse(hdc, (x1 * (b - a) + x2 * a) / b - 1, (y1 * (b - a) + y2 * a) / b - 1,
(x1 * (b - a) + x2 * a) / b + 3, (y1 * (b - a) + y2 * a) / b + 3);
break;
case 2:
MoveToEx(hdc, x1, y1, NULL);
LineTo(hdc, x2, y2);
SetPixel(hdc, x2, y2, color);
break;
case 3:
for(a = 0; a <= b; a++)
Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - 3, (y1 * (b - a) + y2 * a) / b - 3,
(x1 * (b - a) + x2 * a) / b + 5, (y1 * (b - a) + y2 * a) / b + 5);
break;
case 4:
for(a = 0; a <= b; a++)
Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - 2, (y1 * (b - a) + y2 * a) / b - 2,
(x1 * (b - a) + x2 * a) / b + 3, (y1 * (b - a) + y2 * a) / b + 3);
break;
case 5:
for(a = 0; a <= b; a++)
Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - 1, (y1 * (b - a) + y2 * a) / b - 1,
(x1 * (b - a) + x2 * a) / b + 1, (y1 * (b - a) + y2 * a) / b + 1);
break;
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
{
POINT offsTop[] = {{4, -3}, {2, -2}, {0, 0},
{-3, -3}, {-2, -2}, {-1, 0}};
POINT offsBtm[] = {{-3, 4}, {-2, 2}, {-1, 1},
{4, 4}, {2, 2}, {0, 1}};
LONG idx = style - 6;
POINT pts[4];
pts[0].x = x1 + offsTop[idx].x;
pts[0].y = y1 + offsTop[idx].y;
pts[1].x = x1 + offsBtm[idx].x;
pts[1].y = y1 + offsBtm[idx].y;
pts[2].x = x2 + offsBtm[idx].x;
pts[2].y = y2 + offsBtm[idx].y;
pts[3].x = x2 + offsTop[idx].x;
pts[3].y = y2 + offsTop[idx].y;
Polygon(hdc, pts, 4);
break;
}
}
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
}
void
RectSel(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2)
{
HBRUSH oldBrush;
LOGBRUSH logbrush;
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_DOT, 1, GetSysColor(COLOR_HIGHLIGHT)));
UINT oldRop = GetROP2(hdc);
SetROP2(hdc, R2_NOTXORPEN);
logbrush.lbStyle = BS_HOLLOW;
logbrush.lbColor = 0;
logbrush.lbHatch = 0;
oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
Rectangle(hdc, x1, y1, x2, y2);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
SetROP2(hdc, oldRop);
}
void
SelectionFrame(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF system_selection_color)
{
HBRUSH oldBrush;
LOGBRUSH logbrush;
HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_DOT, 1, system_selection_color));
logbrush.lbStyle = BS_HOLLOW;
logbrush.lbColor = 0;
logbrush.lbHatch = 0;
oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
Rectangle(hdc, x1, y1, x2, y2); /* SEL BOX FRAME */
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, system_selection_color));
oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(system_selection_color));
Rectangle(hdc, x1 - 1, y1 - 1, x1 + 2, y1 + 2);
Rectangle(hdc, x2 - 2, y1 - 1, x2 + 2, y1 + 2);
Rectangle(hdc, x1 - 1, y2 - 2, x1 + 2, y2 + 1);
Rectangle(hdc, x2 - 2, y2 - 2, x2 + 2, y2 + 1);
Rectangle(hdc, (x1 + x2) / 2 - 1, y1 - 1, (x1 + x2) / 2 + 2, y1 + 2);
Rectangle(hdc, (x1 + x2) / 2 - 1, y2 - 2, (x1 + x2) / 2 + 2, y2 + 1);
Rectangle(hdc, x1 - 1, (y1 + y2) / 2 - 1, x1 + 2, (y1 + y2) / 2 + 2);
Rectangle(hdc, x2 - 2, (y1 + y2) / 2 - 1, x2 + 1, (y1 + y2) / 2 + 2);
DeleteObject(SelectObject(hdc, oldBrush));
DeleteObject(SelectObject(hdc, oldPen));
}
void
Text(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LPCTSTR lpchText, HFONT font, LONG style)
{
INT iSaveDC = SaveDC(hdc); // We will modify the clipping region. Save now.
RECT rc;
SetRect(&rc, x1, y1, x2, y2);
if (style == 0) // Transparent
{
SetBkMode(hdc, TRANSPARENT);
GetBkColor(hdc);
}
else // Opaque
{
SetBkMode(hdc, OPAQUE);
SetBkColor(hdc, bg);
HBRUSH hbr = CreateSolidBrush(bg);
FillRect(hdc, &rc, hbr); // Fill the background
DeleteObject(hbr);
}
IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
HGDIOBJ hFontOld = SelectObject(hdc, font);
SetTextColor(hdc, fg);
const UINT uFormat = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP |
DT_EXPANDTABS | DT_WORDBREAK;
DrawText(hdc, lpchText, -1, &rc, uFormat);
SelectObject(hdc, hFontOld);
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;
}