Сохранение и выдача изображений


Функция ImageSize.
Возвращает размер памяти в байтах, необходимый для размещения прямоугольного фрагмента изображения. Заголовок:
Function ImageSize(X1,Y1,X2,Y2: Integer): Word;
Здесь X1... Y2 - координаты левого верхнего (X1, Y1) и правого нижнего (Х2, Y2) углов фрагмента изображения.
Процедура Getlmage.
Помещает в память копию прямоугольного фрагмента изображения. Заголовок:
Procedure Getlmage(X1,Y1,X2,Y2: Integer; var Buf)
Здесь X1...Y2 - координаты углов фрагмента изображения; Buf - переменная или участок кучи, куда будет помещена копия видеопамяти с фрагментом изображения.
Размер Buf должен быть не меньше значения, возвращаемого функцией ImageSize с теми же координатами X1....Y2.
Процедура Put Image.
Выводит в заданное место экрана копию фрагмента изображения, ранее помещенную в память процедурой Getlmage. Заголовок:
Procedure Putlmage(X,Y: Integer; var Buf; Mode: Word);
Здесь X,Y- координаты левого верхнего угла того места на экране, куда будет скопирован фрагмент изображения; Buf - переменная или участок кучи, откуда берется изображение; Mode - способ копирования.
Как видим, координаты правого нижнего угла не указываются, так как они полностью определяются размерами вновь выводимой на экран копии изображения. Координаты левого верхнего угла могут быть какими угодно, лишь бы только выводимая копия уместилась в пределах экрана (если копия не может разместиться на экране, она не выводится и экран остается без изменений).
Параметр Mode определяет способ взаимодействия вновь размещаемой копии с уже имеющимся на экране изображением. Взаимодействие осуществляется путем применения кодируемых этим параметром логических операций к каждому биту копии и изображения. Для указания применяемой логической операции можно использовать одну из следующих предварительно определенных констант:
const
NormalPut= 0;{Замена существующего изображения на копию}
XorPut = 1;{Исключительное ИЛИ}
OrPut = 2;{Объединительное ИЛИ}
AndPut = 3;{Логическое И} 
NotPut = 4;{Инверсия изображения}
Наиболее часто используются операции NormalPut, XORPut и NotPut. Первая из них просто стирает часть экрана и на это место помещает копию из памяти в том виде, как она там сохраняется. Операция NotPut делает то же самое, но копия выводится в инверсном виде. Для монохромного режима это означает замену светящихся пикселей на темные и наоборот. В цветном режиме операция NotPut применяется к коду цвета каждого пикселя. Например, для White (код 15 или в двоичном виде 1111) эта операция даст код 0000 = 0 = Black, для Red = 4 = 0100 получим 1011 = 11 = LightCyan и т.д. Операция XORPut, примененная к тому же месту экрана, откуда была получена копия, сотрет эту часть экрана. Если операцию применить дважды к одному и тому же участку, вид изображения на экране не изменится. Таким способом можно довольно просто перемещать изображения по экрану, создавая иллюзию движения.
Следующая программа рисует «Неопознанный Летающий Объект» - летающую тарелку на звездном фоне ( 10).
Рис.14.10. Иллюстрация процедур Getlmage/Putlmage
Uses Graph, CRT; 
const
r = 20; {Характерный размер НЛО} 
pause = 50; {Длительность паузы} 
var
d,m,e,xm/ym,x,y/lx,ly,rx,ry,
Size,i,dx,dy,Width,Height: Integer; 
Saucer : Pointer; 
label
loop; 
begin
{Инициируем графику} 
d := Detect; lnitGraph(d, m, ' ') ; 
e := GraphResult; if e <> grOk then
WriteLn(GraphErrorMsg(e)) 
else 
begin
x := r*5;
у := r*2;
xm := GetMaxX div 4;
ym := GetMaxY div 4;
{Создаем "тарелку" из двух эллипсов с усами антенн}
Ellipse (х,у,0,360,r,r div 3+2); ,
Ellipse (х,у-4,190,357,r,r div 3);
Line (х+7,у-б,х+10,у-12);
Line (x-7,y-6, х-10, у-12);
Circle (x+10,y-12,2);
Circle (х-10,у-12,2);
FloodFill(x+l,y+4,White);
{Определяем габариты НЛО и помещаем его в кучу}
1х := х-r-1;
1у := у-14;
гх := х+r+1;
гу := у+r div 3+3;
Width := rx - lx + 1;
Height:= ry - ly + 1;
Size := ImageSize(lx, ly, rx, ry);
GetMem (Saucer, Size);
Getlmage (lx, ly, rx, ry, Saucer^);
{Стираем построенное}
Putlmage (lx, ly, Saucer^, xorPut);
{Создаем звездное небо}
Rectangle(xm,ym,3 *xm,3 *ym);
SetViewPort(xm+1,ym+1,3*xm-1,3*ym-1,ClipOn);
xm := 2*xm;
ym := 2*ym;
for i:=1 to 200 do
PutPixe1 (Random(xm), Random(ym), White) ;
{Задаем начальное положение НЛО и направление движения}
х := xm div 2;
у := ym div 2;
dx := 10;
dy := 10;
{Основной цикл}
repeat
Putlmage(x,y,Saucer^,xorPut); {Изображаем НЛО на} 
Delay(pause); {новом месте и после} 
Putlmage (x, у, Saucer^, XorPut);{паузы стираем его} 
{Получаем новые координаты} 
loop: x := x+dx;
у := y+dy; 
{НЛО достиг границы экрана?} 
if (x<0) or (x+Width+1>xm) or 
(у<0) or (y+Height+1>ym) then 
begin {Да - НЛО достиг границы: меняем направление его перемещения} 
x := x-dx; 
y:= y-dy;
dx : = GetMaxX div 10 - Random(GetMaxX div 5); 
dy := GetMaxY div 30 - Random(GetMaxY div 15); 
goto loop 
end
until KeyPressed;
if ReadKey=#0 then x := ord(ReadKey); 
CloseGraph 
end 
end.
 
Вывод текста
Описываемые ниже стандартные процедуры и функции поддерживают вывод текстовых сообщений в графическом режиме. Это не одно и то же, что использование процедур Write или WriteLn. Дело в том, что специально для графического режима разработаны процедуры, обеспечивающие вывод сообщений различными шрифтами в горизонтальном или вертикальном направлении, с изменением размеров и т.д. Однако в стандартных шрифтах, разработанных для этих целей фирмой Borland, отсутствует кириллица, что исключает вывод русскоязычных сообщений.
С другой стороны, процедуры Write и WriteLn после загрузки в память второй половины таблицы знакогенератора (а эта операция легко реализуется в адаптерах EGA и VGA) способны выводить сообщения с использованием национального алфавита, но не обладают мощными возможностями специальных процедур.
Ниже описываются стандартные средства модуля Graph для вывода текста.
Процедура OutText.
Выводит текстовую строку, начиная с текущего положения указателя. Заголовок:
Procedure OutText(Txt: String);
Здесь Txt - выводимая строка.
При горизонтальном направлении вывода указатель смещается в конец выведенного текста, при вертикальном - не меняет своего положения. Строка выводится в соответствии с установленным стилем и выравниванием. Если текст выходит за границы экрана, то при использовании штриховых шрифтов он отсекается, а в случае стандартного шрифта не выводится.
Процедура OutTextXY.
Выводит строку, начиная с заданного места. Заголовок: 
Procedure OutTextXY (X,Y: Integer; Txt: String);
Здесь X, Y - координаты точки вывода; Txt - выводимая строка. Отличается от процедуры OutText только координатами вывода. Указатель не меняет своего положения.
Процедура SetTextStyle.
Устанавливает стиль текстового вывода на графический экран. Заголовок:
Procedure SetTextStyle(Font,Direct,Size: Word);
Здесь Font - код (номер) шрифта; Direct - код направления; Size - код размера шрифта.
Для указания кода шрифта можно использовать следующие предварительно определенные константы:
const
DefaultFont = 0;{Точечный шрифт 8x8}
TriplexFont = 1;{Утроенный шрифт TRIP.CHR} 
SmallFont = 2;{Уменьшенный шрифт LITT.CHR}
SansSerifFont = 3;{Прямой шрифт SANS.CHR}
GothicFont = 4;{Готический шрифт GOTH.CHR}
Замечу, что эти константы определяют все шрифты для версий 4.0, 5.0, 5.5 и 6.0. В версии 7,0 набор шрифтов значительно расширен, однако для новых шрифтов не предусмотрены соответствующие мнемонические константы. В этой версии помимо перечисленных Вы можете при обращении к SetTextStyle использовать такие номера шрифтов:


Номер

Файл

Краткое описание

5

scri.chr

«Рукописный» шрифт

6

simp.chr

Одноштриховый шрифт типа Courier

7

tscr.chr

Красивый наклонный шрифт типа Times Italic

8

Icom.chr

Шрифт типа Times Roman

9

euro . chr

Шрифт типа Courier увеличенного размера

10

bold.chr

Крупный двухштриховый шрифт

Шрифт DefaultFont входит в модуль Graph и доступен в любой момент. Это -единственный матричный шрифт, т.е. его символы создаются из матриц 8x8 пикселей. Все остальные шрифты - векторные: их элементы формируются как совокупность векторов (штрихов), характеризующихся направлением и размером. Векторные шрифты отличаются более богатыми изобразительными возможностями, но главная их особенность заключается в легкости изменения размеров без существенного ухудшения качества изображения. Каждый из этих шрифтов размещается в отдельном дисковом файле. Если Вы собираетесь использовать какой-либо векторный шрифт, соответствующий файл должен находиться в Вашем каталоге, в противном случае вызов этого шрифта игнорируется и подключается стандартный.
Замечу, что шрифт DefaultFont создается графическим драйвером в момент инициации графики на основании анализа текстового шрифта. Поэтому, если Ваш ПК способен выводить кириллицу в текстовом режиме, Вы сможете с помощью этого шрифта выводить русскоязычные сообщения и в графическом режиме. В остальных шрифтах эта возможность появляется только после их модификации.
Для задания направления выдачи текста можно использовать константы:
const
HorizDir = 0;{Слева направо}
VertDir = 1;{Снизу вверх}
Как видим, стандартные процедуры OutText и OutTextXY способны выводить сообщения лишь в двух возможных направлениях - слева направо или снизу вверх. Зная структуру векторных шрифтов, нетрудно построить собственные процедуры вывода, способные выводить сообщения в любом направлении.
Каждый шрифт способен десятикратно изменять свои размеры. Размер выводимых символов кодируется параметром Size, который может иметь значение в диапазоне от 1 до 10 (точечный шрифт - в диапазоне от 1 до 32). Если значение параметра равно 0. устанавливается размер 1, если больше 10 - размер 10. Минимальный размер шрифта. при котором еще отчетливо различаются все его детали, равен 4 (для точечного шрифта - 1).
Следующая программа демонстрирует различные шрифты. Их размер выбран так. чтобы строки имели приблизительно одинаковую высоту. Перед исполнением программы скопируйте все шрифтовые файлы с расширением .CHR в текущий каталог.
Uses Graph, CRT; 
const
FontNames: array [1..10] of String[4] =
( 'TRIP' , 'LITT'' SANS ' , ' GOTH ' , 'SCRI ' , ' SIMP ' ,'TSCR ' , ' LOOM ' , ' EURO',' BOLD ' );
Tabl = 50;
Tab2 = 150;
Tab3 =220; 
var
d, r, Err,{Переменные для инициации графики}
Y,dY,{Ордината вывода и ее приращение}
Size,{Размер символов}
MaxFont,{Максимальный номер шрифта}
k: Integer;{Номер шрифта}
NT, SizeT, SynibT: String;{Строки вывода}
c: Char;
 {-------------------}
Procedure OutTextWithTab ( S1, S2, S3, S4: String); 
{Выводит строки S1..S4 с учетом позиций табуляции Таb1..ТаbЗ} 
begin
MoveTo( (Tab1-TextWidth(Sl) ) div2,Y);
OutText (S1) ;
MoveTo(Tabl+(Tab2-Tabl-TextWidth(S2)) div2,Y);
OutText (S2) ;
MoveTo(Tab2+(Tab3-Tab2-TextWidth(S3)) div 2,Y); 
OutText(S3);
if S4='Symbols' then {Заголовок колонки Symbols} 
MoveTo((Tab3+GetMaxX-TextWidth(S4)) div 2,Y)
else {Остальные строки} 
MoveTo(Tab3+3,Y); 
OutText(S4) 
end;
{------------}
begin
{Инициируем графику} 
InitGraph(d,r, ' '); 
Err := GraphResult; if ErrogrOk then
WriteLn(GraphErrorMsg(Err)) 
else 
begin
{Определяем количество шрифтов:} 
{$IFDEF VER70'}
MaxFont := 10; . 
{$ELSE}
MaxFont := 4; 
{$ENDIF}
SetTextStyle(l,0,4); 
Y := 0;
OutTextWi thTab('N','Name',Size','Symbols');
{Определяем высоту Y линии заголовка}
Y := 4*TextHeight('Z') div3;

Line(0,Y,GetMaxX,Y) ;
{Определяем начало Y таблицы и высоту dY каждой строки}
Y := 3*TextHeight('Z') div 2;
dY := (GetMaxY-Y) div (MaxFont);
{Готовим строку символов}
SymbT := '';
for с := 'a' to 'z' do
SymbT := SymbT+c; 
{Цикл вывода строк таблицы} 
for k := 1 to MaxFont do 
begin
Size := 0;
{Увеличиваем размер до тех пор, пока высота строки не станет приблизительно равна dY} 
repeat
inc(Size);
SetTextStyle(k,0,Size+1); 
until (TextHeight('Z')>=dY) or (Size=10)
or (Textwidth(FontNames[k])>(Tab2-Tab1)); 
{Готовим номер NT и размер SizeT шрифта} 
Str(k,NT);
Str(Size,SizeT);
{Выводим строку таблицы}
SetTextStyle(k,HorizDir,Size);
OutTextWithTab(NT,FontNames[k],SizeT,SymbT);
inc(Y,dY) 
end;
{Рисуем линии рамки} 
Rectangle(0,0,GetMaxX,GetMaxY); 
Line(Tab1,0,Tabl,GetMaxY); 
Line(Tab2,0,Tab2,GetMaxY); 
Line(Tab3,0,ТаЬЗ,GetMaxY); 
{Ждем инициативы пользователя} 
ReadLn; 
CloseGraph
end 
end.
Процедура SetTextJustify.
Задает выравнивание выводимого текста по отношению к текущему положению указателя или к заданным координатам. Заголовок:
Procedure SetTextJustify(Horiz,Vert: Word);
Здесь Horiz - горизонтальное выравнивание; Vert - вертикальное выравнивание. Выравнивание определяет как будет размещаться текст - левее или правее указанного места, выше, ниже или по центру. Здесь можно использовать такие константы:
const
LeftText = 0;{Указатель слева от текста}
CenterText= 1;{Симметрично слева и справа,верху и снизу}
RightText = 2;{Указатель справа от текста}
BottomText= 0;{Указатель снизу от текста} 
TopText = 2;{Указатель сверху от текста}
Обратите внимание на неудачные, с моей точки зрения, имена мнемонических констант: если, например, Вы зададите LeftText, что в переводе означает «Левый Текст», сообщение будет расположено справа от текущего положения указателя (при выводе процедурой OutTextXY - справа от заданных координат). Также «наоборот» трактуются и остальные константы.
Следующая программа иллюстрирует различные способы выравнивания относительно центра графического экрана.
Uses Graph, CRT; 
var
d, r, e : Integer; 
begin
{Инициируем графику} 
d := Detect; InitGraph(d,, r, ' ') ; 
e := GraphResult;
if e <> grOk then 
WriteLn(GraphErrorMsg(e))
else 
begin
{Выводим перекрестие линий в центре экрана}
Line(0,GetMaxY div 2,GetMaxX,GetMaxY div 2);
Line(GetMaxX div 2,0,GetMaxX div 2,GetMaxY);
{Располагаем текст справа и сверху от центра}
SetTextStyle(TriplexFont,HorizDir,3);
SetTextJustify(LeftText,BottomText);
OutTextXY (GetMaxX div 2, GetMaxY div 2, 'LeftText,BottomText');
{Располагаем текст слева и снизу}
SetTextJustify (RightText, TopText);
OutTextXY (GetMaxX div 2, GetMaxY div 2,'RightText, TopText'); 
if ReadKey=#0 then d := ord(ReadKey);
CloseGraph 
end 
end.
Процедура SetUserCharSize.
Изменяет размер выводимых символов в соответствии с заданными пропорциями. Заголовок:
Procedure SetUserCharSize(XI,X2,Yl,Y2: Word);
Здесь X1...Y2 - выражения типа Word, определяющие пропорции по горизонтали и вертикали.
Процедура применяется только по отношению к векторным шрифтам. Пропорции задают масштабный коэффициент, показывающий во сколько раз увеличится ширина и высота выводимых символов по отношению к стандартно заданным значениям. Коэффициент по горизонтали находится как отношение X1 к Х2, по вертикали - как отношение Y1 к Y2. Чтобы, например, удвоить ширину символов, необходимо задать X1=2 и Х2=1. Стандартный размер символов устанавливается процедурой SetTextStyle, которая отменяет предшествующее ей обращение к SetUserCharSize.
В следующем примере демонстрируется изменение пропорций уменьшенного шрифта.
Uses Graph, CRT; 
var
d, r, e : Integer; 
begin
{Инициируем графику}
d := Detect; .InitGraph (d, r, '');
e := GraphResult;
if e <> grOk then
WriteLn(GraphErrorMsg(e)) 
else 
begin
MoveTo (0, GetMaxY div 2); SetTextStyle (SmallFont, HorizDir, 5);
SetTextJustify (LeftText, BottomText);
{Выводим сообщение стандартной высотой 5}
OutText ('Normal Width,');
{Удваиваем ширину шрифта}
SetUserCharSize (2, 1, 1, 1);
OutText (' Double Width, ');
{Удваиваем высоту, возвращаем стандартную ширину}
SetUserCharSize (I, 1, 2, 1) ;
OutText ('Double Height,');
SetUserCharSize (2, 1, 2, 1) ;
OutText (' Double Width and Height');
if ReadKey=#0 then d := ord(ReadKey);
CloseGraph
end
end.
Функция TextWidth.
Возвращает длину в пикселях выводимой текстовой строки. Заголовок:
Function TextWidth (Txjt: String): Word;
Учитываются текущий стиль вывода и коэффициенты изменения размеров символов, заданные соответственно процедурами SetTextStyle и SetUserCharSize.
Функция TextHeight.
Возвращает высоту шрифта в пикселях. Заголовок: 
Function TextHeight(Txt: String): Word;
Процедура GetTextSettings.
Возвращает текущий стиль и выравнивание текста. Заголовок:
Procedure GetTextSettins(var Textlnfo: TextSettingsType);
Здесь Textlnfo - переменная типа TextSettingsType, который в модуле Graph определен следующим образом:
type
TextSettingsType = record
Font : Word; {Номер шрифта}
Direction: Word; {Направление}
CharSize : Word; {Код размера}
Horiz : Word; {Горизонтальное выравнивание}
Vert : Word; {Вертикальное выравнивание}
end;
Функция InstallUserFont.
Позволяет программе использовать нестандартный векторный шрифт. Заголовок функции:
Function InstallUserFont(FileName: String): Integer; 
Здесь FileName - имя файла, содержащего векторный шрифт.
Как уже говорилось, в стандартную поставку Турбо Паскаля версий 4.0 - 6.0 включены три векторных шрифта, для версии 7.0 - 10. Функция InstallUserFont позволяет расширить этот набор. Функция возвращает идентификационный номер нестандартного шрифта, который может использоваться при обращении к процедуре SetTextStyle.
Функция InstallUserDriver.
Включает нестандартный графический драйвер в систему BGI-драйверов. Заголовок функции:
Function InstallUserDriver(FileName: String; AutoDetectPtr: Pointer): Integer;
Здесь FileName - имя файла, содержащего программу драйвера; AutoDetectPtr - адрес точки входа в специальную процедуру автоопределения типа дисплея, которая в числе прочих процедур должна входить в состав драйвера.
Эта функция расширяет и без того достаточно обширный набор стандартных графических драйверов и предназначена в основном для разработчиков аппаратных средств.
 
Включение драйвера и шрифтов в тело программы
В Турбо Паскале имеется возможность включения графического драйвера и штриховых шрифтов непосредственно в тело программы. Такое включение делает программу независимой от местоположения и наличия на диске драйверов и шрифтов, а также ускоряет подготовку графических программ к работе (шрифты и драйвер загружаются вместе с программой).
Включение драйвера и шрифтов осуществляется по следующей общей схеме. Сначала с помощью вспомогательной программы BINOBJ.EXE, входящей в комплект поставки Турбо Паскаля, драйвер и шрифты преобразуются в OBJ-файл (файл с расширением .OBJ). Для этого вне среды Турбо Паскаля необходимо вызвать утилиту BINOBJ с тремя параметрами: именем преобразуемого файла, именем получаемого OBJ-файла и глобальным именем процедуры. Эти имена, в принципе, могут быть произвольными, правильными для MS-DOS именами. Например:
c:\tp\binobj cga.bgi cga cgadrv
В результате такого обращения из каталога ТР на диске С будет вызвана программа BINOBJ и ей будут переданы следующие параметры:
CGA.BGI - имя файла с преобразуемым драйвером;
CGA - имя файла с расширением .OBJ, т.е. CGA.OBJ, который будет получен в результате исполнения программы BINOBJ;
CGADRV- глобальное имя, под которым этот драйвер будет известен программе.
После этого можно написать следующий фрагмент программы:
Uses Graph;
Procedure CGADRV; external; 
{$L CGA.OBJ} 
var
d, r, e : Integer; 
begin
if RegisterBGIDriver (@CGADRV) < 0 then
begin
WriteLn ('Ошибка при регистрации драйвера');
halt 
end;
d := CGA; r := CGAHi; 
InitGraph (d, r, '');
.......
Как видно из этого примера, в программе объявляется внешняя процедура с именем CGADRV (глобальное имя, указанное при обращении к BINOBJ), причем дается директива компилятору отыскать в текущем каталоге и загрузить файл CGA.OBJ, в котором находится эта процедура. Затем осуществляется регистрация драйвера путем обращения к функции RegisterBGIDriver. Единственным параметром этой функции является адрес начала драйвера в памяти (@CGADRV). Функция возвращает значение типа Integer, которое служит для контроля правильности завершения процедуры регистрации драйвера: если это значение меньше нуля, обнаружена ошибка, в противном случае функция возвращает номер зарегистрированного драйвера. В примере контролируется правильность регистрации драйвера и, если ошибка не обнаружена, инициируется графический режим работы экрана.
Аналогичным образом можно присоединить к программе стандартные штриховые шрифты (матричный шрифт 8x8 входит в состав модуля Graph и поэтому присоединять его не надо). Присоединение шрифта строится по описанной схеме за тем исключением, что для его регистрации вызывается функция RegisterBGIFont. Например, после преобразования 
c:\Pascal\binobj litt.chr litt litt
можно использовать операторы
Procedure Litt;External;
{$L Litt.obj}
.......
if RegisterBGIFont (@litt) < 0 then ...
Обратите внимание: регистрация и драйвера, и шрифтов должна предшествовать инициации графического режима.
Регистрировать можно также драйверы (шрифты), которые не компилируются вместе с программой, а загружаются в динамическую память. Например:
Uses Graph; 
var
р: Pointer; 
f: file; 
begin
Assign(f,'Litt.chr'); {Открываем файл} 
Reset(f,1); {LITT.CHR для чтения} 
GetMem(p,FileSize(f)) ; {Резервируем для него область кучи нужного размера}
BlockRead(f,pA,FileSize(f)){Читаем файл}
WriteLn(RegisterBGIFont (p)){Регистрируем шрифт}
end.

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика