Простой графический редактор
Содержание
Введение
Цель курсового проекта: получение навыков по разработке программы на языке C\C++ , с использованием WinAPI, для реализации пользовательского интерфейса, а также реализация простенького графического редактора.
Программный продукт написан на языке программирования С++. Реализация темы курсовой работы выполняется с среде Visual С++ с использованием WinAPI.
Системные требования для использования программы:
- Операционная система MS-DOS, Windows 98/2000/xp/Vista/7;
- Процессор от Intel Pentium I и выше;
- 32 MB RAM(ОЗУ) и выше;
- HDD(Дисковая память) 20 MB;
Для создания программы использовался компьютер со следующими характеристиками:
- Intel Core-Duo, 2800 MHz, 2 GВ
- Nvidia Geforce 8600GT, 80 GB HDD;
- Операционная система Microsoft Windows 7.
1. Анализ задания и постановка задач
Курсовая работа представляет собой создание простейшего графического редактора.
Должна быть создана программа, способная производить основные действия над графическими примитивами.
Программа должна осуществлять:
- Рисование с помощью графического инструмента «Кисть»;
- Рисование с помощью графического инструмента «Прямоугольник»;
- Рисование с помощью графического инструмента «Окружность»;
- Рисование с помощью графического инструмента «Распылитель»;
- Рисование с помощью графического инструмента «Прямая»;
- Рисование с помощью графического инструмента «Заливка»;
- Создание и изменение графических файлов.
2. Теоретическая часть
Windows API (application programming interfaces) – общее наименование целого набора базовых функций интерфейсов, программирования приложений операционных систем семейств Windows и Windows NT корпорации «Майкрософт». Является самым прямым способом взаимодействия приложений с Windows.
Все что делает любая программа – делает либо непосредственно с помощью инструкций процессора, либо обращаясь к функциям биоса (хотя их прямые вызовы используются всё реже), либо через системные функции (API). К последним относится: прорисовка окон, получение координат мыши, чтение файлов и т. д.
WinAPI – это основа, в
который должен разбираться
Для обработки изображений на компьютере используются специальные программы - графические редакторы. Графический редактор - это программа создания, редактирования и просмотра графических изображений.
Изображения в графических редакторах хранятся по-разному.
Растровое изображение хранится с помощью точек различного цвета (пикселей), которые образуют строки и столбцы. Любой пиксель имеет фиксированное положение и цвет. Хранение каждого пикселя требует некоторого количества бит информации, которое зависит от количества цветов в изображении.
Векторные изображения формируются из объектов (точка, линия, окружность и т. д.), которые хранятся в памяти компьютера в виде графических примитивов и описывающих их математических формул.
Например, графический примитив точка задается своими координатами (X, У), линия - координатами начала (XI, Y1) и конца (Х2, Y2), окружность - координатами центра (X, У) и радиусом (R), прямоугольник - величиной сторон и координатами левого верхнего угла (XI, У1) и правого нижнего угла (Х2, У2) и т. д. Для каждого примитива назначается также цвет.
Как следствие, графические редакторы подразделяются на две категории: растровые и векторные. Они отличаются по способу, которым представляют графическую информацию.
Векторные графические редакторы
Векторные графические изображения являются оптимальным средством для хранения высокоточных графических объектов (чертежи, схемы и т. д.), для которых имеет значение наличие четких и ясных контуров. С векторной графикой вы сталкиваетесь, когда работаете с системами компьютерного черчения и автоматизированного проектирования, с программами обработки трехмерной графики. Все компоненты векторного изображения описываются математически, а значит - абсолютно точно. Векторные изображения, как правило, строятся вручную, однако в некоторых случаях они могут быть также получены из растровых с помощью программ трассировки. Векторные изображения не в состоянии обеспечить близкую к оригиналу реалистичность, но достоинством векторной графики является то, что файлы, хранящие векторные графические изображения, имеют сравнительно небольшой объем. Важно также, что векторные графические изображения могут быть увеличены или уменьшены без потери качества.
Растровые графические редакторы
Растровые графические редакторы являются наилучшим средством обработки фотографий и рисунков, поскольку растровые изображения обеспечивают высокую точность передачи градаций цветов и полутонов. Способ представления растровых изображений совершенно отличен от векторных. Растровые изображения состоят из отдельных точек, называемых растром. Такое представление изображений существует не только в цифровом виде. Растровые изображения обеспечивают максимальную реалистичность, поскольку в цифровую форму переводится каждый мельчайший фрагмент оригинала. Такие изображения сохраняются в файлах гораздо большего объёма, чем векторные, поскольку в них запоминается информация о каждом пикселе изображения. Таким образом, качество растровых изображений зависит от их размера (числа пикселей по горизонтали и вертикали) и количества цветов, которые могут принимать пиксели. Как следствие того, что они состоят из пикселей фиксированного размера, свободное масштабирование без потери качества к ним не применимо. Эта особенность, а также сама структура растровых изображений несколько затрудняет их редактирование и обработку.
Но кроме создания
изображений графические
Структура – это набор из одной или более переменных, возможно различных типов, сгруппированных под одним именем для удобства обработки. (В некоторых языках, самый известный из которых паскаль, структуры называются “записями”). Структуры оказываются полезными при организации сложных данных особенно в больших программах, поскольку во многих ситуациях они позволяют сгруппировать связанные данные таким образом, что с ними можно обращаться, как с одним целым, а не как с отдельными объектами.
Массив – один из структурированных типов данных. Характеризуется тем, что все его элементы имеют один и тот же тип. При определении массива следует указать его имя и количество элементов. В некоторых случаях допустимо описание без указания количества элементов. Все элементы имеют одно имя – имя массива и отличаются индексами – порядковыми номерами в массиве. Количество элементов в массиве называется его размером.
Указатель – это переменная, содержащая адрес другой переменой. Значениями указателей служат адреса участков памяти, выделенных для объектов конкретных типов. Именно поэтому в определении и описании указателя всегда присутствует обозначение соответствующего ему типа. Эта информация позволяет в последующем с помощью указателя получить доступ ко всему сохраняемому объекту в целом.
Динамическая память – это память, выделяемая программе для ее работы за вычетом сегмента данных, стека, в котором размещаются локальные переменные подпрограмм и собственно тела программы. Для работы с динамической памятью используют указатели. С их помощью осуществляется доступ к участкам динамической памяти, которые называются динамическими переменными. Динамические переменные создаются с помощью специальных функций и операций. Они существуют либо до конца работы программ, либо до тех пор, пока не будут уничтожены с помощью специальных функций или операций. Для создания динамических переменных используют операцию new, определенную в C++; Для удаления динамических переменных используется операция delete, определенная в C++. Размера сегмента данных может быть недостаточно для размещения больших массивов информации. Выходом из этой ситуации является использование динамической памяти.
Язык С, как и другие языки программирования высокого уровня, позволяет осуществлять операции файлового ввода и вывода. Основной алгоритм обработки файлов выполняется в три действия в следующем порядке:
- открытие файла;
- чтение и/или запись данных в файл;
- закрытие файла.
В языке С все файлы делятся на два вида:
- бинарные;
- текстовые.
Бинарный файл - файл, содержащий структурированную или не структурированную информацию, представленную в двоичном (бинарном) виде.
Текстовый файл - файл, содержащий структурированную или не структурированную информацию, представленную в текстовом (ASCII символы) виде.
Операции чтения и записи для текстовых и бинарных файлов отличаются друг от друга (в языке С реализованы в виде различных функций). В языке С для работы с файлами набор функций реализован в библиотеке stdio.h.
Функция - это синтаксически выделенный именованный программный модуль, выполняющий определенное действие или группу действий. Каждая функция имеет свой интерфейс и реализацию.
Интерфейс функции - заголовок функции, в котором указывается название функции, список ее параметров и тип возвращаемого значения.
Реализация функции - тело функции, содержащее внутренние (локальные) данные функции и программный код, выполняющий действия согласно переданным в функцию параметрам и возвращающий значение, соответствующего интерфейсу функции типа.
3. Проектирование программы
При проектировании программы главным этапом является выделение ее ключевых составных частей. Каждая такая часть ответственна за определенные задачи, решаемые в процессе выполнения программы, и является относительно автономной либо частично зависимой от других частей.
В программе выделяется один программный модуль Main.cpp, который является главным модулем программы и содержит реализации процедур работы с графикой.
Функции модуля TextEditor.cpp:
- void Spray(int iDens) – обработчик инструмента «Распылитель»;
- void ClearChecks() – обнуление выбора;
- void ZeroMem(char* ptr, int len) – обнуление памяти;
- bool OpenSaveDlg(bool bSave, HWND hDlg) – диалог сохранения файла;
- void UpdateMenuBmp(HBITMAP bmp, COLORREF clr) – обновление области рисования;
- BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) – функция обработки пунктов меню и инструментов рисования;
- int __stdcall WMain() – инициализация главного окна программы;
- int __stdcall WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd ) – функция вызова главного окна программы.
4. Реализация программы
В модуле Main.cpp реализуются функции инициализации программы и главная функция программы:
В программе объявляются переменные:
- bool bDraw – признак рисования;
- int x, y, x2, y2, x3, y3 – координаты для листа и инструментов рисования;
- HBITMAP bmpBack, bmpUndo, bmpRedo, bmpForeMenu, bmpBackMenu – инструменты отмены действий, возврата;
- HDC dcBack, dcMenuBmp, dcUndo, dcRedo, dcItemPaint – переменные меню, отмены действий;
- HPEN pen – переменная инструмента «карандаш»;
- HBRUSH brush – переменная инструмента «Кисть»;
- wchar_t cBuf[1024] – буфер;
- OPENFILENAMEW ofn – структура OPENFILENAME, используется при вызове окон "Открыть" и "Сохранить как...".
BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) – главная функция программы.
Функция осуществляет обработку пунктов меню и реализует большинство инструментов рисования(выбор толщины кисти, инструмент выбора цвета кисти, инструменты «Кисть», «Прямоугольник», «Окружность», «Прямая» и инструмент заливки).
В главную функцию передаются некоторые параметры, она не возвращает значений.
void Spray(int iDens) – обработчик инструмента «Распылитель».
Функция осуществляет генерацию точек распылителя, определение координат вывода и вывод точек на экран(лист рисования).
Функция не возвращает значений.
void ClearChecks() – обнуление выбора.
Функция по идентификатору обнуляет выбор размеров кисти.
В функцию не передаются значения и она не возвращает значений.
void ZeroMem(char* ptr, int len) – обнуление памяти.
Функция по передаваемому указателю и длине обнуляет память.
Функция не возвращает значений.
bool OpenSaveDlg(bool bSave, HWND hDlg) – диалог открытия/сохранения файла.
Функция осуществляет подготовку и
вызов диалога открытия/
В функцию передается признак сохранения. Возвращаемым значением является сам диалог сохранения/открытия.
void UpdateMenuBmp(HBITMAP bmp, COLORREF clr) – обновление области рисования.
int __stdcall WMain() – инициализация главного окна программы.
Функция осуществляет создание главного окна программы, инициализацию заголовка окна.
В функцию не передается параметров.
int __stdcall WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd ) – функция вызова главного окна программы.
Функция осуществляет вызов главного окна программы и оно же является возвращаемым значением.
5. Тестирование программы
При запуске программы открывается главное окно программы(Рисунок 1). По умолчанию программа создает пустую область рисования.
Рисунок 1 – Главное окно программы
Меню «Файл»(Рисунок 2) и его подпункты позволяют создать графический файл, открыть существующий, сохранить созданный или измененный графический файл. Диалог сохранения/открытия файла приведен на рисунке 3.
Рисунок 2 – Меню «Файл»
Рисунок 3 – Диалог открытия/сохранения файла
Рисунок 4 позволяет увидеть главное окно программы с загруженным графическим файлом.
Рисунок 4 – Загруженный файл
Меню «Правка», подпункт «Отмена» позволяет осуществить откат произведенных изменений(Рисунок 5).
Рисунок 5 – Меню «Правка->Отмена»
Меню «Цвет» позволяет
выбрать цвета пера, соответствующих
правой и левой кнопке мыши, а
также производить обмен
Рисунок 6 – Меню «Цвет»
Диалог выбора цвета приведен на рисунке 7.
Рисунок 7 – Диалог выбора цвета пера
Для выбора толщины кисти нужно воспользоваться меню «Толщина кисти»(Рисунок 8), где можно выбрать один из множества вариантов. На рисунке 9 приведен пример всех возможных вариантов толщины кисти программы.
Рисунок 8 – Меню «Толщина кисти»
Рисунок 9 – Примеры толщин кистей
Меню «Инструменты»(Рисунок 10) позволяет выбрать один из возможных инструментов рисования, таких как кисть, прямоугольник, окружность, примая, а также инструменты заливки и рапылителя.
Рисунок 10 – Меню «Инструменты»
На рисунке 11 приведены примеры всех инструментов рисования доступных в программе.
Рисунок 11 – Примеры инструментов рисования
Для просмотра инвормации о программе надо выбрать пункт меню «О программе…»(Рисунок 12).
Рисунок 12 – Сообщение «О программе»
Для выхода из программы необходимо воспользоваться пунктом меню «Файл->Выход».
Заключение
В курсовом проекте была реализована программа, позволяющая производить операции открытия, создания, редактирования и сохранения графических файлов, позволяет рисовать прямоугольники, окружности, прямые, рисовать кистью и распылителем. Поддерживаются выбираемые два цвета (фоновый и главный), смена размера кисти, загрузка картинок в формате JPG, GIF, PNG, BMP и сохранение в GIF, PNG, BMP. Были получены навыки и умения проектирования программного продукта на WinAPI.
Программа была протестирована, проверена на правильность выполнения операций: открытия, создания, редактирования и сохранения графических файлов и рисования с помощью графических примитивов.
Меню программы доступно и понятно пользователю.
Литература
- Ганеев Р. М. Проектирование интерфейса пользователя средствами Win32 API / Р. М. Ганеев. – М. : Горячая Линия – Телеком, 2001. – 336 с.
- Литвиненко Н. А. – Технология программирования на C++. Win32 API-приложения. / Н. А. Литвиненко – СПб. : БХВ-Петербург, 2010. – 288 с.
- Румянцев П.В. – Азбука программирования в Win32 API /П.В. Румянцев. М. : Горячая Линия - Телеком, 2004 г. 312 с.
- Румянцев П.В. – Работа с файлами в Win32 API / П.В. Румянцев. М. : Горячая Линия – Телеком,2002.216 с.
Приложение А
Функциональная схема программы
Приложение Б
Листинг программы
Модуль Main.cpp
#include "StdAfx.h"
#include "Main.h"
#include <math.h>
#ifdef NDEBUG
#pragma comment(linker,"/ALIGN:4096")
#pragma comment(linker,"/SUBSYSTEM:
#pragma comment(linker,"/MERGE:.rdata=
#pragma comment(linker,"/ENTRY:WMain")
#pragma comment(linker,"/NODEFAULTLIB"
#endif
#define CANVASWIDTH 1600
#define CANVASHEIGHT 1200
bool bDraw;
int x, y, x2, y2, x3, y3;
int px = 0, py = 0;
HBITMAP bmpBack, bmpUndo, bmpRedo, bmpForeMenu, bmpBackMenu;
HDC dcBack, dcMenuBmp, dcUndo, dcRedo, dcItemPaint;
HPEN pen;
HBRUSH brush;
wchar_t cBuf[1024];
OPENFILENAMEW ofn;
HDC dc;
int i, j;
DRAWITEMSTRUCT* disItem = NULL;
RECT rcTmp;
Gdiplus::GdiplusStartupInput gpsiGPSI;
Gdiplus::ImageCodecInfo iciArray[20];
ULONG_PTR upGDIP = 0;
Gdiplus::Bitmap* bmpLoaded;
Gdiplus::Graphics* grBack;
CHOOSECOLOR ccColor;
COLORREF crBrushColor, crBackColor, crTmp;
COLORREF ccArray[16];
char cFormat;
int iPenWidth = 3;
int iTool = 0;
HMENU mnuMain;
bool bFore = true;
int rad, dist;
HCRYPTPROV hProv;
SCROLLINFO sinfo;
template<typename T> int cmpstr(T* str1, T* str2, int iLen)
{
while (iLen > 0)
{
if (*str1 > *str2)
return 1;
if (*str1 < *str2)
return -1;
str1++;
str2++;
iLen--;
}
return 0;
}
template<typename T> void cpystr(T* dst, T* src, int iLen)
{
while (iLen > 0)
{
*dst++ = *src++;
iLen--;
}
}
template<typename T> int lenstr(T* str)
{
int iRes = 0;
while (*str)
{
str++;
iRes++;
}
return iRes;
}
void Spray(int iDens)
{
for (i = 0; i < iDens; i++)
{
CryptGenRandom(hProv, sizeof(x3), (BYTE*)&x3);
CryptGenRandom(hProv, sizeof(y3), (BYTE*)&y3);
x3 = x3 % iPenWidth;
y3 = y3 % iPenWidth;
SetPixel(dcBack, x3 + x2 + px, y3 + y2 + py, bFore ? crBrushColor : crBackColor);
SetPixel(dc, x3 + x2, y3 + y2, bFore ? crBrushColor : crBackColor);
}
}
void ClearChecks()
{
for (i = ID_40016; i <= ID_40028; i++)
CheckMenuItem(mnuMain, i, MF_UNCHECKED);
}
void ZeroMem(char* ptr, int len)
{
while (len--)
{
if (len) *ptr = 0;
ptr++;
}
}
bool OpenSaveDlg(bool bSave, HWND hDlg)
{
ZeroMem((char*)&ofn, sizeof(ofn));
cBuf[0] = '\0';
ofn.lStructSize = sizeof(OPENFILENAMEW);
ofn.hwndOwner = hDlg;
ofn.hInstance = GetModuleHandle(NULL);
if (!bSave)
ofn.lpstrFilter = L"Картинки (*.bmp;*.jpg;*.gif;*.png)\0*.
else
ofn.lpstrFilter = L"BMP\0*.bmp\0GIF\0*.gif\0PNG\
ofn.nMaxFile = sizeof(cBuf);
ofn.lpstrFile = &cBuf[0];
if (bSave)
ofn.lpstrTitle = L"Сохранить файл";
else
ofn.lpstrTitle = L"Открыть файл";
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
if (bSave)
ofn.Flags |= OFN_OVERWRITEPROMPT;
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = L".\\";
if (bSave)
{
if (!GetSaveFileNameW(&ofn)) return false;
}
else
{
if (!GetOpenFileNameW(&ofn)) return false;
}
return true;
}
void UpdateMenuBmp(HBITMAP bmp, COLORREF clr)
{
HDC dcTmp = CreateCompatibleDC(dcMenuBmp);
SelectObject(dcTmp, bmp);
rcTmp.left = 0;
rcTmp.right = 16;
rcTmp.top = 0;
rcTmp.bottom = 16;
brush = CreateSolidBrush(clr);
FillRect(dcTmp, &rcTmp, brush);
FrameRect(dcTmp, &rcTmp, (HBRUSH)GetStockObject(BLACK_
DeleteObject(brush);
DeleteDC(dcTmp);
}
BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
dcItemPaint = GetDC(GetDlgItem(hDlg, IDC_STATICPAINT));
bmpBack = CreateCompatibleBitmap(
bmpUndo = CreateCompatibleBitmap(
bmpRedo = CreateCompatibleBitmap(
dcBack = CreateCompatibleDC(
dcUndo = CreateCompatibleDC(dcBack);
dcRedo = CreateCompatibleDC(dcBack);
SelectObject(dcBack, bmpBack);
SelectObject(dcUndo, bmpUndo);
SelectObject(dcRedo, bmpRedo);
rcTmp.left = 0;
rcTmp.right = CANVASWIDTH;
rcTmp.top = 0;
rcTmp.bottom = CANVASHEIGHT;
FillRect(dcBack, &rcTmp, (HBRUSH)GetStockObject(WHITE_
FillRect(dcUndo, &rcTmp, (HBRUSH)GetStockObject(WHITE_
FillRect(dcRedo, &rcTmp, (HBRUSH)GetStockObject(WHITE_
Gdiplus::GdiplusStartup(&
cFormat = 'g';
crBrushColor = 0x000000;
crBackColor = 0xFFFFFF;
mnuMain = GetMenu(hDlg);
CheckMenuItem(mnuMain, ID_40013, MF_CHECKED);
CheckMenuItem(mnuMain, ID_40018, MF_CHECKED);
CheckMenuItem(mnuMain, ID_40031, MF_CHECKED);
dc = GetDC(hDlg);
bmpForeMenu = CreateCompatibleBitmap(dc, 16, 16);
bmpBackMenu = CreateCompatibleBitmap(dc, 16, 16);
dcMenuBmp = CreateCompatibleDC(dc);
ModifyMenu(mnuMain, ID_40011, MF_BITMAP, ID_40011, (LPCSTR)bmpForeMenu);
ModifyMenu(mnuMain, ID_40100, MF_BITMAP, ID_40100, (LPCSTR)bmpBackMenu);
UpdateMenuBmp(bmpForeMenu, crBrushColor);
UpdateMenuBmp(bmpBackMenu, crBackColor);
sinfo.cbSize = sizeof(sinfo);
sinfo.fMask = SIF_ALL;
sinfo.nMin = 0;
sinfo.nPage = 10;
sinfo.nPos = 0;
sinfo.nTrackPos = 0;
GetClientRect(hDlg, &rcTmp);
sinfo.nMax = CANVASWIDTH - rcTmp.right;
SetScrollInfo(hDlg, SB_HORZ, &sinfo, TRUE);
sinfo.nMax = CANVASHEIGHT - rcTmp.bottom;
SetScrollInfo(hDlg, SB_VERT, &sinfo, TRUE);
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
ReleaseDC(GetDlgItem(hDlg, IDC_STATICPAINT), dcItemPaint);
ReleaseDC(hDlg, dc);
return (TRUE);
case WM_CLOSE:
Gdiplus::GdiplusShutdown(
CryptReleaseContext(hProv, 0);
DestroyWindow(hDlg);
ExitProcess(0);
return (TRUE);
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
SetCapture(hDlg);
bDraw = true;
x = LOWORD(lParam);
y = HIWORD(lParam);
x3 = x;
y3 = y;
bFore = message == WM_LBUTTONDOWN;
BitBlt(dcUndo, 0, 0, CANVASWIDTH, CANVASHEIGHT, dcBack, 0, 0, SRCCOPY);
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
if (!bDraw)
return FALSE;
ReleaseCapture();
bDraw = false;
x2 = (signed short)LOWORD(lParam);
y2 = (signed short)HIWORD(lParam);
pen = CreatePen(PS_SOLID, iPenWidth, bFore ? crBrushColor : crBackColor);
SelectObject(dcBack, pen);
SelectObject(dcBack, GetStockObject(HOLLOW_BRUSH));
switch (iTool)
{
case 0:
MoveToEx(dcBack, x + px, y + py, NULL);
LineTo(dcBack, x2 + px, y2 + py);
break;
case 1:
Rectangle(dcBack, x3 + px, y3 + py, x2 + px, y2 + py);
break;
case 2:
Ellipse(dcBack, x3 + px, y3 + py, x2 + px, y2 + py);
break;
case 3:
MoveToEx(dcBack, x3 + px, y3 + py, NULL);
LineTo(dcBack, x2 + px, y2 + py);
break;
case 4:
brush = CreateSolidBrush(bFore ? crBrushColor : crBackColor);
SelectObject(dcBack, brush);
ExtFloodFill(dcBack, x2 + px, y2 + py, GetPixel(dcBack, x2 + px, y2 + py), FLOODFILLSURFACE);
DeleteObject(brush);
break;
case 5:
Spray(iPenWidth);
break;
}
DeleteObject(pen);
InvalidateRect(GetDlgItem(
return TRUE;
case WM_MOUSEMOVE:
if (!bDraw)
break;
x2 = (signed short)LOWORD(lParam);
y2 = (signed short)HIWORD(lParam);
if (x2 > CANVASWIDTH - iPenWidth)
x2 = CANVASWIDTH - iPenWidth;
if (y2 > CANVASHEIGHT - iPenWidth)
y2 = CANVASHEIGHT - iPenWidth;
dc = GetDC(GetDlgItem(hDlg, IDC_STATICPAINT));
pen = CreatePen(PS_SOLID, iPenWidth, bFore ? crBrushColor : crBackColor);
SelectObject(dc, pen);
SelectObject(dcBack, pen);
switch (iTool)
{
case 0:
MoveToEx(dc, x, y, NULL);
LineTo(dc, x2, y2);
MoveToEx(dcBack, x + px, y + py, NULL);
LineTo(dcBack, x2 + px, y2 + py);
break;
case 1:
i = SetROP2(dc, R2_NOTXORPEN);
Rectangle(dc, x3, y3, x, y);
Rectangle(dc, x3, y3, x2, y2);
SetROP2(dc, i);
break;
case 2:
i = SetROP2(dc, R2_NOTXORPEN);
SelectObject(dc, GetStockObject(HOLLOW_BRUSH));
Ellipse(dc, x3, y3, x, y);
Ellipse(dc, x3, y3, x2, y2);
SetROP2(dc, i);
break;
case 3:
i = SetROP2(dc, R2_NOTXORPEN);
MoveToEx(dc, x3, y3, NULL);
LineTo(dc, x2, y2);
MoveToEx(dc, x3, y3, NULL);
LineTo(dc, x, y);
SetROP2(dc, i);
break;
case 5:
Spray(iPenWidth);
break;
}
x = x2;
y = y2;
DeleteObject(pen);
ReleaseDC(hDlg, dc);
break;
case WM_HSCROLL:
case WM_VSCROLL:
sinfo.fMask = SIF_POS | SIF_RANGE;
GetScrollInfo(hDlg, message == WM_HSCROLL ? SB_HORZ : SB_VERT, &sinfo);
switch(LOWORD(wParam))
{
case SB_PAGEUP:
i = sinfo.nPos - sinfo.nPage;
break;
case SB_PAGEDOWN:
i = sinfo.nPos + sinfo.nPage;
break;
case SB_LINEUP:
i = sinfo.nPos - 10;
break;
case SB_LINEDOWN:
i = sinfo.nPos + 10;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
i = HIWORD(wParam);
break;
}
i < 0 ? i = 0 : i = i;
i > sinfo.nMax ? i = sinfo.nMax : i = i;
sinfo.fMask = SIF_POS;
sinfo.nPos = i;
SetScrollInfo(hDlg, message == WM_HSCROLL ? SB_HORZ : SB_VERT, &sinfo, TRUE);
if (message == WM_HSCROLL)
px = i;
else
py = i;
InvalidateRect(GetDlgItem(
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_40005:
case ID_ACCELERATOR40055:
rcTmp.left = 0;
rcTmp.right = CANVASWIDTH;
rcTmp.top = 0;
rcTmp.bottom = CANVASHEIGHT;
FillRect(dcBack, &rcTmp, (HBRUSH)GetStockObject(WHITE_
InvalidateRect(GetDlgItem(
return TRUE;
case ID_40006:
case ID_ACCELERATOR40056:
if (!OpenSaveDlg(false, hDlg)) return FALSE;
rcTmp.left = 0;
rcTmp.right = CANVASWIDTH;
rcTmp.top = 0;
rcTmp.bottom = CANVASHEIGHT;
FillRect(dcBack, &rcTmp, (HBRUSH)GetStockObject(WHITE_
InvalidateRect(GetDlgItem(
bmpLoaded = Gdiplus::Bitmap::FromFile(ofn.
grBack = Gdiplus::Graphics::FromHDC(
grBack->DrawImage(bmpLoaded, 0, 0);
delete bmpLoaded;
delete grBack;
InvalidateRect(GetDlgItem(
return TRUE;
case ID_40007:
case ID_ACCELERATOR40057:
if (!OpenSaveDlg(true, hDlg)) return FALSE;
switch(ofn.nFilterIndex)
{
case 1:
if (cmpstr<wchar_t>(&ofn.
cpystr<wchar_t>(&ofn.
cFormat = 'b';
break;
case 2:
if (cmpstr<wchar_t>(&ofn.
cpystr<wchar_t>(&ofn.
cFormat = 'g';
break;
case 3:
if (cmpstr<wchar_t>(&ofn.
cpystr<wchar_t>(&ofn.
cFormat = 'p';
break;
}
DeleteFileW(ofn.lpstrFile);
bmpLoaded = Gdiplus::Bitmap::FromHBITMAP(
Gdiplus::GetImageEncodersSize(
Gdiplus::GetImageEncoders(i, j, &iciArray[0]);
i = 0;
while (iciArray[i].MimeType[6] != cFormat) i++;
bmpLoaded->Save(ofn.lpstrFile, &iciArray[i].Clsid, NULL);
delete bmpLoaded;
return TRUE;
case ID_40009:
case ID_ACCELERATOR40058:
SendMessage(hDlg, WM_CLOSE, 0, 0);
return TRUE;
case ID_40010:
MessageBox(hDlg, "MicroPaint\nВерсия 2.0", "О программе...", MB_ICONINFORMATION);
return TRUE;
case ID_40011:
case ID_40100:
ZeroMem((char*)&ccColor, sizeof(ccColor));
ccColor.lStructSize = sizeof(ccColor);
ccColor.hwndOwner = hDlg;