Пример: Транспортная логистика
Я ищу:
На главную  |  Добавить в избранное  

Цифровые устройства /

ISO - Графический редактор на Delphi 5

←предыдущая следующая→
1 2 3 4 



Скачать реферат


Sender).Tag));

end;

procedure TFePaint.Doing(const Action: TDrawAction);

var Fon, AGrid: Boolean;

UCount: Byte;

Size: TPoint;

Bmp: TBitmap;

begin

if not GetCan(Action) then Exit;

Ended;

case Action of

daClear: begin

CanChangeImage;

ClearImage;

ChangedImage;

end;

daCopyToFile: Save(True, False);

end;

end;

Нестандартный способ решения задачи применён и к алгоритму отмены и повтора действий пользователя. Создан специальный класс TBmpMemory, который хранит изображения в памяти. После каждого действия, будь то ри-сование прямоугольника или увеличение контрастности, изображение сохра-няется в отдельной ячейке (Cell) динамического массива, длина которого равна числу возможных отмен + 1. Данный массив представляет собой дву-связный список. Тип каждой ячейки определён следующим образом:

PBitmapCell = ^TBitmapCell;

TBitmapCell = record

NextCell: PBitmapCell; // указатель на следующую ячейку

PrevCell: PBitmapCell; // указатель на предыдущую ячейку

Bitmap: TBitmap;

end;

Таким образом, каждый элемент списка имеет указатель на предыдущий и на следующий элемент. Указатель PrevCell первой ячейки указывает на послед-нюю, а указатель NextCell последней ячейки указывает на первую ячейку. Получается замкнутое кольцо без входа и выхода. Это сделано по той причи-не, что после отмены действия, для восстановления требуется то изображе-ние, которое было отменено. Например: пользователь нарисовал круг, а затем линию. В первой ячейке записано изображение, которое было до рисования круга, во второй – после рисования круга, а в третьей – после рисования ли-нии. После отмены последнего действия указатель перемещается на преды-дущую ячейку (ячейка с кругом, но без линии):

procedure TBmpMemory.Undo(Bitmap: TBitmap);

begin

if CanUndo then begin

Dec(FNumUndo); //уменьшаем число возможных отмен

Bitmap.Assign(FActiveCell^.Bitmap); //передаём изображение с активной ячейки

FActiveCell := FActiveCell^.PrevCell;//переносим указатель на предыдущую ячейку

end;

end;

Если же пользователь передумал и решил вернуть нарисованное, то он может вызвать повтор последнего отменённого действия (если после отмены ничего не было сделано):

procedure TBmpMemory.Redo(Bitmap: TBitmap);

begin

if CanRedo then begin

Inc(FNumUndo); //увеличиваем число возможных отмен

FActiveCell := FActiveCell^.NextCell; //переносим указатель на следующую ячейку

Bitmap.Assign(FActiveCell^.NextCell^.Bitmap); //передаём изображение

//со следующей после активной ячейки, т. к. активная ячейка та,

//которая должна быть отменена

end;

end;

Вся программа построена на основе большого количества классов, каж-дый из которых отвечает за отдельную функцию. Это помогает локализовать, разбить по частям всю программу, а не создавать огромные процедуры, об-работчики событий, что, конечно же, идет на пользу и является подтвержде-нием преимуществ объективно-ориентированного метода программирования.

Принципы графических алгоритмов.

Поскольку программа является растровым (точечным) редактором, то изображение находится в виде объекта графического класса TBitmap и рабо-та всех эффектов основана на работе с этим классом. TBitmap содержит дву-мерный массив, в каждой ячейке которого записан определённый цвет. То есть мы имеем дело с двумерной (плоскостной) системой координат: каждая точка рисунка описывается двумя координатами, например (45, 87).

Доступ к определённой точке можно получить двумя способами: через свойство Canvas.Pixels[x, y] (x и y – координаты точки), которое имеет тип TColor, или с помощью свойства ScanLine[y], которое возвращает указатель на начало строки под номером 'y'. Первый способ работает гораздо медлен-нее второго, поэтому он почти не используется, хотя и более удобен.

Каждый цвет (в компьютерном представлении) состоит из трёх оттен-ков: красного (red), зелёного (green) и синего (blue) – RGB. При этом каждый из оттенков может принимать значения от 0 до 255, то есть, всего компьютер (монитор) может отображать 256*256*256=16777216 разных цветов.

Все функции и процедуры, имеющие отношение к созданию эффектов, находятся в файле FeProcs.pas, который занимает 69 КБ, так как этих функ-ций очень много.

Рассмотрим пример реализации эффекта 'Негатив':

type

TRGB = record

B, G, R: Byte;

end;

pRGB = ^TRGB;

procedure InvertBitmap(Bitmap: TBitmap);

var x, y: Integer;

Dest: pRGB;

begin

for y := 0 to Bitmap.Height - 1 do begin

Dest := Bitmap.ScanLine[y]; //помещаем указатель в начало строки y

for x := 0 to Bitmap.Width - 1 do begin

with Dest^ do begin

R := 255 - R; //чтобы обратить цвет,

G := 255 - G; //нужно обратить на противоположные

B := 255 - B; //его составляющие

end;

Inc(Dest); //перемещаем указатель вправо

end;

end;

end;

Цикл начинается с 0 и заканчивается на Bitmap.Height – 1 (Bitmap.Width – 1), так как в системе координат Windows отсчёт начинается с точки (0, 0), а точ-ки (Width – ширина, Height – высота) не существует. Внешний цикл прохо-дит по порядку все строки (координата Y), потомучто свойство Bitmap ScanLine передаёт указатель на строку, а не на столбец.

Интересной (с точки зрения программирования) является функция под-счёта цветов рисунка:

function HowManyColors(Bitmap: TBitmap): Integer;

var i: Byte;

x, y: Integer;

Dest: pRGB;

RGBArray: array [Byte, Byte] of array of Byte;

begin

Result := 0;

for y := 0 to Bitmap.Height - 1 do begin

Dest := Bitmap.ScanLine[y];

for x := 0 to Bitmap.Width - 1 do begin

with Dest^ do

if RGBArray[r, g] nil then

for i := 0 to High(RGBArray[r, g]) do begin

if RGBArray[r, g] [i] = b then Break; //такой цвет уже есть – выход из цикла

if i = High(RGBArray[r, g]) then begin //если это последний 'круг' цикла, то

//такого цвета нет и его нужно записать

Inc(Result); //прибавляем еще один цвет

SetLength(RGBArray[r, g], Length(RGBArray[r, g]) + 1);

RGBArray[r, g] [High(RGBArray[r, g])] := b;

end;

end

else begin

Inc(Result); //прибавляем еще один цвет

SetLength(RGBArray[r, g], 1);

RGBArray[r, g] [0] := b;

end;

Inc(Dest);

end;

end;

end;

Изначально, для решения задачи подсчёта цветов применялся следующий ал-горитм: использовалась глобальная переменная, которая являлась трёхмер-ным массивом - «ColorsArray: array [0..255, 0..255, 0..255] of Boolean», то есть имел для каждого существующего цвета отдельную ячейку типа Boolean – всего 16777216 ячеек; в начале функции значения всех ячеек устанавливались в False (ложный), это означало, что нет ни одного цвета; затем цвет каждой точки разлагался на составляющие R, G и B, и проверялось значение соответ-ствующей ячейки - «ColorsArray[R, G, B]», если оно было ложным, то изменя-лось на True (истинный), а количество цветов рисунка увеличивалось на один. Но, естественно, такой подход крайне иррационален, так как компиля-тор не позволяет выделять так много памяти внутри процедуры, а выделение 16 Мбайт памяти при загрузке тормозит не только саму программу, но и дру-гие процессы системы. По этой причине пришлось отказаться от такого ре-шения и разработать новый алгоритм, что и было сделано. Функция, реали-зующая новый подход изложена выше, а сам он заключается в динамическом выделении памяти. Переменная RGBArray – это двумерный массив, каждая ячейка которого, в свою очередь, является динамическим массивом типа Byte (0..255). Фактически изначально вообще не выделяется памяти, она выделя-ется по мере увеличения числа цветов.

Системные требования.

Микропроцессор – Pentium 100 и выше.

Оперативная память – 16 Mb RAM.

Операционная система – Windows 9x/Me.

Свободное место на диске – 1 Mb.

Аппаратное обеспечение – мышь.

Заключение.

По мере написания программы возникали всё новые задачи и проблемы, которые было бы невозможно или нецелесообразно решать обычными мето-дами, поэтому приходилось изобретать или где-то заимствовать нестандарт-ные алгоритмы решения задач, коих в программе довольно много. Это по-могло сохранить небольшой размер и высокую производительность про-граммы при её широких возможностях, что делает её весьма привлекатель-ной для пользователей как опытных, так и не очень.

Умелое сочетание применения

←предыдущая следующая→
1 2 3 4 



Copyright © 2005—2007 «Mark5»