Масштабирование растровых изображений WinAPI
Есть окно с областью где можно рисовать мышкой.
Мне нужно рядом разместить такую же область в которой будет уменьшенная версия того рисунка, который нарисован в первой области.
То есть я рисую например букву А в первой области размером 300x300, потом например после нажатия кнопки "Сжать" во второй области размером 64x64 появляется сжатый рисунок А.
Вот код окна:
#include <Windows.h>
#include <vector>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 800
#define WINDOW_XPOS (GetSystemMetrics(SM_CXSCREEN) >> 1) - (WINDOW_WIDTH >> 1)
#define WINDOW_YPOS (GetSystemMetrics(SM_CYSCREEN) >> 1) - (WINDOW_HEIGHT >> 1)
#define CHILD_WIDTH 300
#define CHILD_HEIGHT 300
#define PADDING_L 50
#define PADDING_B 50
HINSTANCE hInst;
RECT clientRect;
HBRUSH WINDOW_BACKGROUND = CreateSolidBrush(RGB(41, 49, 51));
HBRUSH CHILD_BACKGROUND = CreateSolidBrush(RGB(76, 81, 74));
HBRUSH BRUSH_COLOR = CreateSolidBrush(RGB(213, 213, 213));
HPEN hPen = CreatePen(PS_NULL, 0, NULL);
HDC child_hdc;
HDC hdc;
std::vector<std::vector<bool>> pixels = {};
LRESULT CALLBACK ChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static int x = 0, y = 0, x_prev = 0, y_prev = 0, N = 10;
static BOOL fDrawEllipse;
static HBITMAP hBMP;
static HDC hMemDC;
switch (msg) {
case WM_CREATE: {
child_hdc = GetDC(hwnd);
hMemDC = CreateCompatibleDC(child_hdc);
hBMP = CreateCompatibleBitmap(child_hdc, CHILD_WIDTH, CHILD_HEIGHT);
SelectObject(hMemDC, hBMP);
SelectObject(hMemDC, hPen);
SelectObject(hMemDC, BRUSH_COLOR);
FillRect(hMemDC, &clientRect, CHILD_BACKGROUND);
return 0;
}
case WM_LBUTTONDOWN: {
x = LOWORD(lParam);
y = HIWORD(lParam);
fDrawEllipse = true;
Ellipse(hMemDC, x - 5, y - 5, x + 5, y + 5);
BitBlt(child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, hMemDC, 0, 0, SRCCOPY);
return 0;
}
case WM_PAINT: {
BitBlt(child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, hMemDC, 0, 0, SRCCOPY);
return 0;
}
case WM_MOUSEMOVE: {
if (fDrawEllipse) {
x_prev = x;
y_prev = y;
x = LOWORD(lParam);
y = HIWORD(lParam);
for (int i = 0; i < N; ++i) {
int px = x_prev + (x - x_prev) * i / N;
int py = y_prev + (y - y_prev) * i / N;
Ellipse(hMemDC, px - 5, py - 5, px + 5, py + 5);
BitBlt(child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, hMemDC, 0, 0, SRCCOPY);
}
}
return 0;
}
case WM_LBUTTONUP: {
fDrawEllipse = false;
x_prev = 0; y_prev = 0; x = 0; y = 0;
StretchBlt(hdc, 0, 0, 64, 64, child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, SRCCOPY);
return 0;
}
case WM_DESTROY: {
ReleaseDC(hwnd, child_hdc);
DeleteObject(WINDOW_BACKGROUND);
DeleteObject(CHILD_BACKGROUND);
DeleteObject(BRUSH_COLOR);
DeleteObject(hPen);
DeleteDC(hMemDC);
DeleteDC(child_hdc);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static HBITMAP hBMP;
switch (msg) {
case WM_CREATE: {
hdc = GetDC(hwnd);
GetClientRect(hwnd, &clientRect);
WNDCLASSEX wc{};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = ChildProc;
wc.hInstance = hInst;
wc.hbrBackground = CHILD_BACKGROUND;
wc.lpszClassName = "ChildClass";
wc.hCursor = LoadCursor(nullptr, IDC_CROSS);
RegisterClassEx(&wc);
HWND child = CreateWindowEx(0, wc.lpszClassName, (LPCTSTR)nullptr, WS_CHILD | WS_BORDER | WS_VISIBLE,
clientRect.left + PADDING_L, clientRect.bottom - CHILD_HEIGHT - PADDING_B, CHILD_WIDTH, CHILD_HEIGHT,
hwnd, nullptr, hInst, nullptr);
ShowWindow(child, SW_NORMAL);
UpdateWindow(child);
return 0;
}
case WM_DESTROY: {
ReleaseDC(hwnd, hdc);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE,
_In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
HWND hwnd{};
MSG msg{};
WNDCLASSEX wc;
hInst = hInstance;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = WINDOW_BACKGROUND;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wc.hIconSm = nullptr;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = "WindowClass";
wc.lpszMenuName = nullptr;
wc.style = CS_VREDRAW | CS_HREDRAW;
if (!RegisterClassEx(&wc))
return EXIT_FAILURE;
hwnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOPMOST, wc.lpszClassName, "Окно windows",
WS_OVERLAPPEDWINDOW, WINDOW_XPOS, WINDOW_YPOS, WINDOW_WIDTH, WINDOW_HEIGHT,
nullptr, nullptr, hInstance, nullptr);
if (hwnd == INVALID_HANDLE_VALUE)
return EXIT_FAILURE;
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
BOOL bRet;
while (bRet = GetMessage(&msg, nullptr, 0, 0)) {
if (bRet == -1)
return EXIT_FAILURE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Я знаю про функцию StretchBlt, но когда пытался разобраться появилось очень много проблем.
Ответы (1 шт):
Вот полностью рабочий код, который мне нужен был.
#include <Windows.h>
#include <vector>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 800
#define WINDOW_XPOS (GetSystemMetrics(SM_CXSCREEN) >> 1) - (WINDOW_WIDTH >> 1)
#define WINDOW_YPOS (GetSystemMetrics(SM_CYSCREEN) >> 1) - (WINDOW_HEIGHT >> 1)
#define CHILD_WIDTH 300
#define CHILD_HEIGHT 300
#define PADDING_L 50
#define PADDING_B 50
HINSTANCE hInst;
RECT clientRect;
HBRUSH WINDOW_BACKGROUND = CreateSolidBrush(RGB(41, 49, 51));
HBRUSH CHILD_BACKGROUND = CreateSolidBrush(RGB(76, 81, 74));
HBRUSH BRUSH_COLOR = CreateSolidBrush(RGB(213, 213, 213));
HPEN hPen = CreatePen(PS_NULL, 0, NULL);
HDC child_hdc;
HDC hdc;
std::vector<std::vector<bool>> pixels = {};
LRESULT CALLBACK ChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static int x = 0, y = 0, x_prev = 0, y_prev = 0, N = 20;
static BOOL fDrawEllipse;
static HBITMAP hBMP;
static HDC hMemDC;
switch (msg) {
case WM_CREATE: {
child_hdc = GetDC(hwnd);
hMemDC = CreateCompatibleDC(child_hdc);
hBMP = CreateCompatibleBitmap(child_hdc, CHILD_WIDTH, CHILD_HEIGHT);
SelectObject(hMemDC, hBMP);
SelectObject(hMemDC, hPen);
SelectObject(hMemDC, BRUSH_COLOR);
FillRect(hMemDC, &clientRect, CHILD_BACKGROUND);
return 0;
}
case WM_LBUTTONDOWN: {
x = LOWORD(lParam);
y = HIWORD(lParam);
fDrawEllipse = true;
Ellipse(hMemDC, x - 5, y - 5, x + 5, y + 5);
BitBlt(child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, hMemDC, 0, 0, SRCCOPY);
return 0;
}
case WM_PAINT: {
BitBlt(child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, hMemDC, 0, 0, SRCCOPY);
return 0;
}
case WM_MOUSEMOVE: {
if (fDrawEllipse) {
x_prev = x;
y_prev = y;
x = LOWORD(lParam);
y = HIWORD(lParam);
for (int i = 0; i < N; ++i) {
int px = x_prev + (x - x_prev) * i / N;
int py = y_prev + (y - y_prev) * i / N;
Ellipse(hMemDC, px - 5, py - 5, px + 5, py + 5);
BitBlt(child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, hMemDC, 0, 0, SRCCOPY);
}
}
return 0;
}
case WM_LBUTTONUP: {
fDrawEllipse = false;
x_prev = 0; y_prev = 0; x = 0; y = 0;
return 0;
}
case WM_DESTROY: {
ReleaseDC(hwnd, child_hdc);
DeleteObject(WINDOW_BACKGROUND);
DeleteObject(CHILD_BACKGROUND);
DeleteObject(BRUSH_COLOR);
DeleteObject(hPen);
DeleteDC(hMemDC);
DeleteDC(child_hdc);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static HBITMAP hBMP;
static HWND child;
switch (msg) {
case WM_CREATE: {
hdc = GetDC(hwnd);
GetClientRect(hwnd, &clientRect);
WNDCLASSEX wc{};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = ChildProc;
wc.hInstance = hInst;
wc.hbrBackground = CHILD_BACKGROUND;
wc.lpszClassName = "ChildClass";
wc.hCursor = LoadCursor(nullptr, IDC_CROSS);
RegisterClassEx(&wc);
child = CreateWindowEx(0, wc.lpszClassName, (LPCTSTR)nullptr, WS_CHILD | WS_BORDER | WS_VISIBLE,
clientRect.left + PADDING_L, clientRect.bottom - CHILD_HEIGHT - PADDING_B, CHILD_WIDTH, CHILD_HEIGHT,
hwnd, nullptr, hInst, nullptr);
ShowWindow(child, SW_NORMAL);
UpdateWindow(child);
return 0;
}
case WM_PAINT: {
StretchBlt(hdc, 0, 0, 64, 64, child_hdc, 0, 0, CHILD_WIDTH, CHILD_HEIGHT, SRCCOPY);
UpdateWindow(child);
return 0;
}
case WM_DESTROY: {
ReleaseDC(hwnd, hdc);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE,
_In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
HWND hwnd{};
MSG msg{};
WNDCLASSEX wc;
hInst = hInstance;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = WINDOW_BACKGROUND;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wc.hIconSm = nullptr;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = "WindowClass";
wc.lpszMenuName = nullptr;
wc.style = CS_VREDRAW | CS_HREDRAW;
if (!RegisterClassEx(&wc))
return EXIT_FAILURE;
hwnd = CreateWindowEx(WS_EX_WINDOWEDGE, wc.lpszClassName, "Окно windows",
WS_OVERLAPPEDWINDOW, WINDOW_XPOS, WINDOW_YPOS, WINDOW_WIDTH, WINDOW_HEIGHT,
nullptr, nullptr, hInstance, nullptr);
if (hwnd == INVALID_HANDLE_VALUE)
return EXIT_FAILURE;
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
BOOL bRet;
while (bRet = GetMessage(&msg, nullptr, 0, 0)) {
if (bRet == -1)
return EXIT_FAILURE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Когда ты рисуешь в большом прямоугольнике, то сразу обновляется в урезанном виде в маленьком. Так же при изменении размера, сворачивании и тд поля остаются не тронутыми.
Возможно выглядит костыльно, если так, то приведите в виде ответа пример хорошего кода. Буду очень рад!) И если будет так же работать, то выберу ваш ответ как правильный.