программирование :: разное

Практическое руководство по компьютерным приколам 15

Наша Весна подобна крупному IT-проекту на середине разработки: вроде как все есть, а присмотришься — так ничего и не начиналось.

Давным-давно, когда древние люди были еще не очень умными и весьма неохотно делились мамонтами с налоговой инспекцией, свои шутники были везде. Конечно, юмор их был весьма грубым и примитивным — саблезубого тигра там в койку подсунуть, ерунду всякую на стене нарисовать, коварно представляя, как ученые в далеком будущем будут говорить о страшных видах живых существ, на которых охотились древние, или обменять новую жену вождя на старый компьютер... тьфу ты... понесло... — в общем, все это было пошло, банально и практически нереализуемо в нашей с вами среде Borland Delphi 6:). К слову, судя по письмам, многие читатели вполне успешно используют для реализации большинства описанных здесь приколов Visual C++, что еще раз доказывает правильность взгляда в сторону универсального WinApi. А теперь пора бы и перейти к очередной партии компьютерных розыгрышей.

1. Простите, у вас монитор нормально работает? А сейчас?

Есть такой глюк, замечательный глюк, товарищи, который часто наблюдается на старых мониторах — выпадение цвета либо, наоборот, его чрезмерность. И, конечно же, что может быть приятнее, чем показать объекту розыгрыша всю несостоятельность покупки нового 17-дюймового LCD-монитора, красующегося на столе. Запускаем Borland Delphi, вешаем на форму таймер, задаем ему любой интервал на ваше усмотрение и пишем в обработчике:
procedure TForm1.Timer1Timer(Sender: TObject);
var
bmp: TBitmap;
DC: HDC;
begin
//инициализация переменной типа TBitmap
bmp:=TBitmap.Create;
//задание размеров битмапа
bmp.Height:=Screen.Height;
bmp.Width:=Screen.Width;
//получение контекста экрана
DC:=GetDC(0);
//копирование изображения экрана в нашу переменную
bitblt(bmp.Canvas.Handle, 0, 0,
Screen.Width, Screen.Height,
DC, 0, 0, SRCCOPY);
// вызов процедуры изменения битмапа
grad(bmp);
// копирование измененного изображения назад на экран
bitblt(dc, 0, 0, Screen.Width, Screen.Height,
bmp.Canvas.Handle, 0, 0, SRCCOPY);
end;

В этом коде мы получаем изображение с экрана, меняем его и возвращаем измененное изображение назад на экран. Нам осталось только написать саму процедуру изменения битмапа grad().

procedure Grad(var Bitmap:Tbitmap);
type
//создаем структуру трех составляющих цвета
TRGB = record
r,g,b: byte;
end;
//создаем указатель на эту структуру
ARGB = array[0..1] of TRGB;
PARGB = ^ARGB;
var x,y:integer;
p:PARGB;
b:Tbitmap;
begin
Bitmap.PixelFormat := pf24Bit;
//создаем временный битмап для работы
b:=Tbitmap.Create;
//помещаем туда наш основной передаваемый битмап
b.Assign(bitmap);
for y:=0 to b.Height-1 do
begin
//scanline работает с битмапом по линиям, а не по пикселям, что значительно ускоряет работу.
p := b.scanline[y];
for x := 0 to b.width — 1 do
begin
//устанавливаем синюю составляющую цвета всего происходящего на экране на максимум
p[x].b:=255
end;
end;
//возвращаем в передаваемый битмап измененную картинку
bitmap.Canvas.Draw(0,0,b);
end;

для исчезновения какого-либо цвета с экрана достаточно выставить вместо p[x].b:=255:

p[x].r:=0 — исчезновение красной составляющей цветов
p[x].g:=0 — исчезновение зеленой составляющей цветов
p[x].b:=0 — исчезновение синей составляющей цветов



Теперь немного усложним наш эффект и полюбуемся на градиентный переход цветовой составляющей. Для тех, кто с нами недавно, напоминаю, что градиент у нас — плавный переход из одного цвета в другой. Перепишем процедуру следующим образом:

procedure Grad(var Bitmap:Tbitmap);
type
//создаем структуру трех составляющих цвета
TRGB = record
r,g,b: byte;
end;
//создаем указатель на эту структуру
ARGB = array[0..1] of TRGB;
PARGB = ^ARGB;
//инициализация начальных переменных
var x,y:integer;
p:PARGB;
b:Tbitmap;
begin
Bitmap.PixelFormat := pf24Bit;
//создаем временный битмап для работы
b:=Tbitmap.Create;
//помещаем туда наш основной передаваемый битмап
b.Assign(bitmap);
for y:=0 to b.Height-1 do
begin
//scanline работает с битмапом по линиям, а не по пикселям, что значительно ускоряет работу.
p := b.scanline[y];
for x := 0 to b.width — 1 do
begin
//делаем плавное увеличение синей и уменьшение красной составляющей цветов
p[x].r:=((((b.width-x)*100) div b.width)*255) div 100;
p[x].b:=(((x*100) div b.width)*255) div 100;
end;
end;
//возвращаем в передаваемый битмап измененную картинку
bitmap.Canvas.Draw(0,0,b);
end;

Эффект получается просто шикарный. Впрочем, вы легко в этом убедитесь, просто скомпилировав вышеприведенный код.



А вот теперь попробуем действительно оживить рабочий стол, населив его мелкой копошащейся живностью. Попутно от этого копошения он непременно должен приобрести больной цвет лица, если, конечно, вы можете уверенно сказать, где у рабочего стола лицо:). Для этого выставьте Interval на таймере в 100 мсек и переписывайте процедуру grad() следующим образом:

procedure Grad(var Bitmap:Tbitmap);
type
//создаем структуру трех составляющих цвета
TRGB = record
r,g,b: byte;
end;
//создаем указатель на эту структуру
ARGB = array[0..1] of TRGB;
PARGB = ^ARGB;
//инициализация начальных переменных
var x,y:integer;
p:PARGB;
b:Tbitmap;
begin
Bitmap.PixelFormat := pf24Bit;
//создаем временный битмап для работы
b:=Tbitmap.Create;
//помещаем туда наш основной передаваемый битмап
b.Assign(bitmap);
for y:=0 to b.Height-1 do
begin
//scanline работает с битмапом по линиям, а не по пикселям, что значительно ускоряет работу.
p := b.scanline[y];
for x := 0 to b.width — 1 do
begin
//меняем случайным образом красную составляющую цвета
p[x].r:=random(255);
end;
end;
//возвращаем в передаваемый битмап измененную картинку
bitmap.Canvas.Draw(0,0,b);
end;

Каждые 100 мсек изображение на побледневшем от такого беспредела мониторе будет меняться, создавая эффект копошащихся точек и вызывая полное недоумение на лице противника.



Ну что ж, а пока жертва нашего розыгрыша трехэтажным мат... великим и могучим русским языком пытается как можно доходчивее объяснить продавцам монитора, что он с ними сделает, употребляя сложные для понимания технические термины, которым позавидовала бы группа “Ленинград”, мы едем дальше.

2. Лупа

Конечно же, все знают, что долгое сидение за компьютером крайне негативно сказывается на зрении сидящего, поэтому министерство здравоохранения последний раз предупреждает... Нам по статусу предупреждать никого не нужно, мы вполне можем помочь несчастному самостоятельно. Самое трудное за монитором — всматриваться в эти мелкие буковки, циферки, пиктограммки и прочее. Наверняка разработчики программного обеспечения заключили договоренность с производителями очков на поставку клиентов, т.е. нас с вами. Пора разрушить эту буржуйскую коалицию и встроить очки непосредственно в наш монитор. Вешаем на форму таймер, ставим его интервал в 100 мсек и пишем в обработчике:

procedure TForm1.Timer1Timer(Sender: TObject);
var
srcBitmap:TBitmap;
DC:HDC;
lp:Tpoint;
begin
//инициализация переменной битмапа
srcBitmap:=TBitmap.Create;
//задание начальных размеров битмапа для считывания
srcBitmap.Width:=20;
srcBitmap.Height:=20;
// получение контекста всего экрана
dc:=getdc(0);
//получение координат текущей позиции курсора мышки
getcursorpos(lp);
//считывание прямоугольника 20х20 под мышкой в битмап
BitBlt(SrcBitmap.Canvas.Handle, 0, 0,20,20, dc, lp.x, lp.y, SRCCOPY);
//изменение размеров прямоугольного изображения
resizebmp(srcbitmap,100,100);
//восстановление из битмапа на экран по центру экрана
BitBlt(dc,screen.Width div 2 — 50, screen.Height div 2 — 50,100,100, srcbitmap.Canvas.Handle, 0,0, SRCCOPY);
end;

Все, что нам остается добавить — процедура изменения размеров битмапа, которую я и привожу ниже:

Procedure ResizeBmp(var bitmp: TBitmap; nw, nh: Integer);
var
Tmp: TBitmap;
pRect: TRect;
begin
//инициализация дополнительного битмапа
Tmp := TBitmap.Create;
//установка его размеров
Tmp.Width := nw;
Tmp.Height := nh;
pRect := Rect(0,0, nw, nh);
//копирование основного битмапа в дополнительный с новыми размерами
Tmp.Canvas.StretchDraw(pRect, bitmp);
//присваивание дополнительного битмапа основному
bitmp.Assign(Tmp);
Tmp.Free;
end;

И теперь над всеми окнами будет висеть наш микроувеличитель, увеличивающий все, до чего дойдет курсор пользователя.



Засим позвольте откланяться, присылайте свои идеи розыгрышей и будем с вами вместе писать приколы и ждать весну. Пока.



Паша Либер aka Fireangel, Fireangel@tut.by

© компьютерная газета