Живая открытка
|
Автор: Матвеев Игорь
- Я не покупаю кота в мешке,- сказал жених родителям невесты.
- До свадьбы я хотел бы увидеть свою нареченную в натуральном виде, какой ее бог сотворил!
Родители невесты долго колебались, но в конце концов согласились.
Жених очень внимательно осмотрел невесту и наконец сказал:
- Я не могу на ней жениться. У нее слишком большие уши.
|
Сегодня я решил сделать нечто вроде открытки, живой открытки - изображение
будет как бы колеблющемся.
Сперва необходимо решить, что будет изображено на открытке,
я решил изобразить сердце, а под ним надпись вроде "Я люблю тебя".
Хотя рисовать можно все что угодно: зеленую новогоднюю елочку,
симпатичную рожицу или даже цветок. Это не столь важно, смысл в том,
что необходимо простое векторное изображение - некоторое количество точек,
определенным образом связанных между собой.
Однако, оставим пока тонкости рисования рисунка и перейдем к
тому как сделать изображение красивым, плавным, колеблющемся.
Это можно сделать просто немного изменяя координаты "точек для построения" -
точек, необходимых для построения той или иной фигуры и накладывая новое,
слегка измененное изображение на предыдущее. В тоже время нужно сделать, чтобы
цвета постепенно как бы гасли к цвету фона, тогда изображение будет похожим на
то, что изображено на рисунке.
Для исключения мигания, сначала изображение открытки рисуется на виртуальном
Bitmap-е, а затем методом Draw() выводится на канву PaintBox-а.
Код осветления изображения необходимо поместить в обработчике
OnTimer таймера с минимальным интервалом. Поскольку работа с канвой
занимает много времени, будем работать напрямую с Bitmap-ом через свойство ScanLine.
В следующем коде представлен алгоритм осветления изображения:
type
TRGB = record
b, g, r: byte;
end;
ARGB = array[0..1] of TRGB;
PARGB = ^ARGB;
var
p : PARGB;
x, y : Integer;
begin
for y := 0 to BMP.height - 1 do
begin
p := BMP.ScanLine[y];
for x := 0 to BMP.width - 1 do
begin
if p[x].r <> 255 then p[x].r := p[x].r+2;
if p[x].g <> 255 then p[x].g := p[x].g+2;
if p[x].b <> 255 then p[x].b := p[x].b+2;
end;
end;
Далее поговорим о рисовании сердца: очевидно, что для формирования сердца необходимо
четыре точки, плюс для формирования дуг эллипсов необходима верхняя грань прямоугольной
области, в которую вписано сердце. Вот и получается, что структура сердца выглядит
следующим образом:
type
THeart = record
P1, P2, P3, P4 : TPoint; // Точки построения
Top : Integer; // Верхняя граница
end;
Формировать сердце можно по разному, ниже приведена функция, которая
на основе прямоугольной область вычисляет координаты точек для построения
сердца, вписанного в эту область:
function InitHeart(Rect : TRect): THeart;
begin
with Result do
begin
// Сохраняем верхнюю грань сердца
Top := Rect.Top;
// Вычисление координат точек для построения
P1.X := Rect.Left;
P1.Y := Round(Rect.Top + (Rect.Bottom - Rect.Top) / 3);
P2.X := Round((Rect.Left + Rect.Right) / 2);
P2.Y := Round(Rect.Top + (Rect.Bottom - Rect.Top) / 9);
P3.X := Rect.Right;
P3.Y := P1.Y;
P4.X := P2.X;
P4.Y := Rect.Bottom;
end;
end;
Далее необходимо создать процедуру отрисовки сердца: сперва рисуются
прямые линии, затем две дуги эллипса:
procedure DrawHeart(Canvas: TCanvas; Heart: THeart);
begin
with Heart do
begin
Canvas.Pen.Color := HColor;
Canvas.MoveTo(P1.X, P1.Y);
Canvas.LineTo(P4.X, P4.Y);
Canvas.LineTo(P3.X, P3.Y);
Canvas.Arc(P1.X-3, Top, Round(P1.X+P3.X/2)+12, Round(Top+P4.Y/2), P2.X-7, P2.Y, P1.X, P1.Y+1);
Canvas.Arc(P2.X-20, Top, P3.X+3, Round(Top+P4.Y/2), P3.X, P3.Y, P2.X-20, P2.Y+10);
end;
end;
Итак, поскольку сердце будет колеблющемся, необходимо две переменные типа
THeart - первая (MHeart) будет хранить первоначальные координаты точек, вторая (NewHeart)
непосредственно будет использоваться для рисования, координаты точек этого
сердца будут вычисляться на основе координат первого с небольшим случайным "люфтом".
В результате в OnCreate формы необходимо поместить следующий код:
// Инициализация генератора случайных чисел
Randomize;
// Создание виртуального изображения
BMP := TBitmap.Create;
BMP.pixelformat := pf24bit;
BMP.Width := Pole.Width;
BMP.Height := Pole.Height;
BMP.Canvas.Pen.Color := clRed;
BMP.Canvas.Pen.Width := 3;
// Вычисление первоночальных точек для построения сердца
MHeart := InitHeart(Rect(20, 5, Pole.Width - 20, Pole.Height - 80));
NewHeart := MHeart;
Рисование сердца тоже выносим в отдельный таймер с минимальным
интервалом. Вот как это происходит:
NewHeart.P1.X := MHeart.P1.X + Random(31) - 15;
NewHeart.P1.Y := MHeart.P1.Y + Random(31) - 15;
NewHeart.P2.X := MHeart.P2.X + Random(31) - 15;
NewHeart.P2.Y := MHeart.P2.Y + Random(31) - 15;
NewHeart.P3.X := MHeart.P3.X + Random(31) - 15;
NewHeart.P3.Y := MHeart.P3.Y + Random(31) - 15;
NewHeart.P4.X := MHeart.P4.X + Random(31) - 15;
NewHeart.P4.Y := MHeart.P4.Y + Random(31) - 15;
DrawHeart(BMP.Canvas, NewHeart);
Вот пожалуй и все, несколько расширенный проект открытки (плавно
появляется и исчезает, играет музыка) смотрите здесь.
Напоследок хочется еще раз сказать, что рисовать в такой открытке
можно все, что угодно, представьте себе нарисованную так забавную рожицу или
логотип компании где вы работайте. Желаю удачи в ваших экспериментах.
|