close

Вход

Забыли?

вход по аккаунту

?

Курсовой проект Svirin проверен

код для вставкиСкачать
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
Федеральное государственное бюджетное образовательное учреждение
высшего профессионального образования
Рязанский государственный радиотехнический университет
Кафедра АИТУ
Курсовой проект по дисциплине
"Объектно-ориентированное программирование"
на тему:
«РАЗРАБОТКА РАСТРОВОГО ГРАФИЧЕСКОГО РЕДАКТОРА»
Выполнил:
ст.гр. 031
Свирин В.Ю.
Саиф М.А.Х.
Проверил:
Стротов В.В.
Рязань 2012
Оглавление
1. Задание....................................................................................................
2. Разработка общего алгоритма построения графического
редактора......................................................................................................
3. Разработка графического интерфейса………………………………..
4. Разработка графического редактора. Алгоритмы работы и блоксхемы пользовательских функций:
4.1 Создание нового изображения......................................................
4.2 Удаление закрытых форм…..........................................................
4.3 Загрузка изображения....................................................................
4.4 Подстройка размеров формы........................................................
4.5 Сохранение изображения..............................................................
4.6 Поддержка буфера обмена............................................................
4.7 Поддержка буфера отката.............................................................
4.8 Изменение размеров изображения...............................................
4.9 Разработка инстуменов редактирования изображения: линия,
кисть, ластик, заливка, прямоугольник, эллипс, многоугольник......
4.10 Выбор цвета рисования и заливки..............................................
4.11 Установка индивидуальных параметров рисования.................
4.12 Разработка графического фильтра..............................................
4.13 Разработка справочной системы.................................................
5. Приложение............................................................................................
3
4
6
10
13
16
18
20
21
25
27
32
54
55
56
62
63
2
1. Задание
Разработать
растровый
графический
редактор,
отвечающий
представленным требованиям в соответствии с заданным вариантом.
Требования к редактору:
1. Создание нового изображения.
2. Загрузка и сохранение графических файлов в формате BMP.
3. Поддержка до 10 окон редактирования.
4. Поддержка буфера обмена.
5. Возможность «отката» последней операции редактирования.
6. Возможность изменения размеров изображения (с масштабированием и
без него).
7. Поддержка инструментов: линия, кисть, ластик, заливка, прямоугольник,
эллипс, многоугольник с индивидуальными параметрами (толщина,
количество углов).
8. Персональные курсоры в режиме редактирования для каждого
инструмента.
9. Возможность выбора цвета рисования и заливки.
10. Переключение между инструментами с помощью панели инструментов и
с помощью контекстного меню окна редактирования.
11. Отображение дополнительной информации в строке состояния формы с
редактируемым изображением (режим работы, текущие координаты
курсора и цвет пикселя под ним).
12. Реализация модального графического фильтра по апертуре «ромб» с
размерами от 3х3 до 9х9.
13. Наличие справочной системы по основным функциям редактора:
элементам интерфейса, инструментам и фильтру.
3
2. Разработка общего алгоритма построения графического редактора
Для соответствия графического редактора предъявленным требованиям
разработаем общий алгоритм его работы:
1. Если пользователю необходимо создать новое изображение, то создаем
новую форму для редактирования;
2. Если пользователю необходимо загрузить изображение, то загружаем
изображение;
3. Если изображение загружено или создано в данном графическом
редакторе, пользователь может:
a. изменить размеры изображения;
b. редактировать изображение, используя программные инструменты;
c. применить фильтр к изображению;
4. Если пользователю необходимо сохранить изображение:
a. Предлагается ввести имя файла изображения;
b. Изображение сохраняется в указанную пользователем директорию;
5. Пользователь может воспользоваться справочной системой
6. Если пользователю необходимо завершить работу с графическим
редактором, то осуществляется выход из программы, иначе алгоритм
повторяется.
Блок-схема, соответствующая разработанному алгоритму, представлена
рис.1.
на
4
Начало
Нет
Загрузка
изображени
я
Создание
новой
картинки
Да
Да
Редактирование
изображения
Нет
Изменение
размера
Да
С сохранением
пропорций или без
С масштабированием
или без
Нет
Фильтр
Да
Размер фильтра
Нет
Да
Сохранени
е
Ввод нового имени
Выход
Конец
Рисунок 1 - Блок-схема общего алгоритма работы графического редактора
5
3. Разработка графического интерфейса
Создание программы необходимо начать с создания главной формы FmMain,
которая появляется на экране при запуске программа. Для удобства работы с
редактором разделим форму на несколько блоков, выполняющие разные
функции. Для этого поместим на форму компонент Panel_main. На нём
поместим кнопки, по нажатию на которые пользователь может изменить
инструмент рисования. Для упрощения работы с редактором поместим на
каждую кнопку рисунок, соответствующий данному инструменту. Также на
панель поместим компонент Edit1 и UpDown1 , переключатель для
изменения толщины рисования многоугольника. А на форме разместим две
панели Panel2 и Panel3, для смены цвета линии и фона и триметки Labelc
текстом «Цвет», «Фон» и «Толщина».
Для вызова диалоговых окон поместим на форму компоненты
OpenPictureDialog_Main,SavePictereDialog_Main,
ColorDialog_main и MainMenu1. Последний компонент отвечает за
наличие главного меню в верхней части формы. Главное меню также поделим
на три блока: «Файл», «Изображение» и «Помощь». В первый поместим кнопки
«Новая картинка», «Загрузить картинку», «Сохранить картинку» и «Выход», во
втором разделесоздадим процедуру вызова справочной системы, по нажатию на
третий раздел поместим кнопки «Размер» и «Фильтр».
Для работы с изображением создадим форму FmImage, на которую поместим
компонент Image_pic, и строку состояния StatusBar_pic. На ней будет
отображаться информация о изображении: режим работы, координаты курсора
и цвет пикселя, находящегося под курсором. Данная форма необходима для
размещения растрового рисунка и работы с ним. Также создадим обработчик
вызова контекстного менюPopupMenu1, в которое добавим следующие пункты:
«Копировать» - копирование в буфер выделенного участка, «Вставить» копирование изображения из буфера вставки на форму, «Откатить» - возврат
предыдущего изображения и пункт «Инструменты», в который, добавим
пункты «Линия» - выбор инструмента линия, «Прямоугольник» - выбор
инструмента Прямоугольник, «Многоугольник» - выбор инструмента
Многоугольник, «Выделение» - выбор инструмента Выделение, «Кисть» выбор инструмента Кисть, «Заливка» - отрисовка фигур с заполнением,
(аналогично процедуре главного меню формы FmMain).
Для изменения настроек размеров окна создадим форму Form_Size, на
которую поместим два компонента Shir(TEdit),Vis(TEdit),Panel1
на
которой
поместим два переключателя Propor(TCheckBox),
Mastab(TCheckBox) и две кнопки Ok(TBitBtn),Cancel(TBitBtn).
Вызов данной формы будет производится кнопкой «Размер» главного меню
формы FmMain.
Для обращению к фильтру создадим форму FmFilter. На ней разместим
компоненты: Label1 –Label4 вспомогательные элементы, BitBtn1,BitBtn2,
6
ComboBox2 который будет определять значение коэффициента фильтра по
горизонтали и ComboBox1, который будет определять значение коэффициента
фильтра по вертикали. Вызов данной формы будем осуществлять кнопкой
«Фильтр» из меню главной формы. Главным назначением этой формы будет
назначение степени фильтрации изображения.
Окно главной формы графического редактора:
7
Окно формы редактирования:
Окно формы изменения размеров:
8
Окно формы фильтра:
9
4. Разработка графического редактора. Алгоритмы работы и блоксхемы пользовательских функций
4.1 Создание нового изображения
Для создания нового изображения в модуле Unit1 создана процедураобработчик нажатия на пункт меню N_nova («Новая картинка») формы
FmMain - TFmMain.N_newClick.
Алгоритм работы процедуры создания изображения следующий:
1) пункты меню N_save («Сохранить картинку»), N_size («Размер...») и
N_filt («Фильтр») становятся доступны:
// разрешить изменение размеров, использование фильтра, сохранение
N_size.Enabled:=true;
N_filt.Enabled:=true;
N_save.Enabled:=true;
2) для подсчета количества открытых форм проверяем массив состояний форм Flag_pic_mas. Если есть закрытые формы, запускается процедура удаления
закрытых форм remove_FmImage (эта процедура будет рассмотрена в пункте
3.2):
//Проверяем наличие закрытых форм. Если
закрытых форм
if Flag_pic_mas[0] then remove_FmImage;
есть,
запускаем
процедуру
удаления
3) для выполнения требования поддержки до 10 окон редактирования
проверяем количество открытых форм редактирования - N_form. Если число
форм для редактирования равно 10, выводится сообщение об ошибке:
//Ошибка, если количество форм уже равно 10
if (n_form)=10 then messagedlg('Оч много окон открыто',mtError,[mbOk],0)
Если форм меньше 10, то:
-увеличиваем количество форм:
Inc(N_form);
-создаем форму редактирования в массиве форм – form_image. Очищаем
изображение на ней (компонент Image_main):
application.CreateForm(TFmImage,form_image[n_form]); //процедура создания новой
формы
form_image[n_form].image_main.Canvas.Rectangle(0,0,form_image[n_form].image_main
.Width,form_image[n_form].image_main.Height);//очищаем и рисуем белый фон поля
редактирования
-используем свойство Tag для присвоения новой форме номера:
form_image[n_form].tag:=n_form;//присваиваем номер создаваемой форме
10
-создаем заголовок формы:
form_image[n_form].Caption:='New image';
-показываем созданную форму:
form_image[n_form].Show;
-поднимаем флаг наличия созданной формы в массиве FmImage_flag:
//ставим флаг наличия новой формы
FmImage_flag[n_form]:=true;
Блок-схема алгоритма создания нового изображения приведена на рис.2.
11
Начало
Пункты N_save, N_size и
N_filt доступны
нет
да
Есть
закрытые
формы
Форм =10
да
Удаление закрытых
форм
нет
Увеличение
количества форм
'Нельзя
открыть
больше 10
окон'
Создание новой
чистой формы
Нумерация
формы
Изменение
заголовка
Показать форму
Поднятие флага
наличия формы
1
1
Конец
Рисунок 2 - Блок-схема алгоритма работы процедуры создания нового
изображения
12
4.2 Удаление закрытых форм
Для
удаления
закрытых
форм,
создадим
RemoveKartinkaForms, созданную в модуле Unit_1.
процедуру
Алгоритм работы процедуры удаления закрытых форм следующий:
1) для того, чтобы отсортировать массив форм, разместив открытые формы
последовательно в начале массива, запускаем цикл для прохождения по
созданным формам:
//цикл перебирает все значения массива FmImage_flag, кроме последнего
for i:=1 to (n_form-1) do
-используем массив состояний форм для проверки, закрыта ли i-я форма:
//находим номер закрытой формы
if (FmImage_flag[i]=false) then
Если форма закрыта, то:
- проверяем флаг наличия закрытых форм. Если имеется открытая форма, то
записываем ее вместо закрытой и в массиве состояний форм устанавливаем
соответствующие флаги.
Фрагмент кода:
j:=i;
repeat
inc(j); //перебираем все элементы массива, следующие после элемента
закрытой формы
if FmImage_flag[j]=true then
begin
form_image[i]:=form_image[j]; //смещаем номер открытой формы на
место закрытой
FmImage_flag[i]:=FmImage_flag[j];// сортируем массив FmImage_flag
FmImage_flag[j]:=false;
form_image[i].Tag:=i;
col_form:=i;//число открытых форм определяется номером счетчика и
записывается в соответствующую переменную
break; //выходим из цикла, если сработает оператор if
end;
until (j=n_form);
-определяем число открытых форм, если была закрыта последняя форма
редактирования изображения. Фрагмент кода:
if (FmImage_flag[n_form]=false) then
begin
col_form:=0;
for i:=1 to (n_form-1) do
if FmImage_flag[i]=true then col_form:=col_form+1;
end;
2) обновляем количество открытых форм:
n_form:=col_form;
3) опускаем флаг наличия закрытых форм:
13
FmImage_flag[0]:=false;//помечаем, что не было факта закрытия окон
Блок-схема алгоритма удаления закрытых форм приведена на рис.3.
Начало
i:=0..( Kolvo form)
нет
Форма i
закрыта
да
j=i
k=i
Увеличить j
нет
Форма j не
закрыта
да
Form_picture[i]:=
Form_picture[j]
Форма i открыта
Форма j закрыта
Изменение
номера и
заголовка
k=i
нет
1
2
j=Kolvo
form
да
3
4
14
1
2
3
4
Kolvo form=k
Закрытых форм нет
Конец
Рисунок 3 - Блок-схема алгоритма удаления закрытых форм
15
4.3 Загрузка изображения
Для загрузки изображения в модуле Unit1 создана процедура-обработчик
нажатия на пункт меню N_load («Загрузить картинку») формы FmMain TFmMain.N_loadClick.
Алгоритм работы процедуры загрузки изображения следующий:
1) если диалог открытия выполнен:
if OpenPictureDialog_glav.Execute then begin
-для временного хранения загружаемого изображения создаем буферное
изображение:
BMP:=TBitmap.Create; //создается буферное изображение
-для подсчета количества открытых форм проверяем массив состояний форм FmImage_flag. Если есть закрытые формы, то запускается процедура
удаления закрытых форм remove_FmImage (рассмотрена в пункте 3.2):
//есть закрытые формы? Запускаем процедуру удаления закрытых форм
if FmImage_flag[0] then remove_FmImage;
-если количество открытых форм редактирования Kolvo_form равно нулю, то
необходимо создать новую форму. Для этого вызываем процедура
Form_Glav.N_nova.Click (рассмотрена в пункте 3.1):
if (n_form=0) then FmMain.N_new.Click;
-загружаем картинку в созданный ранее буфер:
//загружаем буферное изображение из файла
Bmp.LoadFromFile(OpenPictureDialog_Main.FileName);
-для подстройки размеров формы под загружаемую картинку используем
процедуру sizeformWH (будет рассмотрена в пункте 3.4):
//задаем размеры окна
sizeformWH(form_image[cur_Form],BMP.Width,BMP.Height);
-копируем изображение из буфера на форму:
//изображение загружается в поле Bitmap выбранного окна из буфера
form_image[cur_Form].Image_main.Picture.Bitmap:=BMP;
-изменяем заголовок формы на имя загруженного файла:
//изменяем заголовок окна
form_image[cur_Form].Caption:=OpenPictureDialog_Main.FileName;
-уничтожаем буфер изображения:
BMP.Destroy;
16
Блок-схема алгоритма загрузки изображения приведена на рис.4.
Начало
Выполнен
диалог
открытия
нет
да
Создание буфера
изображения
нет
да
Есть
закрытые
формы
нет
Кол-во
форм=0
Вызов процедуры
удаления закрытых форм
да
Вызов процедуры
создания новой формы
Загрузка изображения в буфер
Изменение размеров формы
Загрузка изображения из
буфера на форму
Изменение заголовка формы
Уничтожение буфера
Конец
Рисунок 4 - Блок-схема алгоритма работы процедуры загрузки изображения
17
4.4 Подстройка размеров формы
Рассмотрим процедуру подстройки размеров формы редактирования
razm_form, созданную в модуле Unit1. Она имеет три входных параметра:
p_form типа TFmImage, содержащий форму редактирования, размеры
которой надо подстроить; pic_w типа word содержит ширину
изображения; pic_h типа word содержит высоту изображения.
Алгоритм работы процедуры подстройки размеров изображения следующий:
1) для того, чтобы подстроить размер формы, рассчитываем его, учитывая
ширину и высоту загружаемого рисунка, а также высоту панели статуса:
//ширина загружаемого рисунка
w:=pic_w;
//высота загружаемого рисунка плюс высота строки состояния
h:=pic_h+p_form.StatusBar_main.Height;
2) устанавливаем размеры формы: минимальное значение ширины – 300,
максимальное – 1200; минимальное значение высоты – 100+высота панели
статуса, максимальное – 1004+высота панели статуса:
//изменяем значение высоты и ширины окна
if (pic_w<=300) then w:=300;
if (pic_h<=200) then h:=200+p_form.StatusBar_main.Height;
if (pic_w>=800) then w:=1200;
if (pic_h>=700) then h:=700+p_form.StatusBar_main.Height;
3) устанавливаем выравнивание компонента Image_main на форме FmImage
в зависимости от ширины и высоты изображения:
if (pic_w>=300) and (pic_h>=200) and (pic_w<=800) and (pic_h<=700) then
p_form.Image_main.Align:=alClient
else
p_form.Image_main.Align:=alTop;
4) устанавливаем новые значения высоты и ширины формы редактирования:
p_form.ClientWidth:=w;
p_form.ClientHeight:=h;
Блок-схема
рис.5.
алгоритма
загрузки
подстройки
размеров
приведена
на
Начало
Вычисление новых значений
ширины и высоты формы
нет
1
Ширина <=
300
да
2
18
2
1
Ширина=300
нет
Высота <=200
да
Высота=200+вы
сота StatusBar
нет
Ширина >= 800
да
Ширина=1200
нет
Высота >=700
да
Высота=700+
высота StatusBar
нет
Ширина>= 300 и
высота >= 300, и
ширина <=800, и
ширина <=700
да
Ориентация=alClient
Ориентация=alTop
Изменение
размеров формы
на новые
Конец
Рисунок 6 - Блок-схема алгоритма работы процедуры сохранения изображения
19
4.5 Сохранение изображения
Для сохранения изображения в модуле Unit1 создана процедура-обработчик
нажатия на пункт меню N_save («Сохранить картинку») формы FmMain TFmMain.N_saveClick.
Алгоритм работы процедуры сохранения изображения следующий:
1) если диалог сохранения выполнен:
//если выполнен диалог сохранения...
if SavePictureDialog_main.Execute then begin
-сохраняем изображение с текущей формы редактирования в файл, указанный в
диалоге сохранения:
form_image[cur_Form].Image_main.Picture.Bitmap.SaveToFile(savePictureDialo
g_Main.FileName);
-меняем заголовок текущей формы на имя файла:
form_image[cur_Form].Caption:=SavePictureDialog_Main.FileName;
Блок-схема алгоритма сохранения изображения в файл приведена на
рис.6.
Начало
нет
Выполнен
диалог
сохранения
да
Сохранение
изображения с
текущей формы
Изменение заголовка
Конец
Рисунок 6 - Блок-схема алгоритма работы процедуры сохранения изображения
20
4.6 Поддержка буфера обмена
Буфер обмена Copy_buffer инициализируется при создании формы
FmMain:
// инициализация буфера копирования
Copy_Buffer:=TBitmap.Create;
Чтобы использовать буфер обмена, необходимо выделить часть изображения
с помощью инструмента «Выделение». Рисование выделяющей рамки
производится в процедуре-обработчике движения мыши на компоненте
Image_main формы FmImage – TFmImage. Image_mainMouseMove
(подробно эта процедура будет рассмотрена в пункте 3.9).
Для копирования выделенного участка в модуле Unit2 создана процедураобработчик нажатия на пункт N3 («Копировать») контекстного меню формы
FmImage - TFmImage.N3Click.
Алгоритм работы процедуры копирования изображения следующий:
1) для определения, есть ли на данной форме выделение, проверяем флаг
выделения (Selected):
if Selected=1 then begin
Если выделение есть:
-для того, чтобы убрать выделение, стираем выделяющую рамку и опускаем
флаг выделения Selected:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
Image_main.Canvas.Rectangle(XBegin,YBegin,XEnd,YEnd);
Selected:=0;
- в зависимости от того, как пользователь выделил участок (слева направо или
справа налево, сверху вниз или снизу вверх), переназначаются координаты
выделения XBegin, YBegin, XEnd, YEnd. Для этого вводим
соответствующие проверки:
//
Проверка
координат
правого
//прямоугольника выделения
if XBegin>XEnd then
begin
xtemp:=xbegin;
xbegin:=XEnd;
XEnd:=xtemp;
end;
if yBegin>YEnd then
begin
ytemp:=ybegin;
ybegin:=YEnd;
YEnd:=ytemp;
нижнего
и
верхнего
левого
углов
21
end;
-изменяем размер буфера копирования под выделенный участок:
// изменяем размер буфера
Copy_Buffer.Width:= XS-XBegin+1;
Copy_Buffer.Height:=YS-YBegin+1;
-выделенный участок копируем в буфер:
// копирум выделенный кусок в буфер
Copy_Buffer.Canvas.CopyRect(Rect(0,0,XEnd-XBegin,YEnd-YBegin),
Image_main.Canvas, Rect(XBegin,YBegin,XEnd,YEnd));
Иначе (ничего не выделено), выводим сообщение об ошибке:
else
showmessage('Сначало надо создать выделение');
Блок-схема алгоритма копирования выделенного участка изображения в буфер
приведена на рис.7.
Начало
нет
'Сначало
надо
создать
выделение'
Есть
выделени
е
да
Стираем
выделение
Изменение размера
буфера копирования
нет
XBegin>XE
nd
да
xtemp:=xbegin;
xbegin:=XEnd;
XEnd:=xtemp;
нет
YBegin>YE
nd
да
ytemp:=ybegin;
ybegin:=YEnd;
YEnd:=ytemp;
1
2
22
1
2
Копирование
выделенного в буфер
Конец
Рисунок 7 - Блок-схема алгоритма работы
выделенного участка изображения в буфер обмена
процедуры
копирования
Для вставки содержимого буфера обмена на форму в модуле Unit2 создана
процедура-обработчик нажатия на пункт N4 («Вставить») контекстного меню
формы FmImage - TFmImage.N_4Click. Для того, чтобы изображение из
буфера помещалось в указанное место, используются координаты вызова
контекстного меню.
Алгоритм работы процедуры вставки изображения следующий:
1) для возможности отмены вставки перезаписываем буфер отката текущей
формы Back_buffer[Tag]:
// изменить размер буфера отката
Undo_Buffer[cur_form-1].Width :=Image_main.Picture.Bitmap.Width;
Undo_Buffer[cur_form-1].Height:=Image_main.Picture.Bitmap.Height;
// Перезаписать буфер отката
Undo_Buffer[cur_form-1].Canvas.CopyRect(Rect(0,0,Undo_Buffer[cur_form-1].Width,
Undo_Buffer[cur_form-1].Height), Image_main.Canvas,
Rect(0,0,Undo_Buffer[cur_form-1].Width,Undo_Buffer[cur_form-1].Height));
2) создаем временный буфер, необходимый для изменения размеров
изображения (рассмотрено далее в п.3)
BMP_temp:=TBitmap.Create;
3) выполняем проверку, выйдет ли вставляемый фрагмент за границы текущего
изображения. Если выйдет, то изменяем размеры текущего изображения на
разницу между шириной (высотой). Выполняем проверку и, при
необходимости изменяем, сначала для горизонтали:
if (XCM+XEnd-XBegin>=image_main.Width) then
begin
BMP_temp.Width:=XCM+XEnd-XBegin;
BMP_temp.Height:=form_image[Cur_form].Image_main.Height;
BMP_temp.Canvas.Pen.Color:=clWhite;
BMP_temp.Canvas.Brush.Color:=clWhite;
BMP_temp.Canvas.Rectangle(0,0,XCM+XEndXBegin,form_image[Cur_form].Image_main.Height);
BMP_temp.Canvas.Draw(0,0,form_image[Cur_Form].Image_main.Picture.Bitmap);
23
form_image[Cur_Form].Image_main.Picture.Bitmap:=BMP_temp;
razm_form(form_image[Cur_Form],XCM+XEndXBegin,form_image[Cur_form].Image_main.Height)
end;
для вертикали:
if (YCM+YEnd-YBegin>=image_main.Height) then
begin
BMP_temp.Width:=form_image[Cur_form].Image_main.Width;
BMP_temp.Height:=YCM+YEnd-YBegin;
BMP_temp.Canvas.Pen.Color:=clWhite;
BMP_temp.Canvas.Brush.Color:=clWhite;
BMP_temp.Canvas.Rectangle(0,0,form_image[Cur_form].Image_main.Width,YCM+YEndYBegin);
BMP_temp.Canvas.Draw(0,0,form_image[Cur_Form].Image_main.Picture.Bitmap);
form_image[Cur_Form].Image_main.Picture.Bitmap:=BMP_temp;
razm_form(form_image[Cur_Form],form_image[Cur_form].Image_main.Width,YCM+YEndYBegin)
4) Уничтожаем временный буфер
BMP_temp.Destroy;
5) копируем содержимое буфера обмена на форму редактирования:
// копирум выделенный кусок из буфера в точку вызова контекстного меню
Image_main.Canvas.CopyRect( Rect(XCM,YCM,XCM+XEnd-XBegin,
YCM+YEnd-YBegin),Copy_Buffer.Canvas, Rect(0,0,XEnd-XBegin,YEnd-YBegin) );
Блок-схема алгоритма вставки изображения из буфера на форму приведена на
рис.8.
Начало
нет
Есть
выделение
да
Убираем
выделение
Перезапись буфера отката
Копирование
содержимого буфера на
форму
Конец
Рисунок 8 - Блок-схема алгоритма работы процедуры вставки содержимого
буфера обмена на форму
24
4.7 Поддержка буфера отката
Имеется индивидуальный буфер отката Undo_buffer для каждой формы
редактирования, который инициализируется при создании этой формы:
Undo_Buffer[Cur_Form]:= TBitmap.Create;//инициализация буфера отката;
Перед совершением над текущим изображением какой-либо операции
редактирования происходит перезапись буфера отката по следующему
алгоритму:
1) измененяем размеры буфера отката под текущее изображение:
// изменить размер буфера отката
Undo_Buffer[cur_form-1].Width :=Image_main.Picture.Bitmap.Width;
Undo_Buffer[cur_form-1].Height:=Image_main.Picture.Bitmap.Height;
2) копируем текущее изображения в буфер отката:
// Перезаписать буфер отката
Undo_Buffer[cur_form-1].Canvas.CopyRect(Rect(0,0,Undo_Buffer[cur_form-1].Width,
Undo_Buffer[cur_form-1].Height), Image_main.Canvas,
Rect(0,0,Undo_Buffer[cur_form-1].Width,Undo_Buffer[cur_form-1].Height));
Блок-схема алгоритма перезаписи буфера отката приведена на рис.9.
Начало
Изменение размеров
буфера отката
Копирование
изображения в буфер
отката
Конец
Рисунок 9 - Блок-схема алгоритма перезаписи буфера отката
Для отмены последнего действия в модуле Unit2 создана процедураобработчик нажатия на пункт N_back («Откатить») контекстного меню формы
Form_Kartinka - TForm_Kartinka.N_backClick.
Алгоритм работы отката последнего действия следующий:
1) создаем промежуточный буфер, где сохраняем текущее содержимое буфера
отката в него (необходимо для отмены отката):
//создаем буфер отмены отмены
Undo_undo_buffer[cur_form-1]:=TBitmap.Create;
//перезаписываем текущее содержимое буфера отката
Undo_undo_buffer[cur_form-1].Width:=Undo_buffer[cur_form-1].Width;
Undo_undo_buffer[cur_form-1].Height:=Undo_buffer[cur_form-1].Height;
25
Undo_undo_buffer[cur_form-1].Canvas.CopyRect
(Rect(0,0,Undo_undo_buffer[cur_form-1].Width,Undo_undo_buffer[cur_form-1].
Height),Undo_buffer[cur_form-1].Canvas,
Rect(0,0,Undo_buffer[cur_form-1].Width,Undo_buffer[cur_form-1].Height));
2) для подстройки размера формы под содержимое промежуточного буфера
вызываем процедуру razm_form:
//подстраиваем размеры формы
razm_form(form_image[Cur_Form],Undo_undo_buffer[cur_form-1].
Width,Undo_undo_buffer[cur_form-1].Height);
3) для возможности последующей отмены отката перезаписываем буфер отката:
// изменить размер буфера отката
Undo_Buffer[cur_form-1].Width :=Image_main.Picture.Bitmap.Width;
Undo_Buffer[cur_form-1].Height:=Image_main.Picture.Bitmap.Height;
// Перезаписать буфер отката
Undo_Buffer[cur_form-1].Canvas.CopyRect(Rect(0,0,Undo_Buffer[cur_form-1].Width,
Undo_Buffer[cur_form-1].Height), Image_main.Canvas,
Rect(0,0,Undo_Buffer[cur_form-1].Width, Undo_Buffer[cur_form-1].Height));
4) вставляем все изображение из промежуточного буфера:
//вставляем все изображение из промежуточного буфера
Image_main.Picture.Bitmap:=Undo_undo_buffer[cur_form-1];
Блок-схема алгоритма отмены последнего действия редактирования приведена
на
рис.10.
Начало
Создание
промежуточного буфера,
запись в него
Перезапись буфера отката
Замена изображения на
содержимое
промежуточного буфера
Подстройка размеров
формы
Конец
Рисунок 10 - Блок-схема алгоритма работы процедуры отката последней
операции редактирования
26
4.8 Изменение размеров изображения
Для возможности изменения размеров изображения создан отдельный модуль
Unit_size c формой Form_size, на которой можно ввести требуемые
ширину и высоту. Имеется возможность сохранения пропорций и
масштабирования.
Для изменения размеров изображения в модуле Unit_size создана
процедура-обработчик нажатия на кнопку BitBtn1 («ОК») формы
Form_size - TForm_size. BitBtn1Click.
Алгоритм работы процедуры изменения размеров следующий:
1) для возможности отмены операции изменения размеров перезаписываем
буфер отката текущей формы Undo_Buffer[Cur_Form-1]:
// изменить размер буфера отката
Undo_Buffer[Cur_Form-1].Width:= form_image[Cur_Form].
Image_main.Picture.Bitmap.Width;
Undo_Buffer[Cur_Form-1].Height:= form_image[Cur_Form].
Image_main.Picture.Bitmap.Height;
// Перезаписать буфер отката
Undo_Buffer[Cur_Form-1].Canvas.CopyRect(Rect(0,0,Undo_Buffer[Cur_Form-1].
Width,Undo_Buffer[Cur_Form-1].Height),form_image[Cur_Form].
Image_main.Canvas,Rect(0,0,Undo_Buffer[Cur_Form-1].Width,
Undo_Buffer[Cur_Form-1].Height));
2) создаем буфер, используемый для изменения размеров:
// создаём буфер
BMP:=TBitmap.Create;
3) считываем значения ширины и высоты изображения в переменные w и h
соответственно:
// считываем ширину и высоту
w:=StrToInt(Edit_w.Text);
h:=StrToInt(Edit_H.Text);
4) изменяем размер временного буфера, необходимого для хранения
изображения с новыми размерами:
// изменяем размер буфера
BMP.Width :=w;
BMP.Height:=h
5) для возможности масштабирования, проверяем, установлен ли компонент
CheckBox2:
// Если масштабирования нет
if CheckBox2.Checked = false then
Просто копируем изображение с формы в буфер:
//просто копируем в буфер изображение из формы редактирования
BMP.Canvas.Draw(0,0,form_image[Cur_Form].Image_main.Picture.Bitmap)
27
Если масштабирование выбрано, то копируем в буфер масштабированное
изображение с формы:
else
//растягиваем или сжимаем изображение до размеров буфера
BMP.Canvas.StretchDraw(rect(0,0,w,h),form_image[Cur_form].Image_main.
Picture.Bitmap);
6) подстраиваем размеры формы под
помощью процедуры razm_form:
размеры промежуточного буфера, с
// Подстраиваем размеры формы
razm_form(form_image[Cur_Form],w,h););
7) заменяем изображение содержимым временного буфера:
// копируем изображение из буфера на форму
form_image[Cur_Form].Image_main.Picture.Bitmap:=BMP;
8) уничтожаем временный буфер:
// уничтожаем буфер
BMP.Destroy;
9) закрываем форму изменения размеров Form_size:
// закрываем окно изменения размеров
Form_size.Close;
Блок-схема алгоритма изменения размеров изображения приведена на рис.11.
Начало
Перезапись буфера отката
Создание временного
буфера
Считывание значений
ширины и высоты
Изменение размера
промежуточного буфера
1
28
1
да
не
т
Масштаб
ировать
копируем в буфер
масштабированное
изображение
копируем изображение с
формы в буфер
Подстройка размеров
формы
Замена изображения
содержимым
промежуточного буфера
уничтожаем временный
буфер
Закрытие формы
Конец
Рисунок 11 - Блок-схема алгоритма работы процедуры изменения размеров
Для реализации возможности сохранения пропорций изображения в модуле
Unit_size
созданы
процедуры-обработчики
изменения
полей
редактирования Edit_Width («Ширина») и Edit_Height («Высота»)
формы:
Form_size
TForm_size.Edit_WidthChange
и
TForm_size.Edit_HeightChange соответственно.
Алгоритм работы процедур сохранения пропорций аналогичен. Рассмотрим
их работу на примере процедуры TForm_Razmer. Edit_WidthChange:
1) проверяем, выбрано ли поле Edit_ Width:
if Edit_Width.Focused then
29
Если да, то:
2) проверяем, введено ли значение ширины в поле Edit_Width:
if Edit_width.Text<>'' then
Если да, то:
3) проверяем, надо ли сохранять пропорции, используя компонент CheckBox1:
if CheckBox1.Checked then begin
Если да, то:
-рассчитываем новые значение высоты, используя вводимое значение
ширины и их изначальное соотношение:
// считываем ширину
Width:=StrToInt(Edit_Width.Text);
// вычисляем высоту
Height:=round(Width/propor);
-записываем в поле Edit_Height новое значение высоты:
// изменяем значение поля высоты
Edit_Height.Text:=IntToStr(Height);
Блок-схема алгоритма изменения поля «Ширина» приведена на рис.12.
Начало
нет
Поле в
фокусе
да
нет
Значение
введено
да
нет
1
Сохранят
ь
пропорци
и да
2
30
1
2
Расчет значения высоты
Запись значения в поле
высоты
Конец
Рисунок 12 - Блок-схема алгоритма работы процедуры изменения поля
«Ширина»
31
4.9 Разработка инстуменов редактирования изображения: линия, кисть,
ластик, заливка, прямоугольник, эллипс, многоугольник
Для реализации возможности использования данных инструментов
редактирования, создано три процедуры-обработчика событий, происходящих
на компоненте Image_main, который содержит изображение, формы
FmImage:
1. нажатие мыши ̶TFmImage.Image_mainMouseDown;
2. движение ̶ TFmImage.Image_mainMouseDownMove;
3. отпускание мыши ̶ TFmImage.Image_mainMouseDownUp.
Рассмотрим процедуру Image_mainMouseDown. Алгоритм работы этой
процедуры следующий:
1) проверяем, нажата ли левая кнопка мыши:
// если нажата левая кнопка мыши
if (Button=mbLeft) then
2) для возможности отката перезаписываем буфер:
// изменить размер буфера отката
Undo_Buffer[cur_form-1].Width :=Image_main.Picture.Bitmap.Width;
Undo_Buffer[cur_form-1].Height:=Image_main.Picture.Bitmap.Height;
// Перезаписать буфер отката
Undo_Buffer[cur_form-1].Canvas.CopyRect(Rect(0,0,Undo_Buffer[cur_form-1].Width,
Undo_Buffer[cur_form-1].Height),
Image_main.Canvas,
Rect(0,0,Undo_Buffer[cur_form-1].Width,
Undo_Buffer[cur_form-1].Height));
3) проверяем, есть ли выделение:
if Selected = 1 then begin
Если есть, стираем его:
// стираем его
// цвет линии - синий
Image_main.Canvas.Pen.Color:=clBlue;
// вид линии - штрихпунктирный
Image_main.Canvas.Pen.Style:=psDashDot;
// метод отрисовки линии - NotXor
Image_main.Canvas.Pen.Mode:=pmNotXor;
// толщина - 1 пиксел
Image_main.Canvas.Pen.Width:=1;
// кисть - прозрачная
Image_main.Canvas.Brush.Style:=bsClear;
// нарисовать новый прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,XEnd,YEnd);
// Снимаем флаг
Selected:=0;
4) сохраняем координаты нажатия мыши и устанавливаем флаг рисования:
// сохранение координат точки нажатия кнопки мыши
Xbegin:=X;
32
Ybegin:=Y;
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
// поднятие флага рисования
risovanae:=true;
5) проверяем, выбран ли инструмент «Заливка»:
if FmMain.SpeedButton_so.Down then
Если выбран:
-для отображения действия в StatusBar выводим «Заливка»:
StatusBar_main.Panels[0].Text:='Звливка';
-сохраняем цвет пикселя под мышью:
// запоминаем цвет точки под пикселом
Color_to_fill:=Image_main.Canvas.Pixels[X,Y];
-закрашиваем область этого цвета цветом фона:
// Закрашиваем эту область цветом фона
Image_main.Canvas.Brush.Color:=back_col;
Image_main.Canvas.FloodFill(X,Y,Color_to_fill,fsSurface);
Блок-схема алгоритма работы процедуры нажатия кнопки мыши приведена на
рис.13.
Начало
нет
Нажата левая
кнопка мыши
нет
Есть
выделение
да
Удаление
выделения
нет
Выделение
не выбрано
да
Перезапись
буфера
отката
1
2
33
2
1
Сохранение координат
нажатия и установка флага
рисования
нет
Выбрана
Заливка
да
Вывод
«Заливка» в
StatusBar
Сохраняем
цвет пикселя
Закрашиваем
область
Конец
Рисунок 13 - Блок-схема алгоритма работы процедуры нажатия кнопки мыши
Рассмотрим процедуру Image_mainMouseMove. Алгоритм работы этой
процедуры следующий:
1) для отображения действия, текущих координат и цвета под мышкой
заполняем панели StatusBar:
-в первую панель выводим «Обзор»:
// Вывод текста в первую панель
StatusBar_main.Panels[0].Text:='Обзор';
-во вторую панель выводим текущие координаты курсора:
// Вывод координат курсора во вторую панель
StatusBar_main.Panels[1].Text:='X='+InttoStr(X)+',Y='+InttoStr(Y);
-в третью панель выводим цвет пикселя под курсором:
34
// Вывод цвета точки под курсором в третью панель
c:=Image_main.Canvas.Pixels[X,Y];
StatusBar_main.Panels[2].Text:='Color='+ColorToString(C);
b) проверяем, поднят ли флаг рисования:
// Если поднят флаг рисования
if risovanae then //если поднят флаг рисования
Если поднят:
- проверяем, выбран ли инструмент «Линия»:
// Если нажата кнопка "ЛИНИЯ"
if FmMain.SpeedButton_Line.Down then
Если выбрана линия:
-устанавливаем атрибуты рисования:
//Устанавливаем атрибуты рисования
Image_main.Canvas.Pen.Color:=clBlack;
Image_main.Canvas.Pen.Style:=psDash;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
-стираем предыдущую линию:
// Cтереть предыдущую линию
Image_main.Canvas.MoveTo(XBegin,YBegin);
Image_main.Canvas.LineTo(X1,Y1);
-рисуем новую:
// нарисовать новую линию
Image_main.Canvas.MoveTo(XBegin,YBegin);
Image_main.Canvas.LineTo(X,Y);
-сохраняем координаты мыши:
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
-для отображения действия в StatusBar выводим «Рисование линии»:
StatusBar_main.Panels[0].Text:='Рисование линии';
- иначе проверяем, выбран ли инструмент «Кисть»:
else if FmMain.SpeedButton_Brush.Down then begin
Если выбрана кисть:
-если толщина равна 1-у пикселю, то рисуем точку в месте нахождения мыши:
if BrushW=1 then Image_main.Canvas.Pixels[X,Y]:=Front_col
35
-иначе устанавливаем атрибуты рисования и рисуем круг в месте нахождения
мыши:
else // если толщина больше 1 - рисуем окружность
begin
// устанавливаем атрибуты
Image_main.Canvas.Pen.Color:=Front_col;
image_main.Canvas.Pen.Width:=0;
Image_main.Canvas.Brush.Color:=Front_col;
d:=BrushW div 2;
Image_main.Canvas.Ellipse(X-d,Y-d,X-d+BrushW,Y-d+BrushW);
end;
-для отображения действия в StatusBar выводим «Рисование кистью»:
StatusBar_main.Panels[0].Text:='Рисование кистью';
- иначе проверяем, выбран ли инструмент «Ластик»:
else if FmMain.SpeedButton_Eraser.Down then
Если выбран ластик:
-если толщина равна 1, то рисуем точку в месте нахождения мыши:
if EraserW=1 then Image_main.Canvas.Pixels[X,Y]:=back_col
-иначе устанавливаем атрибуты рисования и рисуем квадрат в месте
нахождения мыши:
else // если толщина >1 - рисуем прямоугольник
begin
// устанавливаем цвета для окружности
Image_main.Canvas.Pen.Color:=back_col;
image_main.Canvas.Pen.Width:=0;
Image_main.Canvas.Brush.Color:=back_col;
d:=EraserW div 2;
Image_main.Canvas.Rectangle(X-d,Y-d,X-d+EraserW,Y-d+EraserW);
end;
-для отображения действия в StatusBar выводим «Стирание»:
StatusBar_main.Panels[0].Text:='Стирание';
- иначе проверяем, выбран ли инструмент «Прямоугольник»:
else if FmMain.SpeedButton_pr.Down then begin
Если выбран прямоугольник:
-устанавливаем атрибуты рисования:
// нет заливки
Image_main.Canvas.Brush.style:=bsClear;
// цвет линии - чёрный
Image_main.Canvas.Pen.Color:=clBlack;
// вид линии - пунктирный
Image_main.Canvas.Pen.Style:=psDash;
// метод отрисовки линии - NotXor
36
Image_main.Canvas.Pen.Mode:=pmNotXor;
// толщина - 1 пиксел
Image_main.Canvas.Pen.Width:=1;
// кисть - прозрачная
Image_main.Canvas.Brush.Style:=bsClear;
-стираем предыдущий прямоугольник:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
-рисуем новый:
// нарисовать новый прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X,Y);
-сохраняем координаты мыши:
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
-для отображения
прямоугольника»:
действия
в
StatusBar
выводим
«Рисование
StatusBar_main.Panels[0].Text:='Рисование прямоугольника';
- иначе проверяем, выбран ли инструмент «Эллипс»:
else if FmMain.SpeedButton_kr.Down then begin
Если выбран эллипс:
-устанавливаем атрибуты рисования:
// нет заливки
Image_main.Canvas.Brush.style:=bsClear;
// цвет линии - чёрный
Image_main.Canvas.Pen.Color:=clBlack;
// вид линии - пунктирный
Image_main.Canvas.Pen.Style:=psDash;
// метод отрисовки линии - NotXor
Image_main.Canvas.Pen.Mode:=pmNotXor;
// толщина - 1 пиксел
Image_main.Canvas.Pen.Width:=1;
// кисть - прозрачная
Image_main.Canvas.Brush.Style:=bsClear;
-стираем предыдущий эллипс:
// Cтереть предыдущий эллипс
Image_main.Canvas.ellipse(XBegin,YBegin,X1,Y1);
-рисуем новый:
// нарисовать новый эллипс
Image_main.Canvas.ellipse(XBegin,YBegin,X,Y);
37
-сохраняем координаты мыши:
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
-для отображения действия в StatusBar выводим «Рисование эллипса»:
StatusBar_main.Panels[0].Text:='Рисование эллипса';
- иначе проверяем выбран ли инструмент «Многоугольник»:
else if FmMain.SpeedButton_mn.Down then begin
Если выбран многоугольник:
-устанавливаем атрибуты рисования:
Image_main.Canvas.Brush.Style:=bsClear; //кисть - прозрачная
Image_main.Canvas.Pen.Width:=1; //толщина по умолчанию
Image_main.Canvas.Brush.style:=bsClear; // нет заливки
// цвет линии - чёрный
Image_main.Canvas.Pen.Color:=clBlack;
// вид линии - пунктирный
Image_main.Canvas.Pen.Style:=psDash;
// метод отрисовки линии - NotXor
Image_main.Canvas.Pen.Mode:=pmNotXor;
// толщина - 1 пиксел
Image_main.Canvas.Pen.Width:=1;
// кисть - прозрачная
Image_main.Canvas.Brush.Style:=bsClear;
-рисуем многоугольник, используя только часть массива
Image_main.Canvas.Polygon(Slice(kol, kol_u));
- записываем значение SpinEdit2 в переменную kol_u
kol_u:=FmMain.SpinEdit2.Value;
-для формирования массива kol новых координат (X и Y) вершин запускаем
цикл от 1 до kol_u:
for d:=1 to kol_u do
begin
kol[d].X:=((X+XBegin) div 2)+round (((X-XBegin) div 2)*
cos(2*3.1415926*d/kol_u));
kol[d].Y:=((Y+YBegin) div 2)-round (((Y-YBegin) div 2)*
sin(2*3.1415926*d/kol_u));
end;
-рисуем новый многоугольник:
image_main.Canvas.Polygon(Slice(kol, kol_u));
-для отображения действия в StatusBar выводим «Рисование
многоугольника»:
38
StatusBar_main.Panels[0].Text:='Рисование многоугольника';
- иначе проверяем выбран ли инструмент «Выделение»:
else if FmMain.SpeedButton_sel.Down then begin
Если выбрано выделение, выполняем ряд проверок, чтобы выделение не
выходило за границы окна редактирования:
- если координаты правого нижнего угла выделения не выходят за границы
изображения
if ((X<=Image_main.Width)
(Y>=0)) then begin
and
(Y<=Image_main.Height)
and
(x>=0)
and
- устанавливаем атрибуты рисования рамки выделения:
// цвет линии - синий
Image_main.Canvas.Pen.Color:=clBlue;
// вид линии - штрихпунктирный
Image_main.Canvas.Pen.Style:=psDashDot;
// метод отрисовки линии - NotXor
Image_main.Canvas.Pen.Mode:=pmNotXor;
// толщина - 1 пиксел
Image_main.Canvas.Pen.Width:=1;
// кисть - прозрачная
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
// нарисовать новый прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X,Y);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
XEnd:=X;
YEnd:=Y;
- если координата Х больше или равна величине ширины изображения:
if ((X>=Image_main.Width))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
39
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,image_main.Width,Y);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=image_main.Width;
Y1:=Y;
XEnd:=image_main.Width;
YEnd:=Y;
- если координата У больше или равна величине высоты изображения:
if ((Y>=Image_main.Height))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
IImage_main.Canvas.Rectangle(XBegin,YBegin,X,Image_main.Height);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=X;
Y1:=Image_main.Height;
XEnd:=X;
YEnd:=Image_main.Height;
- если координата У больше или равна величине высоты изображения:
if ((Y>=Image_main.Height))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
40
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
IImage_main.Canvas.Rectangle(XBegin,YBegin,X,Image_main.Height);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=X;
Y1:=Image_main.Height;
XEnd:=X;
YEnd:=Image_main.Height;
- если координата У больше или равна величине высоты изображения и
координата Х больше или равна величине ширины изображения:
if ((Y>=Image_main.Height) and (X>=Image_main.Width))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,Image_main.Width,Image_main.Height);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=Image_main.Width;
Y1:=Image_main.Height;
XEnd:=Image_main.Width;
YEnd:=Image_main.Height;
- если координата У меньше или равна «0» и координата Х больше или равна
величине ширины изображения:
if ((Y<=0) and (X>=Image_main.Width))then begin
41
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,Image_main.Width,0);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=Image_main.Width;
Y1:=0;
XEnd:=Image_main.Width;
YEnd:=0;
- если координата У меньше или равна «0» и координата Х меньше величины
ширины изображения:
if ((Y<=0) and (X<Image_main.Width))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,X,0);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=X;
Y1:=0;
XEnd:=X;
YEnd:=0;
- если координата У меньше или равна «0» и координата Х меньше или равна
«0»:
42
if ((Y<=0) and (X<=0))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,0,0);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=0;
Y1:=0;
XEnd:=0;
YEnd:=0;
- если координата У меньше или равна «0» и координата X больше «0»:
if ((Y<=0) and (X>0))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,X,0);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=X;
Y1:=0;
XEnd:=X;
YEnd:=0;
- если координата У больше «0» и координата X меньше или равна «0»:
43
if ((Y>0) and (X<=0))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,0,Y);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=0;
Y1:=Y;
XEnd:=0;
YEnd:=Y;
- если координата У больше или равна величине высоты изображения и
координата X меньше «0»:
if ((Y>=image_main.Height) and (X<0))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,0,image_main.Height);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=0;
Y1:=image_main.Height;
XEnd:=0;
YEnd:=image_main.Height;
44
- если координата У меньше или равна «0» и координата X больше или равна
величине ширины изображения:
if ((Y<=0) and (X>=image_main.Width))then begin
- устанавливаем атрибуты рисования рамки выделения:
Image_main.Canvas.Pen.Color:=clBlue;
Image_main.Canvas.Pen.Style:=psDashDot;
Image_main.Canvas.Pen.Mode:=pmNotXor;
Image_main.Canvas.Pen.Width:=1;
Image_main.Canvas.Brush.Style:=bsClear;
- стираем предыдущую рамку выделения:
// Cтереть предыдущий прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
- рисуем новую рамку выделения:
Image_main.Canvas.Rectangle(XBegin,YBegin,image_main.Width,0);
-сохраняем координаты мыши и координаты правого нижнего угла выделения:
X1:=image_main.Width;
Y1:=0;
XEnd:=image_main.Width;
YEnd:=0;
-для отображения действия в StatusBar выводим «Выделение»:
StatusBar_main.Panels[0].Text:='Выделение';
-поднимаем флаг выделения:
Selected:=1;
Блок-схема алгоритма работы процедуры движения мыши приведена на рис.14.
Начало
нет
нет
1
2
да
Поднят флаг
рисования
Выбрана
Линия
да
3
45
1
2
3
Устанавливаем
атрибуты
рисования
Стираем
предыдущую
линию
Рисуем новую
Сохраняем
координаты
мыши
Вывод «Рисование
линии» в StatusBar
нет
да
Выбрана
Кисть
нет
Устанавливаем
атрибуты
Толщина=
1
да
Рисуем точку
Рисуем круг
Вывод «Рисование
кистью» в StatusBar
нет
да
Выбран
Ластик
нет
Толщина=
1
Устанавливаем
атрибуты
да
Рисуем точку
Рисуем квадрат
1
2
3
4
46
1
2
4
3
Вывод «Стирание» в
StatusBar
нет
Выбран
Прямоугольник
да
Устанавливаем
атрибуты
Стираем
предыдущий
Рисуем новый
Сохраняем
координаты
Вывод
«Рисование
прямоугольника
» в StatusBar_pic
нет
Выбран
Эллипс
да
Устанавливаем
атрибуты
Стираем
предыдущий
Рисуем новый
Сохраняем
координаты
Вывод «Рисование
эллипса» в StatusBar
1
2
3
47
1
2
нет
Выбран
Многоугольник
3
да
Устанавливаем
атрибуты
Стираем
предыдущий
j:=1..nCorners
Расчет PArray [i].X
Расчет PArray [i].Y
Рисуем новый
Сохраняем вершины
Вывод «Рисование
многоугольника» в
StatusBar
нет
Выбрано
Выделение
да
Устанавливаем
атрибуты
Стираем рамку
1
2
3
4
48
1
2
3
4
Рисуем новую
Сохраняем
координаты
Вывод «Выделение»
в StatusBar_pic
Устанавливаем флаг
выделения
Конец
Рисунок 14 - Блок-схема алгоритма работы процедуры движения мыши
Рассмотрим процедуру TFmImage.Image_mainMouseUp. Алгоритм
работы этой процедуры следующий:
1) проверяем, нажата ли левая кнопка мыши:
// если нажата левая кнопка мыши
if (Button=mbLeft) then begin
Если нажата левая кнопка мыши:
- проверяем, выбран ли инструмент «Линия»:
if FmMain.SpeedButton_Line.Down then begin
Выбрана линия:
-устанавливаем атрибуты рисования:
// нарисовать линию тем цветом, который выбран
Image_main.Canvas.Pen.Color:=Front_col;
Image_main.Canvas.Pen.Mode :=pmCopy;
Image_main.Canvas.Pen.Style:=psSolid;
Image_main.Canvas.Pen.Width:=LineW;
-рисуем линию:
Image_main.Canvas.MoveTo(Xbegin,Ybegin);
Image_main.Canvas.LineTo(X,Y);
- иначе проверяем, выбран ли инструмент «Прямоугольник»:
49
else if FmMain.SpeedButton_pr.Down then begin
Выбран прямоугольник:
-устанавливаем атрибуты рисования:
Image_main.Canvas.Pen.Width:=RectW;
Image_main.Canvas.pen.mode:=pmcopy;
Image_main.Canvas.Pen.Style:=psSolid;
Image_main.Canvas.Pen.Color:=Front_col;
-для реализации заполнения проверяем компонент CheckBox1. Если выбрано,
то устанавливаем стиль кисти bsSolid и цвет фона как цвет заполнения.
Иначе стиль кисти – bsClear:
// Проверка флага "заливка"
if FmMain.CheckBox1.Checked then
begin
Image_main.Canvas.Brush.style:=bsSolid; // есть заливка
Image_main.Canvas.Brush.Color:=back_col
end
else
Image_main.Canvas.Brush.style:=bsClear; // нет заливки
-рисуем прямоугольник:
//рисуем прямоугольник
Image_main.Canvas.Rectangle(XBegin,YBegin,X,Y);
- иначе проверяем, выбран ли инструмент «Эллипс»:
else if FmMain.SpeedButton_kr.Down then begin
Выбран эллипс:
-устанавливаем атрибуты рисования:
Image_main.Canvas.Pen.Width:=EllipseW;
Image_main.Canvas.pen.mode:=pmcopy;
Image_main.Canvas.Pen.Style:=psSolid;
Image_main.Canvas.Pen.Color:=Front_col;
-для реализации заполнения проверяем компонент CheckBox1. Если выбрано,
то устанавливаем стиль кисти bsSolid и цвет фона как цвет заполнения.
Иначе стиль кисти – bsClear:
// Проверка флага "заливка"
if FmMain.CheckBox1.Checked then
begin
Image_main.Canvas.Brush.style:=bsSolid; // есть заливка
Image_main.Canvas.Brush.Color:=back_col
end
else
Image_main.Canvas.Brush.style:=bsClear; // нет заливки
-рисуем эллипс:
Image_main.Canvas.Ellipse(XBegin,YBegin,X,Y);
50
- иначе проверяем, выбран ли инструмент «Многоугольник»:
else if FmMain.SpeedButton_mn.Down then begin
Выбран многоугольник:
-устанавливаем атрибуты рисования:
Image_main.Canvas.Pen.Width:=nAngleW;
Image_main.Canvas.pen.mode:=pmcopy;
Image_main.Canvas.Pen.Style:=psSolid;
Image_main.Canvas.Pen.Color:=Front_col;
-для реализации заполнения проверяем компонент CheckBox1. Если выбрано,
то устанавливаем стиль кисти bsSolid и цвет фона как цвет заполнения.
Иначе стиль кисти – bsClear:
// Проверка флага "заливка"
if FmMain.CheckBox1.Checked then
begin
Image_main.Canvas.Brush.style:=bsSolid; // есть заливка
Image_main.Canvas.Brush.Color:=back_col
end
else
Image_main.Canvas.Brush.style:=bsClear; // нет заливки
-рисуем многоугольник:
Image_main.Canvas.Polygon(Slice(kol, kol_u));
-сбрасываем переменную, хранящую количество углов:
kol_u:=0;
2) снимаем флаг рисования:
// опустить флаг рисования
risovanae:=false;
3) для отображения действия в StatusBar выводим «Обзор»:
StatusBar_kartin.Panels[0].Text:='Обзор';
Блок-схема алгоритма работы процедуры отпускания мыши приведена на
рис.15.
Начало
нет
1
Нажата левая
кнопка мыши
да
2
51
1
2
нет
да
Выбрана
Линия
Устанавливаем
атрибуты
рисования
Рисуем линию
нет
да
Выбран
Прямоугольник
Устанавливаем
атрибуты
нет
Выбрано
заполнени
е
да
Атрибут отсутствия
заливки - bsClear
Атрибут заливки bsSolid
Рисуем
прямоугольник
нет
Выбран
да
Эллипс
Устанавливаем
атрибуты
1
2
3
4
52
1
2
3
нет
4
Выбрано
заполнение
да
Атрибут отсутствия
заливки - bsClear
Атрибут заливки bsSolid
Рисуем эллипс
нет
Выбран
Многоугольник
да
Устанавливаем
атрибуты
нет
Атрибут отсутствия
заливки - bsClear
Выбрано
заполнени
е
да
Атрибут заливки bsSolid
Рисуем
многоугольник
Снимаем флаг
рисования
Вывод «Обзор» в
StatusBar
Конец
Рисунок 15 - Блок-схема алгоритма работы процедуры отпускания мыши
53
4.10 Выбор цвета рисования и заливки
Для выбора цветов в модуле Unit1 созданы две процедуры-обработчика
нажатия на панель Panel_FG_Color («Цвет») и панель Panel_BG_Color
(«Фон») формы FmMain:
TFmMain.Panel_FG_ColorClick;
TFmMain.Panel_BG_ColorClick.
Алгоритмы работы этих процедур схожи:
1) проверяем выполнен ли диалог выбора цвета:
// Если выполнен диалог изменения цвета кисти
if FmMain.ColorDialog_Main.Execute then
Диалог выполнен:
-устанавливаем выбранный цвет:
// то меняем значения цвета кисти на полученный из диалога
Front_col:=FmMain.ColorDialog_Main.Color;
-для отображения текущего цвета изменяем цвет панели:
// Изменим цвет панели
FmMain.Panel_FG_Color.Color:=Front_col;
Блок-схема алгоритма работы процедуры выбора цвета приведена на
рис.16.
Начало
нет
Выполнен
диалог выбора
цвета
да
Устанавливаем
выбранный цвет
Изменяем цвет
панели
Конец
Рисунок 16 - Блок-схема алгоритма работы процедуры выбора цвета
54
4.11 Установка индивидуальных параметров рисования
К таким параметрам можно отнести толщину линии для инструментов: кисть,
линия, прямоугольник, многоугольник, эллипс, ластик и количество углов для
инструмента многоугольник.
Параметр количество углов устанавливается с помощью компонента
SpinEdit2, расположенного на форме FmMain и считывается в переменную
kol_u в процессе рисования, а точнее в процедуре нажатия мыши
TFmImage.Image_mainMouseMove, расположенной в модуле Unit2.
В свойствах компонента SpinEdit2 установлены следующие параметры:
Минимальное значение - MinValue:=3;
Максимальное значение - MaxValue:=100;
Параметр толщина линии доступен для всех инструментов, кроме заливки и
выделения. Устанавливается с помощью компонента SpinEdit1,
расположенного на форме FmMain и считывается в переменную,
соответствующую выбранному компоненту. Для установки толщины создана
процедура-обработчик изменения поля SpinEdit1Change («Толщина
линии») - TFmMain.SpinEdit1Change.
Алгоритм работы установки толщины линии следующий:
1)проверяем какой из инструментов выбран и устанавливаем его толщину. На
примере толщины кисти:
if FmMain.SpeedButton_Brush.Down then
BrushW:=SpinEdit1.Value
Блок-схема алгоритма установки толщины на примере инструмента «Линия»
приведена на рис.18.
Начало
нет
Выбран
инструмент
«Кисть»
да
Устанавливаем
толщину «Кисть»
Конец
Рисунок 18 - Блок-схема алгоритма установки толщины на примере
инструмента «Линия»
55
4.12 Разработка графического фильтра
Для реализации модального фильтра по апертуре «ромб» с размерами от 3х3
до 9х9 создан модуль Unit4 и форма FmFilter, на которой можно ввести
величину диагонали ромба.
Для применения фильтра создана процедура-обработчик нажатия на кнопку
BitBtn1 («OK») – T FmFilter.BitBtn1Click.
Объявляем следующие переменные, необходимые для работы процедуры:
i,j,m,n,k
: integer; // счётчики
L
: integer;
tx,ty,ix,iy
: integer; // Яркости каналов цвета
r,g,b
: integer; // Компоненты цвета
n_col,c
: TColor; // Новый цвет текущей точки
MaxR,MaxG,MaxB
: integer;
// Новые коэффициенты яркости каналов
цвета
MaxIr,MaxIg,MaxIb
: integer;
// Новые коэффициенты яркости
каналов цвета
Mask: array [1..3, 1..3] of integer; // Матрица маски
MasR, MasG, MasB: array [1..16] of integer;
nMasR, nMasG, nMasB: array [1..16] of integer;
Алгоритм работы процедуры применения фильтра следующий:
1) для возможности отмены изменений перезаписываем буфер отката
Undo_Buffer текущей формы:
// Перезаписать буфер отката
Undo_Buffer[Current_Fm].Width:=Fm_pic[Current_Fm].pic.Picture.Bitmap.Width;
Undo_Buffer[Current_Fm].Height:=Fm_pic[Current_Fm].pic.Picture.Bitmap.Height;
Undo_Buffer[Current_Fm].Canvas.CopyRect(
Rect(0,0,Undo_Buffer[Current_Fm].Width,Undo_Buffer[Current_Fm].Height),
Fm_pic[Current_Fm].pic.Canvas,
Rect(0,0,Undo_Buffer[Current_Fm].Width,Undo_Buffer[Current_Fm].Height));
2) инициализируем переменные:
// считываем коэффициент маски фильтра
L:=strtoint(Edit1.Text);
k:=0;
if L=3 then k:=2
else if L=5 then k:=3
else if L=7 then k:=4
else if L=9 then k:=5;
m:=k;
n:=k;
3)двигаемся по пикселям картинки:
// Цикл движения по пикселям картинки
while m<=Undo_Buffer[Current_Fm].Height-k do
begin
56
while n<=Undo_Buffer[Current_Fm].Width-k do
begin
tx:=n-k+1;
ty:=m+1;
ix:=1;
iy:=-1;
for i:=1 to 2*(l-1) do
begin
if (tx<=n) and (ix=1) then ty:=ty+iy;
if (tx>n) and (tx<=(n+k-1)) and (ix=1) then
begin
iy:=1;
ty:=ty+iy;
end;
if (ty=m) and (iy=1) then ix:=-1;
if (tx>=n) and (tx<=(n+k-1)) and (ix=-1) then ty:=ty+iy;
if (tx<n) and (ix=-1) then ty:=ty-iy;
4) определяем цвет данного пикселя:
c:=Undo_Buffer[Current_Fm].Canvas.Pixels[tx,ty];
5) Разложениe цвета данного пикселя на каналы RGB:
r:= (c mod $00000100);
g:= ((c mod $00010000) div $00000100);
b:= ((c mod $01000000) div $00010000);
MasR[i]:=r;
MasG[i]:=g;
MasB[i]:=b;
tx:=tx+ix;
end;
for i:=1 to 2*(l-1)-1 do
begin
maxR:=MasR[i];
MaxIr:=i;
maxG:=MasG[i];
MaxIg:=i;
maxB:=MasB[i];
MaxIb:=i;
for j:=1+i to 2*(l-1) do
begin
if MaxR<MasR[j] then
begin
maxR:=MasR[j];
MaxIr:=j;
end;
if MaxG<MasG[j] then
begin
maxG:=MasG[j];
MaxIg:=j;
end;
if MaxB<MasB[j] then
begin
maxB:=MasB[j];
MaxIb:=j;
end;
end;
MasR[maxIr]:=MasR[i];
MasR[i]:=MaxR;
MasG[maxIg]:=MasG[i];
MasG[i]:=MaxG;
MasB[maxIb]:=MasB[i];
MasB[i]:=MaxB;
57
end;
6) Определение нового цвета данного пикселя:
n_col:=$00010000*MasB[round((l-1)/2)]+$00000100*MasG[round((l1)/2)]+MasR[round((l-1)/2)];
7) Присваивание данному пикселю нового цвета:
Fm_Pic[Current_Fm].Pic.Canvas.Pixels[n,m]:=n_col;
8) Переход к следующему пикселю по горизонтали:
n:=n+1;
9) Переход к следующему пикселю по вертикали:
m:=m+1;
n:=k;
11) закрытие формы фильтра:
FmFilter.Close;
Блок-схема работы фильтра представлена на рис 19.
Начало
Перезаписываем буфер
отката
Считывание значения
габаритов креста Lи L1
1
58
1
да
L=3
L1=3
нет
k=2
нет
k1=3
да
L=5
нет
да
L1=5
k=3
k1=5
да
L=7
да
L1=7
k=4
нет
k1=7
нет
да
да
L=9
нет
L1=9
k=5
k1=9
нет
m=k1; n=k
m< (высота буф-k1)
нет
да
нет
n<(ширина буф. –k)
да
определяем координаты нового
текущего пикселя
1
2
3
4
5
59
1
2
3
4
5
8
9
j:=1..L
i:=1..L1
Определение цвета данного
пикселя
Разложение данного цвета на
каналы RGB и запись в массивы
нет
i:=1..(L1*L-1)
Первые элементы
максимальны
j:=1+i..L1*L
да
MaxR<MasR[j]
maxR:=MasR[j]
MaxIr:=j
нет
1
2
3
4
5
6
7
60
1
2
3
5
4
6
9
maxG:=MasG[j]
MaxIg:=j
да
MaxB<MasB[j]
нет
8
да
MaxG<MasG[j]
нет
7
maxB:=MasB[j]
MaxIb:=j
Перестановка элементов
массива
Определение нового цвета
данного пикселя
Присваивание нового цвета
данному пикселю
Переход к следующему пикселю по
горизонтали
Переход к следующему пикселю по
вертикали
Закрытие формы фильтра
Конец
Рисунок 19 -Блок-схема алгоритма работы фильтра
61
4.13 Разработка справочной системы
Для реализации справки создан специальный файл HELP.HLP, содержащий
форму справки.
Для вызова справки в модуле Unit1 создана процедура-обработчик нажатия на
пункт меню N_help («Справка») формы FmMain - TFmMain.N_helpClick.
Фрагмент текста программы, в котором производится вызов справки:
//вызов окна справки
winhelp(FmMain.Handle,'HELP.HLP', HELP_Context,1);
62
5. Приложение
{$A+,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W,X+,Y+,Z1}
{$MINSTACKSIZE $00004000}
{$MAXSTACKSIZE $00100000}
{$IMAGEBASE $00400000}
{$APPTYPE GUI}
{$r cur_res.res}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs, Menus, ExtDlgs, unit2, unit3, unit4, ExtCtrls, Buttons,
StdCtrls, ComCtrls,
ActnMan, ActnColorMaps;
type
TFmMain = class(TForm)
OpenPictureDialog1: TOpenPictureDialog;
SavePictureDialog1: TSavePictureDialog;
MainMenu1: TMainMenu;
N1: TMenuItem;
New_im: TMenuItem;
Load_im: TMenuItem;
Save_im: TMenuItem;
N5: TMenuItem;
Exit_Main: TMenuItem;
Help1: TMenuItem;
ColorDialog_Main: TColorDialog;
Panel1: TPanel;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
SpeedButton3: TSpeedButton;
Label1: TLabel;
Label2: TLabel;
Panel2: TPanel;
Panel3: TPanel;
SpeedButton4: TSpeedButton;
SpeedButton5: TSpeedButton;
SpeedButton6: TSpeedButton;
SpeedButton7: TSpeedButton;
CheckBox1: TCheckBox;
SpeedButton8: TSpeedButton;
Picture1: TMenuItem;
Size1: TMenuItem;
Filter: TMenuItem;
Edit1: TEdit;
UpDown1: TUpDown;
Edit2: TEdit;
UpDown2: TUpDown;
Label3: TLabel;
Label4: TLabel;
procedure Exit_MainClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure New_imClick(Sender: TObject);
procedure Load_imClick(Sender: TObject);
procedure Save_imClick(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
63
procedure
procedure
procedure
procedure
procedure
procedure
procedure
procedure
procedure
procedure
procedure
procedure
SpeedButton3Click(Sender: TObject);
SpeedButton2Click(Sender: TObject);
Panel2Click(Sender: TObject);
Panel3Click(Sender: TObject);
SpeedButton7Click(Sender: TObject);
SpeedButton6Click(Sender: TObject);
SpeedButton5Click(Sender: TObject);
SpeedButton4Click(Sender: TObject);
Size1Click(Sender: TObject);
FilterClick(Sender: TObject);
Edit1Change(Sender: TObject);
Help1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FG_Color: TColor;
BG_color: TColor;
LW,BW,EW: byte;
RW, ElW, nAW: Integer;
Copy_Buffer : TBitmap;
FmMain: TFmMain;
Fm_Pic: array [1..11] of TFmImage;
Fm_Pic_Flag: array [0..10] of boolean;
N_of_Fm: integer;
Current_Fm,n: integer;
procedure resize1(r_fm: TFmImage; r_w, r_h: integer);
implementation
{$R *.dfm}
procedure TFmMain.Exit_MainClick(Sender: TObject);
begin
FmMain.Close;
end;
procedure TFmMain.FormCreate(Sender: TObject);
var
i: integer;
begin
FG_Color:=Panel2.Color;
BG_Color:=Panel3.Color;
LW:=1;
BW:=5;
EW:=10;
RW:=1;
ElW:=1;
nAW:=1;
Screen.Cursors[1]:=LoadCursor(HInstance,'CRSOR1');
FmMain.Panel1.cursor:=1;
FmMain.Panel2.cursor:=1;
FmMain.Panel3.cursor:=1;
FmMain.Panel1.cursor:=1;
FmMain.cursor:=1;
FmMain.cursor:=1;
N_of_Fm:=0;
for i:=0 to 10 do Fm_Pic_Flag[i]:=false;
Copy_Buffer:=TBitmap.Create;
64
end;
procedure TFmMain.Help1Click(Sender: TObject);
begin
winhelp(FmMain.Handle,'HELP.HLP',Help_Context,1);
end;
procedure TFmMain.New_imClick(Sender: TObject);
begin
Application.CreateForm(TFmImage, Fm_Pic[11]);
Size1.Enabled:=true;
Filter.Enabled:=true;
Save_im.Enabled:=true;
n:=1;
repeat
if (Fm_Pic_Flag[n]=true) then Inc(n)
else
begin
N_of_Fm:=n;
Application.CreateForm(TFmImage, Fm_Pic[N_of_Fm]);
Fm_Pic[N_of_Fm].Pic.Canvas.Pen.Color:=clWhite;
Fm_Pic[N_of_Fm].Pic.Canvas.Rectangle
(0,0,Fm_Pic[N_of_Fm].Pic.Width, Fm_Pic[N_of_Fm].Pic.Height);
Fm_Pic[N_of_Fm].Tag:=N_of_Fm;
Fm_Pic[N_of_Fm].Caption:='Новое изображение '+IntToStr(N_of_Fm);
Fm_Pic[N_of_Fm].Show;
Fm_Pic_Flag[N_of_Fm]:=true;
break;
end;
if n=11 then MessageDlg(' Максимально может быть открыто 10 картинок
!!! ', mtWarning, [mbOk],0);
until (n>10);
end;
procedure resize1(r_fm: TFmImage; r_w, r_h: integer);
var
w, h: integer;
begin
w:=r_w;
h:=r_h+r_fm.StBar.Height;
if (r_w<=100)then w:=100;
if (r_h<=100)then h:=100+r_fm.StBar.Height;
if (r_w>=900) then w:=900;
if (r_h>=900) then h:=900;
if (r_w>=100) and (r_h>=100) and (r_w<=900) and (r_h<=900)
then r_fm.Pic.Align:=AlClient
else r_fm.Pic.Align:=AlTop;
r_fm.ClientWidth:=w;
r_fm.ClientHeight:=h;
end;
procedure TFmMain.Load_imClick(Sender: TObject);
var
bmp: TBitmap;
begin
if OpenPictureDialog1.Execute then
begin
bmp:=TBitmap.Create;
New_im.Click;
If n<11 then
begin
bmp.LoadFromFile(OpenPictureDialog1.FileName);
resize1(Fm_Pic[Current_fm],bmp.width,bmp.height);
Fm_Pic[Current_fm].Pic.Picture.Bitmap:=bmp;
65
Fm_Pic[Current_fm].Caption:=OpenPictureDialog1.FileName;
bmp.Destroy;
end;
end;
end;
procedure TFmMain.Save_imClick(Sender: TObject);
begin
if SavePictureDialog1.Execute then
begin
Fm_Pic[Current_fm].Pic.Picture.Bitmap.SaveToFile(SavePictureDialog1.FileName);
Fm_Pic[Current_fm].Caption:=SavePictureDialog1.FileName;
end;
end;
procedure TFmMain.SpeedButton1Click(Sender: TObject);
begin
Edit1.Text :=inttostr(LW);
Edit2.Enabled:=False;
end;
procedure TFmMain.SpeedButton3Click(Sender: TObject);
begin
Edit1.Text :=inttostr(BW);
Edit2.Enabled:=False;
end;
procedure TFmMain.SpeedButton2Click(Sender: TObject);
begin
Edit1.Text :=inttostr(EW);
Edit2.Enabled:=False;
end;
procedure TFmMain.Edit1Change(Sender: TObject);
begin
If FmMain.speedbutton1.down then LW:=strtoint(Edit1.Text);
If FmMain.speedbutton3.down then BW:=strtoint(Edit1.Text);
If FmMain.speedbutton2.down then EW:=strtoint(Edit1.Text);
If FmMain.speedbutton7.down then RW:=strtoint(Edit1.Text);
If FmMain.speedbutton6.down then ElW:=strtoint(Edit1.Text);
If FmMain.speedbutton5.down then nAW:=strtoint(Edit1.Text);
end;
procedure TFmMain.Panel2Click(Sender: TObject);
begin
If
FmMain.ColorDialog_Main.Execute
FG_color:=FmMain.ColorDialog_Main.Color;
FmMain.Panel2.Color:=FG_color;
end;
procedure TFmMain.Panel3Click(Sender: TObject);
begin
If
FmMain.ColorDialog_Main.Execute
BG_color:=FmMain.ColorDialog_Main.Color;
FmMain.Panel3.Color:=BG_color;
end;
then
then
procedure TFmMain.SpeedButton7Click(Sender: TObject);
begin
Edit1.Text :=inttostr(RW);
Edit2.Enabled :=False;
end;
66
procedure TFmMain.SpeedButton6Click(Sender: TObject);
begin
Edit1.Text :=inttostr(ElW);
Edit2.Enabled:=False;
end;
procedure TFmMain.SpeedButton5Click(Sender: TObject);
begin
Edit1.Text:=inttostr(nAW);
Edit2.Enabled:=True;
Edit1.Text :=inttostr(nAW);
end;
procedure TFmMain.SpeedButton4Click(Sender: TObject);
begin
Edit2.Enabled:=False;
end;
procedure TFmMain.Size1Click(Sender: TObject);
begin
FmPicSize.Show;
end;
procedure TFmMain.FilterClick(Sender: TObject);
begin
FmFilter.Show;
end;
End.
{$r Instruments.res}
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs, ComCtrls, ExtCtrls, Menus;
type
TFmImage = class(TForm)
Pic: TImage;
StBar: TStatusBar;
PopupMenu: TPopupMenu;
SetColor: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
Copy: TMenuItem;
Paste: TMenuItem;
N6: TMenuItem;
Undo: TMenuItem;
N1: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
N7: TMenuItem;
N8: TMenuItem;
N9: TMenuItem;
N10: TMenuItem;
procedure FormActivate(Sender: TObject);
procedure FormDeActivate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure PicMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure PicMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
67
procedure PicMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PicContextPopup(Sender: TObject; MousePos: TPoint;
var Handled: Boolean);
procedure SetColorClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure CopyClick(Sender: TObject);
procedure PasteClick(Sender: TObject);
procedure UndoClick(Sender: TObject);
procedure N1Click(Sender: TObject);
procedure N4Click(Sender: TObject);
procedure N5Click(Sender: TObject);
procedure N7Click(Sender: TObject);
procedure N8Click(Sender: TObject);
procedure N9Click(Sender: TObject);
procedure N10Click(Sender: TObject);
procedure FormResize(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FmImage: TFmImage;
// координаты точки нажатия кнопки мыши
Xbegin, Ybegin : Integer;
// координаты точки, над которой была мышь
X1 , Y1: Integer;
Undo_buffer: array [1..10] of TBitmap;
Redo_Buffer: array [1..10] of TBitmap;
ctf: Tcolor;
PA:array [1..15] of TPoint;
nCorners:integer;
Sel,xs,ys,xcm,ycm :integer;
// флаг рисования
drawing,Copy_Buffer_flag: Boolean;
implementation
uses unit1, Types, Math;
{$R *.dfm}
procedure TFmImage.FormActivate(Sender: TObject);
begin
Current_fm:=Tag;
end;
procedure TFmImage.FormDeactivate(Sender: TObject);
begin
if Sel=tag then
begin
Pic.Canvas.Pen.Color:=clRed;
Pic.Canvas.Pen.Style:=psDashDot;
Pic.Canvas.Pen.Width:=1;
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Brush.style:=bsClear;
Pic.Canvas.Rectangle(XBegin,YBegin,Xs,Ys);
Sel:=0;
end;
end;
procedure TFmImage.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
68
var
i,s:byte;
begin
Fm_Pic_Flag[Tag]:=False;
s:=0;
for i:=1 to 10 do
if Fm_Pic_Flag[i]=False then s:=s+1;
if s=10 then
begin
FmMain.Size1.Enabled:=False;
FmMain.Filter.Enabled:=False;
FmMain.Save_im.Enabled:=False;
end;
//Fm_Pic_Flag[0]:=true;
end;
procedure TFmImage.PicMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
j:integer;
c:TColor;
begin
// Вывод текста в первую панель
StBar.Panels[0].Text:='Обзор';
// Вывод координат курсора во вторую панель
StBar.Panels[1].Text:='X: '+InttoStr(X)+'
Y: '+InttoStr(Y);
// Вывод цвета точки под курсором в третью панель
c:=Pic.Canvas.Pixels[X,Y];
StBar.Panels[2].Text :='Color: '+ColortoString(c);
if FmMain.SpeedButton1.Down then Pic.cursor:=2;
if FmMain.SpeedButton3.Down then Pic.cursor:=3;
if FmMain.SpeedButton2.Down then Pic.cursor:=4;
if FmMain.SpeedButton4.Down then Pic.cursor:=5;
if FmMain.SpeedButton7.Down then Pic.cursor:=6;
if FmMain.SpeedButton6.Down then Pic.cursor:=7;
if FmMain.SpeedButton5.Down then Pic.cursor:=8;
if FmMain.SpeedButton8.Down then Pic.cursor:=9;
if drawing then
begin
if FmMain.SpeedButton1.Down then
begin
Pic.Canvas.Pen.Color:=FmMain.Panel2.Color;
Pic.Canvas.Pen.Style:=psSolid;
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Pen.Width:=strtoint(FmMain.Edit1.text);
Pic.Canvas.MoveTo(XBegin, YBegin);
Pic.Canvas.LineTo(X1, Y1);
Pic.Canvas.MoveTo(XBegin, YBegin);
Pic.Canvas.LineTo(X, Y);
Pic.Canvas.Pen.Mode:=pmCopy;
X1:=X;
Y1:=Y;
StBar.Panels[0].Text:='Рисование линии';
end
else if FmMain.SpeedButton3.Down then
begin
Pic.Canvas.Pen.Style:=psSolid;
Pic.Canvas.Pen.Mode:=pmCopy;
Pic.Canvas.Pen.Color:=FmMain.Panel2.Color;
Pic.Canvas.Pen.Width:=strtoint(FmMain.Edit1.Text);
Pic.Canvas.MoveTo(X1, Y1);
Pic.Canvas.LineTo(X, Y);
X1:=X;
Y1:=Y;
69
StBar.Panels[0].Text:='Рисование кистью';
end
else if FmMain.SpeedButton2.Down then
begin
Pic.Canvas.Pen.Style:=psSolid;
Pic.Canvas.Pen.Color:=BG_Color;
Pic.Canvas.Pen.Mode:=pmCopy;
Pic.Canvas.Pen.Color:=FmMain.Panel3.Color;
Pic.Canvas.Pen.Width:=strtoint(FmMain.Edit1.Text);
Pic.Canvas.MoveTo(X1, Y1);
Pic.Canvas.LineTo(X, Y);
X1:=X;
Y1:=Y;
StBar.Panels[0].Text:='Стирание';
end
// Если нажата кнопка "нарисовать ПРЯМОУГОЛЬНИК"
else if FmMain.SpeedButton7.Down then
begin
Pic.Canvas.Pen.Style:=psSolid;
Pic.Canvas.Pen.Width:=strtoint(FmMain.Edit1.Text);
// цвет линии - чёрный
Pic.Canvas.Pen.Color:=FG_Color;
// метод отрисовки линии - NotXor
Pic.Canvas.Pen.Mode:=pmNotXor;
// Cтереть предыдущий прямоугольник
Pic.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
// нарисовать новый прямоугольник
Pic.Canvas.Rectangle(XBegin,YBegin,X,Y);
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
StBar.Panels[0].Text:='Рисование прямоугольника';
end
else if FmMain.SpeedButton6.Down then
begin
Pic.Canvas.Pen.Style:=psSolid;
Pic.Canvas.Pen.Width:=strtoint(FmMain.Edit1.Text);
Pic.Canvas.Pen.Color:=FG_Color;
// метод отрисовки линии - NotXor
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Ellipse(XBegin,YBegin,X1,Y1);
Pic.Canvas.Ellipse(XBegin,YBegin,X,Y);
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
StBar.Panels[0].Text:='Рисование эллипса';
end
else if FmMain.SpeedButton5.Down then
begin
Pic.Canvas.Pen.Style:=psSolid;
Pic.Canvas.Pen.Width:=strtoint(FmMain.Edit1.Text);
nCorners:=strtoint(FmMain.Edit2.Text);
Pic.Canvas.Pen.Color:=FG_Color;
Pic.Canvas.Pen.Mode:=pmNotXor;
for j:=1 to nCorners do
begin
// формируем координату Х i-го угла
PA[j].X:=((X1+XBegin) div 2) + round (((X1-XBegin) div 2)*
cos(2*3.1415926*j/nCorners));
// формируем координату Y i-го угла
PA[j].Y:=((Y1+YBegin) div 2) - round (((Y1-YBegin) div 2)*
sin(2*3.1415926*j/nCorners));
end;
Pic.Canvas.Polygon(Slice(PA, nCorners));
70
for j:=1 to nCorners do
begin
// формируем координату Х i-го угла
PA[j].X:=((X+XBegin) div 2) + round (((X-XBegin) div 2)*
cos(2*3.1415926*j/nCorners));
// формируем координату Y i-го угла
PA[j].Y:=((Y+YBegin) div 2) - round (((Y-YBegin) div 2)*
sin(2*3.1415926*j/nCorners));
end;
Pic.Canvas.Polygon(Slice(PA, nCorners));
StBar.Panels[0].Text:='Рисование многоугольника';
X1:=X;
Y1:=Y;
end
else if FmMain.SpeedButton8.Down then
begin
FmMain.UpDown2.Enabled:=true;
Pic.Canvas.Pen.Color:=clRed;
Pic.Canvas.Pen.Style:=psDashDot;
Pic.Canvas.Pen.Width:=1;
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Brush.style:=bsClear;
if x>Undo_Buffer[Current_Fm].Width
then x:=Undo_Buffer[Current_Fm].Width;
if x<1 then x:=0;
if y>Undo_Buffer[Current_Fm].Height
then y:=Undo_Buffer[Current_Fm].Height;
if y<1 then y:=0;
Pic.Canvas.Rectangle(XBegin,YBegin,X1,Y1);
Pic.Canvas.Rectangle(XBegin,YBegin,X,Y);
X1:=X;
Y1:=Y;
Xs:=X;
Ys:=Y;
StBar.Panels[0].Text:='Выделение';
Sel:=tag;
end
end;
end;
procedure TFmImage.PicMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
j:integer;
begin
// обработчик нажатия на левую кнопку мыши
// если нажата левая кнопка мыши
if (Button=mbLeft) then
begin
// Проверка флага "заливка"
if FmMain.CheckBox1.Checked then
begin
Pic.Canvas.Brush.style:=bsSolid; // есть заливка
Pic.Canvas.Brush.Color:=BG_Color;
end
else Pic.Canvas.Brush.style:=bsClear; // нет заливки
if Sel=tag then
begin
Pic.Canvas.Pen.Color:=clRed;
Pic.Canvas.Pen.Style:=psDashDot;
Pic.Canvas.Pen.Width:=1;
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Brush.style:=bsClear;
71
Pic.Canvas.Rectangle(XBegin,YBegin,Xs,Ys);
Sel:=0;
end;
// сохранение координат точки нажатия кнопки мыши
Xbegin:=X;
Ybegin:=Y;
// сохранение координат точки, над которой была мышь
X1:=X;
Y1:=Y;
// поднятие флага рисования
drawing:=true;
Undo_Buffer[Tag].Width:=Pic.Picture.Bitmap.Width;
Undo_Buffer[Tag].Height:=Pic.Picture.Bitmap.Height;
Undo_Buffer[Tag].Canvas.CopyRect(Rect(0,0,Undo_Buffer[Tag].Width,Undo_Buffer[Tag
].Height),
Pic.Canvas,
Rect(0,0,Undo_Buffer[Tag].Width,Undo_Buffer[Tag].Height));
if FmMain.SpeedButton5.Down then
begin
Pic.Canvas.Pen.Width:=strtoint(FmMain.Edit1.Text);
nCorners:=strtoint(FmMain.Edit2.Text);
Pic.Canvas.Pen.Color:=FG_Color;
Pic.Canvas.Pen.Mode:=pmNotXor;
for j:=1 to nCorners do
begin
PA[j].X:=((X1+XBegin) div 2) + round (((X1-XBegin) div 2)*
cos(2*3.1415926*j/nCorners));
PA[j].Y:=((Y1+YBegin) div 2) - round (((Y1-YBegin) div 2)*
sin(2*3.1415926*j/nCorners));
end;
Pic.Canvas.Polygon(Slice(PA, nCorners));
end;
StBar.Panels[0].Text:='Рисование линии';
// Если нажата кнопка "ЗАЛИВКА"
if FmMain.SpeedButton4.Down then
begin
// запоминаем цвет точки под пикселом
Ctf:=Pic.Canvas.Pixels[X,Y];
Pic.Canvas.Brush.Color:=FG_Color;
Pic.Canvas.FloodFill(X,Y,Ctf,fsSurface);
end;
end;
end;
procedure TFmImage.PicMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
// если нажата левая кнопка мыши
if (Button=mbLeft) then
begin
// нарисовать линию тем цветом, который выбран
Pic.Canvas.Pen.mode:=pmCopy;
Pic.Canvas.Pen.Color:=FmMain.Panel2.Color;
if FmMain.SpeedButton1.Down then
begin
Pic.Canvas.MoveTo(Xbegin,Ybegin);
Pic.Canvas.LineTo(X,Y);
end ;
if FmMain.SpeedButton3.Down then
72
begin
Pic.Canvas.MoveTo(X1,Y1);
Pic.Canvas.LineTo(X,Y);
end ;
if FmMain.SpeedButton2.Down then
begin
Pic.Canvas.Pen.Color:=BG_Color;
Pic.Canvas.MoveTo(X1,Y1);
Pic.Canvas.LineTo(X,Y);
end ;
if
FmMain.SpeedButton7.Down
then
Pic.Canvas.Rectangle(XBegin,YBegin,X,Y);
if
FmMain.SpeedButton6.Down
then
Pic.Canvas.Ellipse(XBegin,YBegin,X,Y);
if
FmMain.SpeedButton5.Down
then
Pic.Canvas.Polygon(Slice(PA,
nCorners));
end;
// опустить флаг рисования
drawing:=false;
StBar.Panels[0].Text:='Обзор';
end;
procedure TFmImage.PicContextPopup(Sender: TObject; MousePos: TPoint;
var Handled: Boolean);
begin
xcm:=MousePos.X;
ycm:=MousePos.Y;
// вызвать всплывающее контекстное меню в той точке, где мышь
// для этого пересчитываем координаты с использованием
// положения формы (Left, Top)
PopupMenu.Popup(MousePos.X+Left,MousePos.Y+Top+20);
end;
procedure TFmImage.FormCreate(Sender: TObject);
begin
Screen.Cursors[1]:=LoadCursor(HInstance,'CRSOR2');
Screen.Cursors[2]:=LoadCursor(HInstance,'PEN');
Screen.Cursors[3]:=LoadCursor(HInstance,'BRUSH');
Screen.Cursors[4]:=LoadCursor(HInstance,'ERASER');
Screen.Cursors[5]:=LoadCursor(HInstance,'DYE');
Screen.Cursors[6]:=LoadCursor(HInstance,'RECT');
Screen.Cursors[7]:=LoadCursor(HInstance,'CIRC');
Screen.Cursors[8]:=LoadCursor(HInstance,'POLY');
Screen.Cursors[9]:=LoadCursor(HInstance,'SEL');
Pic.cursor:=1;
Sel:=0;
if FmMain.Save_im.Enabled=true then
begin
Undo_Buffer[N_of_Fm]:=TBitmap.Create;
Redo_Buffer[N_of_Fm]:=TBitmap.Create;
Undo_Buffer[N_of_Fm].Width:=pic.Width;
Undo_Buffer[N_of_Fm].Height:=pic.Height;
Undo_Buffer[N_of_Fm].Canvas.CopyRect(
Rect(0,0,Undo_Buffer[N_of_Fm].Width,Undo_Buffer[N_of_Fm].Height),
Fm_pic[N_of_Fm].pic.Canvas,
Rect(0,0,Undo_Buffer[N_of_Fm].Width,Undo_Buffer[N_of_Fm].Height));
end;
end;
procedure TFmImage.SetColorClick(Sender: TObject);
begin
FmMain.Panel2Click(FmMain);
73
end;
procedure TFmImage.CopyClick(Sender: TObject);
begin
if Sel=tag then
begin
Pic.Canvas.Pen.Color:=clRed;
Pic.Canvas.Pen.Style:=psDashDot;
Pic.Canvas.Pen.Width:=1;
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Brush.style:=bsClear;
Pic.Canvas.Rectangle(XBegin,YBegin,Xs,Ys);
Sel:=0;
Copy_Buffer.Width:=xs-XBegin+1;
Copy_Buffer.Height:=ys-yBegin+1;
Copy_Buffer.Canvas.CopyRect(Rect(0,0,xs-XBegin,ys-yBegin),
Pic.Canvas, Rect(XBegin,yBegin,Xs,Ys));
Copy_Buffer_flag:=true;
end
else
MessageDlg('Сначала
надо
выделить
область',
mtInformation,
[mbOk],0);
end;
procedure TFmImage.PasteClick(Sender: TObject);
begin
if Sel=tag then
begin
Pic.Canvas.Pen.Color:=clRed;
Pic.Canvas.Pen.Style:=psDashDot;
Pic.Canvas.Pen.Width:=1;
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Brush.style:=bsClear;
Pic.Canvas.Rectangle(XBegin,YBegin,Xs,Ys);
Sel:=0;
end;
if Copy_Buffer_flag=true then
Pic.Canvas.CopyRect(Rect(xcm,ycm,xcm+Copy_Buffer.Width,ycm+Copy_Buffer.Height),
Copy_Buffer.Canvas,
Rect(0,0,Copy_Buffer.Width,Copy_Buffer.Height))
else MessageDlg('Сначала надо скопировать область', mtInformation,
[mbOk],0);
end;
procedure TFmImage.UndoClick(Sender: TObject);
begin
if Sel=tag then
begin
Pic.Canvas.Pen.Color:=clRed;
Pic.Canvas.Pen.Style:=psDashDot;
Pic.Canvas.Pen.Width:=1;
Pic.Canvas.Pen.Mode:=pmNotXor;
Pic.Canvas.Brush.style:=bsClear;
Pic.Canvas.Rectangle(XBegin,YBegin,Xs,Ys);
Sel:=0;
end;
Fm_Pic[11].Pic.Picture.Bitmap:=Undo_Buffer[Current_Fm];
resize1(Fm_Pic[Current_Fm],Undo_Buffer[Current_Fm].Width,Undo_Buffer[Current_Fm]
.Height);
Redo_Buffer[Current_Fm].Width:=Undo_Buffer[Current_Fm].Width;
Redo_Buffer[Current_Fm].Height:=Undo_Buffer[Current_Fm].Height;
74
Redo_Buffer[Current_Fm].Canvas.CopyRect(
Rect(0,0,Redo_Buffer[Current_Fm].Width,Redo_Buffer[Current_Fm].Height),
pic.Canvas,
Rect(0,0,Redo_Buffer[Current_Fm].Width,Redo_Buffer[Current_Fm].Height));
Fm_Pic[Current_Fm].Pic.Picture.Bitmap:=Fm_Pic[11].Pic.Picture.Bitmap;
Undo_Buffer[Current_Fm]:=Redo_Buffer[Current_Fm];
Fm_Pic[Current_Fm].StBar.Panels[0].Width:=round(Undo_Buffer[Current_Fm].Width/3)
;
Fm_Pic[Current_Fm].StBar.Panels[1].Width:=round(Undo_Buffer[Current_Fm].Width/3)
;
end;
procedure TFmImage.N1Click(Sender: TObject);
begin
FmMain.SpeedButton1.Down:=True;
FmMain.SpeedButton1.Click;
end;
procedure TFmImage.N4Click(Sender: TObject);
begin
FmMain.SpeedButton3.Down:=True;
FmMain.SpeedButton3.Click;
end;
procedure TFmImage.N5Click(Sender: TObject);
begin
FmMain.SpeedButton2.Down:=True;
FmMain.SpeedButton2.Click;
end;
procedure TFmImage.N7Click(Sender: TObject);
begin
FmMain.SpeedButton4.Down:=True;
FmMain.SpeedButton4.Click;
end;
procedure TFmImage.N8Click(Sender: TObject);
begin
FmMain.SpeedButton7.Down:=True;
FmMain.SpeedButton7.Click;
end;
procedure TFmImage.N9Click(Sender: TObject);
begin
FmMain.SpeedButton6.Down:=True;
FmMain.SpeedButton6.Click;
end;
procedure TFmImage.N10Click(Sender: TObject);
begin
FmMain.SpeedButton5.Down:=True;
FmMain.SpeedButton5.Click;
end;
procedure TFmImage.FormResize(Sender: TObject);
begin
75
Fm_Pic[Current_Fm].StBar.Panels[0].Width:=round(Fm_Pic[Current_Fm].Width/3);
Fm_Pic[Current_Fm].StBar.Panels[1].Width:=round(Fm_Pic[Current_Fm].Width/3);
end;
End.
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants,
Forms,
Dialogs, StdCtrls, ExtCtrls, Buttons;
Classes,
Graphics,
Controls,
type
TFmPicSize = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
Panel1: TPanel;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
Label1: TLabel;
Label2: TLabel;
procedure FormShow(Sender: TObject);
procedure Edit1Change(Sender: TObject);
procedure Edit2Change(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Ratio: real;
FmPicSize: TFmPicSize;
implementation
uses Unit1, Unit2;
{$R *.dfm}
procedure TFmPicSize.FormShow(Sender: TObject);
var
w,h : integer;
begin
// считываем размер картинки
w:=Fm_Pic[Current_Fm].Pic.Picture.Bitmap.Width;
h:=Fm_Pic[Current_Fm].Pic.Picture.Bitmap.Height;
Undo_Buffer[Current_Fm].Width:=Fm_pic[Current_Fm].pic.Picture.Bitmap.Width;
Undo_Buffer[Current_Fm].Height:=Fm_pic[Current_Fm].pic.Picture.Bitmap.Height;
Undo_Buffer[Current_Fm].Canvas.CopyRect(
Rect(0,0,Undo_Buffer[Current_Fm].Width,Undo_Buffer[Current_Fm].Height),
Fm_pic[Current_Fm].pic.Canvas,
76
Rect(0,0,Undo_Buffer[Current_Fm].Width,Undo_Buffer[Current_Fm].Height));
// заполняем поля редактирования
Edit1.Text:=IntToStr(w);
Edit2.Text:=IntToStr(h);
ratio:=w/h;
end;
procedure TFmPicSize.Edit1Change(Sender: TObject);
var
// высота и ширина
w,h : integer;
begin
if Edit1.Modified=True then
// если надо сохранять пропорции
if CheckBox2.Checked then
begin
if Edit1.Text<>'' then
begin
// считываем ширину
w:=StrToInt(Edit1.Text);
// вычисляем высоту
h:=round(w/ratio);
// заполняем поле редактирования
Edit2.Text:=IntToStr(h);
end;
end;
end;
procedure TFmPicSize.Edit2Change(Sender: TObject);
var
// высота и ширина
wh,hh : integer;
begin
if Edit2.Modified=True then
// если надо сохранять пропорции
if CheckBox2.Checked then
begin
if Edit2.Text<>'' then
begin
// считываем ширину
hh:=StrToInt(Edit2.Text);
// вычисляем высоту
wh:=round(hh*ratio);
// заполняем поле редактирования
Edit1.Text:=IntToStr(wh);
end;
end;
end;
procedure TFmPicSize.BitBtn2Click(Sender: TObject);
begin
FmPicSize.Close;
end;
procedure TFmPicSize.BitBtn1Click(Sender: TObject);
var
w,h : integer;
BMP : TBitmap;
begin
if (Edit1.text='') or (Edit2.text='') then
MessageDlg('Необходимо ввести значения', mtError, [mbOk],0)
else
if (StrToInt(Edit1.text)=0) or (StrToInt(Edit2.text)=0) then
77
MessageDlg('Значение не может быть равным 0', mtError, [mbOk],0)
else
begin
// создаём буферное изображение
BMP:=TBitmap.Create;
// считываем ширину
w:=StrToInt(Edit1.Text);
h:=StrToInt(Edit2.Text);
// изменяем размер буфера
BMP.Width :=w;
BMP.Height:=h;
// очищаем буфер
BMP.Canvas.Pen.Color:=clWhite;
BMP.Canvas.Brush.Color:=clWhite;
BMP.Canvas.Rectangle(0,0,w,h);
if CheckBox1.Checked then
// копируем в буфер изображение из формы редактирования
// растягивая или сжимая его до размеров буфера
BMP.Canvas.StretchDraw(rect(0,0,w,h),Fm_Pic[Current_Fm].Pic.Picture.Bitmap)
else
// копируем в буфер изображение из формы редактирования
BMP.Canvas.Draw(0,0,Fm_Pic[Current_Fm].Pic.Picture.Bitmap);
resize1(Fm_Pic[Current_Fm],w,h);
Fm_Pic[Current_Fm].StBar.Panels[0].Width:=round(w/3);
Fm_Pic[Current_Fm].StBar.Panels[1].Width:=round(w/3);
// копируем изображение из буфера на форму
Fm_Pic[Current_Fm].Pic.Picture.Bitmap:=BMP;
// уничтожаем буфер
BMP.Destroy;
// закрываем окно изменения размеров
FmPicSize.Close;
end
end;
end.
unit Unit4;
interface
uses
Windows,
Forms,
Dialogs,
ActnColorMaps;
Messages,
StdCtrls,
SysUtils,
Spin,
Variants,
Buttons,
Classes,
ExtCtrls,
Graphics,
Controls,
ComCtrls,
ActnMan,
type
TFmFilter = class(TForm)
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
Label1: TLabel;
Label3: TLabel;
Button1: TButton;
Button2: TButton;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
RadioButton3: TRadioButton;
RadioButton4: TRadioButton;
Label2: TLabel;
Label6: TLabel;
RadioButton5: TRadioButton;
RadioButton6: TRadioButton;
RadioButton7: TRadioButton;
RadioButton8: TRadioButton;
78
procedure BitBtn2Click(Sender:
procedure BitBtn1Click(Sender:
procedure Button1Click(Sender:
procedure Button2Click(Sender:
private
{ Private declarations }
public
{ Public declarations }
end;
TObject);
TObject);
TObject);
TObject);
var
FmFilter: TFmFilter;
implementation
uses Unit1, Unit2, Unit3, Math;
{$R *.dfm}
procedure TFmFilter.BitBtn2Click(Sender: TObject);
begin
FmFilter.Close;
end;
procedure TFmFilter.Button1Click(Sender: TObject);
begin
label3.Visible:=true;
radiobutton1.Visible:=true;
radiobutton2.Visible:=true;
radiobutton3.Visible:=true;
radiobutton4.Visible:=true;
radiobutton5.Visible:=false;
radiobutton6.Visible:=false;
radiobutton7.Visible:=false;
radiobutton8.Visible:=false;
end;
procedure TFmFilter.Button2Click(Sender: TObject);
begin
label3.Visible:=true;
radiobutton1.Visible:=false;
radiobutton2.Visible:=false;
radiobutton3.Visible:=false;
radiobutton4.Visible:=false;
radiobutton5.Visible:=true;
radiobutton6.Visible:=true;
radiobutton7.Visible:=true;
radiobutton8.Visible:=true;
end;
procedure TFmFilter.BitBtn1Click(Sender: TObject);
var
i,j,m,n,k
: integer; // счётчики
L
: integer;
tx,ty,ix,iy
: integer; // Яркости каналов цвета
r,g,b
: integer; // Компоненты цвета
n_col,c
: TColor; // Новый цвет текущей точки
MaxR,MaxG,MaxB
: integer;
// Новые коэффициенты яркости каналов
цвета
MaxIr,MaxIg,MaxIb
: integer;
// Новые коэффициенты яркости
каналов цвета
Mask: array [1..3, 1..3] of integer; // Матрица маски
79
MasR, MasG, MasB: array [1..16] of integer;
nMasR, nMasG, nMasB: array [1..16] of integer;
Begin
// Перезаписать буфер отката
Undo_Buffer[Current_Fm].Width:=Fm_pic[Current_Fm].pic.Picture.Bitmap.Width;
Undo_Buffer[Current_Fm].Height:=Fm_pic[Current_Fm].pic.Picture.Bitmap.Height;
Undo_Buffer[Current_Fm].Canvas.CopyRect(
Rect(0,0,Undo_Buffer[Current_Fm].Width,Undo_Buffer[Current_Fm].Height),
Fm_pic[Current_Fm].pic.Canvas,
Rect(0,0,Undo_Buffer[Current_Fm].Width,Undo_Buffer[Current_Fm].Height));
// считываем коэффициент маски фильтра
k:=0;
if
(radiobutton1.Checked)
or
(radiobutton2.Checked)
or
(radiobutton3.Checked) or (radiobutton4.Checked) then
begin
if radiobutton1.Checked then
begin
l:=3;
k:=2;
radioButton1.Checked:=False;
end;
if radiobutton2.Checked then
begin
l:=5;
k:=3;
radioButton2.Checked:=False;
end;
if radiobutton3.Checked then
begin
l:=7;
k:=4;
radioButton3.Checked:=False;
end;
if radiobutton4.Checked then
begin
l:=9;
k:=5;
radioButton4.Checked:=False;
end;
end
else
if radiobutton5.Checked then
begin
l:=3;
k:=3;
radioButton5.Checked:=False;
end;
if radiobutton6.Checked then
begin
l:=5;
k:=5;
radioButton6.Checked:=False;
end;
if radiobutton7.Checked then
begin
l:=7;
k:=7;
radioButton7.Checked:=False;
end;
if radiobutton8.Checked then
begin
l:=9;
80
k:=9;
radioButton8.Checked:=False;
end;
m:=k;
n:=k;
// Цикл движения по пикселям картинки
while m<=Undo_Buffer[Current_Fm].Height-k do
begin
while n<=Undo_Buffer[Current_Fm].Width-k do
begin
tx:=n-k+1;
ty:=m+1;
ix:=1;
iy:=-1;
for i:=1 to 2*(l-1) do
begin
if (tx<=n) and (ix=1) then ty:=ty+iy;
if (tx>n) and (tx<=(n+k-1)) and (ix=1) then
begin
iy:=1;
ty:=ty+iy;
end;
if (ty=m) and (iy=1) then ix:=-1;
if (tx>=n) and (tx<=(n+k-1)) and (ix=-1) then ty:=ty+iy;
if (tx<n) and (ix=-1) then ty:=ty-iy;
// Определение цвета данного пикселя
c:=Undo_Buffer[Current_Fm].Canvas.Pixels[tx,ty];
// Разложениe цвета данного пикселя на каналы RGB
r:= (c mod $00000100);
g:= ((c mod $00010000) div $00000100);
b:= ((c mod $01000000) div $00010000);
MasR[i]:=r;
MasG[i]:=g;
MasB[i]:=b;
tx:=tx+ix;
end;
for i:=1 to 2*(l-1)-1 do
begin
maxR:=MasR[i];
MaxIr:=i;
maxG:=MasG[i];
MaxIg:=i;
maxB:=MasB[i];
MaxIb:=i;
for j:=1+i to 2*(l-1) do
begin
if MaxR<MasR[j] then
begin
maxR:=MasR[j];
MaxIr:=j;
end;
if MaxG<MasG[j] then
begin
maxG:=MasG[j];
MaxIg:=j;
end;
if MaxB<MasB[j] then
begin
maxB:=MasB[j];
MaxIb:=j;
end;
end;
MasR[maxIr]:=MasR[i];
81
MasR[i]:=MaxR;
MasG[maxIg]:=MasG[i];
MasG[i]:=MaxG;
MasB[maxIb]:=MasB[i];
MasB[i]:=MaxB;
end;
// Определение нового цвета данного пикселя
n_col:=$00010000*MasB[round((l-1)/2)]+$00000100*MasG[round((l1)/2)]+MasR[round((l-1)/2)];
// Присваивание данному пикселю нового цвета
Fm_Pic[Current_Fm].Pic.Canvas.Pixels[n,m]:=n_col;
// Переход к следующему пикселю по горизонтали
n:=n+1;
end;
// Переход к следующему пикселю по вертикали
m:=m+1;
n:=k;
end;
// закрытие формы
FmFilter.Close;
end;
end.
82
Документ
Категория
Программное обеспечение
Просмотров
65
Размер файла
918 Кб
Теги
svirin_проверен, проект, курсовой
1/--страниц
Пожаловаться на содержимое документа