Графические устройства



 

Программный знакогенератор

В данном разделе будет описана подпрограмма, которая по коду ASCII выбирает из таблицы соответствующую заготовку и рисует изображение символа на экране. В технической литературе для обозначения подобных подпрограмм используется термин "программный знакогенератор". Подпрограмма будет предназначена для выполнения в видеорежимах PPG. Однако, учитывая ее значимость, мы специально обсудим те изменения, которые позволят выводить текст при работе в видеорежимах direct color.

Общая характеристика знакогенератора

Структура заготовки символа (см. рис. 5.1) ничем не отличается от структуры упакованного двухцветного рисунка. Способ построения строки такого рисунка был показан в примере 3.18 раздела. Особенности построения небольших рисунков обсуждались в разделе, а соответствующая подпрограмма приведена в примере 3.21. Нам остается объединить эти примеры и учесть следующие обстоятельства.

В отличие от рисунка заготовка символа хранится не в файле, а в таблице символов и знакогенератор должен самостоятельно вычислять адрес ее начала в оперативной памяти. Для этого ему нужны следующие величины: адрес начала таблицы, ширина и высота символа (размер знакоместа для размещения символа) и код ASCII. Мы ограничимся случаями, когда ширина символов составляет 8 точек, т. е. подпрограмма рассчитана на стандартные таблицы символов. Адрес таблицы и высота символов будут находиться в специальных переменных, расположенных в разделе данных задачи.
К рисунку прилагается палитра, содержащая описание использованных в нем цветов. Таблица символов не содержит палитры. В зависимости от состояния текущего бита, знакогенератор выбирает код одного из двух заранее задаваемых цветов, они могут различаться для каждого символа.

При работе в текстовых режимах аппаратный знакогенератор выбирает коды цветов точек изображения символа (foreground) и фона (background) из байта атрибута, находящегося в видеопамяти (см. раздел). В нем можно закодировать 16 разных цветов foreground и 8 цветов background, коды которых соответствуют стандартной палитре CGA (см. табл. 4.2).

При работе в графических режимах для каждого выводимого символа указываются коды цветов точек его изображения и фона. В режимах PPG кодами являются номера регистров цвета видеокарты, содержащих нужные цвета. В режимах direct color это коды самих цветов, имеющие размер слова (Hi-Color) или двойного слова (True Color). В зависимости от используемого видеорежима в разделе данных задачи надо зарезервировать два байта, два слова или два двойных слова, содержащие цвета для раскрашивания изображения символов и окружающего их фона.

Новые переменные

Для того чтобы знакогенератор мог выбрать заготовку рисунка символа из таблицы и раскрасить ее в нужные цвета, в разделе данных задачи должны располагаться переменные, приведенные в примере 5.18.

Пример 5.18. Аргументы программного знакогенератора

ftaddr dd 00 ; полный адрес таблицы символов
hsymb dw 16 ; высота символа (размер заготовки в байтах)
augment dw 00 ; ! ! константа переадресации строк рисунка символа
grndcol db OFFh ; !! код цвета точек фона, окружающего символ
symbcol db 00 ; !! код цвета точек контура символа

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

Высота символов обычно известна заранее и указывается в исходном тексте программы. Напомним, что стандартные таблицы содержат символы высотой 8, 14 или 16 строк. В тех случаях, когда планируется работа с символами разной высоты, вам придется предусмотреть запись ее значения в переменную hsymb.

Переменная augment содержит величину, которая добавляется к текущему адресу видеопамяти для перехода в начало следующей строки рисунка символа. Напомним, что в режимах PPG она выражается в точках и вычисляется как разность между шириной рабочего поля экрана и шириной рисунка. Если установлен режим с разрешением 640x480 точек, то при ширине символа В 8 точек значение augment = horsize - 8 = 640 - 8 = 632.

В примере 5.18 значения переменных grndcol и symbcol выбраны исходя из предположения, что символы изображаются черным цветом на белом фоне и что коды черного и белого цветов находятся в DAC-регистрах видеокарты с номерами 00 и 0FFh. Например, именно их используют Windows и ее приложения при работе с текстом. В общем же случае значения указанных переменных зависят от того, в каких регистрах видеокарты расположены коды нужных вам цветов.

Подпрограмма знакогенератора. Текст подпрограммы знакогенератора приведен в примере 5.19. Перед обращением к ней код ASCII выводимого на экран символа помещается в регистр ai. В di записывается адрес видеопамяти для размещения кода точки левого верхнего угла изображения символа. Переменная cur_win содержит окно видеопамяти, которому принадлежит адрес, указанный в di. Предварительная установка окна не требуется. Как обычно при работе с графикой, в регистре ез должен находиться сегмент видеобуфера (значение переменной vbuff). Остальные параметры задаются неявно, это переменные примера 5.18. После выполнения подпрограммы регистр di содержит адрес начала следующего символа, а переменная cur_win — окно, к которому относится этот адрес.

Пример 5.19. Подпрограмма рисования символов шириной в 8 точек

outsgn: PushReg <ax,bx, ex, fs, si,di> ; сохранение используемых регистров
call Setwin установка исходного окна
push Cur win сохранение номера исходного окна
Ifs si, ftaddr; fs si = адрес таблицы символов
mov ex, hsymb; ex = количество строк рисунка
xor ah, ah очистка байта ah
mul cl смещение рисунка в таблице (ax*cl)
add si, ax полный адрес рисунка символа
; Построение изображения символа (внешний цикл)
out ext mov bh, f s : [si]; bh = код текущей строки таблицы
inc si адрес следующей строки таблицы
mov Ы, 8 Oh константа выделения (и счетчик)
; Построение текущей строки рисунка (внутренний цикл)
out int mov al, grndcol; ! al = цвет точки окружающего фона
test bh, Ы текущий бит установлен ?
jz @F => нет, на запись кода точки
mov al, symbcol; ! al = цвет точки контура символа
@@: stosb ! ! запись кода в видеопамять
or di, di достигнута граница сегмента ?
jne @F => нет
call Nxtwin установка следующего окна
@@: shr bl, 01 сдвиг константы выделения
jne out int управление внутренним циклом
add di , augment адрес следующей строки рисунка
jne @F => адрес в пределах окна
call Nxtwin установка следующего окна
@@: loop out ext управление внешним циклом
pop Cur win исходный номер окна
pop di восстановление исходного адреса
add di, 08 ! ! адрес для следующего символа
jne @F => адрес в пределах окна
mov ax, GrUnit константа для коррекции окна
add Cur win, ax вычисляем значение нового окна
@@: PopReg <si, fs, cx,bx, ах> ; восстанавливаем регистры
ret конец подпрограммы

Выполнение примера 5.19 начинается с сохранения в стеке содержимого используемых регистров. После этого устанавливается окно видеопамяти, в которое будет выводиться символ, и значение cur_win сохраняется в стеке, т. к. оно может измениться в процессе рисования символа.

Команда ifs загружает младшее слово ftaddr в регистр si, а старшее — в сегментный регистр fs, в результате пара регистров fs:si содержит адрес таблицы символов в оперативной памяти. После этого в сх записывается количество строк в рисунке символа. Эта величина определяет количество повторов внешнего цикла, она же используется при вычислении адреса начала заготовки символа в таблице. При умножении кода символа ASCII на высоту рисунка (ci) в регистре ах получается смещение заготовки символа, оно прибавляется к адресу начала таблицы, в результате чего в регистре si получается адрес первого байта заготовки рисунка символа.
Основные действия выполняют два вложенных цикла. Внешний имеет имя out_ext и начинается с чтения в регистры кода очередного байта заготовки изображения символа. После чтения адрес, находящийся в регистре si, увеличивается на 1. В ьь записывается константа выделения разрядов кода (80h) и начинается выполнение внутреннего цикла.

Внутренний цикл имеет имя out_int. В нем, начиная со старшего, последовательно выделяются биты строки, хранящейся в регистре ы. В зависимости от состояния текущего бита в ai записывается значение переменной grndcol или symbcol, затем оно копируется в видеопамять командой stosb. Константа выделения смещается на разряд вправо и если она не равна нулю, то внутренний цикл повторяется.

После построения текущей строки продолжается выполнение внешнего цикла. При этом формируется адрес байта видеопамяти, соответствующий началу следующей строки, и команда loop повторяет выполнение внешнего цикла, пока не будут нарисованы все строки.

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

После выхода из внешнего цикла из стека восстанавливаются значение исходного окна и адрес видеопамяти, который увеличивается на ширину символа. Если при этом произойдет выход за границу сегмента, то увеличивается номер окна. Для этого к нему прибавляется значение переменной Grunit (см. раздел). Перед возвратом из подпрограммы восстанавливается сохраненное в стеке исходное содержимое регистров.

Отметим, что при однократном обращении к знакогенератору не обязательно вычислять позицию следующего символа. Однако при выводе связного текста такие вычисления необходимы, и удобнее их делать именно в знакогенераторе.

Описанная подпрограмма рассчитана на выполнение в режимах PPG. Для того чтобы при описании режимов direct color не возвращаться к программированию знакогенератора, покажем, что надо изменить для его использования в этих видеорежимах. В примерах 5.18 и 5.19 комментарий к изменяемым командам отмечен двумя восклицательными знаками.

Изменения для режимов Hi-Color

В режимах Hi-color код точки занимает слово (два байта), а код цвета содержит 15 или 16 разрядов этого слова.

В пример 5.18 вносятся следующие изменения. Значение переменной augment надо вычислять по формуле (horsize - 8)*2. Переменные grndcol и symbcol описываются директивой dw как слова (а не как байты), а их содержимое (цвет) кодируется так, как описано в главе 7.

В тексте примера 5.19 изменяемые команды будут выглядеть так:

out_int:mov ax, grndcol; !! ах = цвет точки окружающего фона
mov ax, symbcoi ; !! ах = цвет точки контура символа
stosw ; !! запись кода в видеопамять
add di, 16 ; !! адрес для следующего символа

Изменения для режимов True Color

В этих режимах код точки занимает двойное слово (четыре байта), а код цвета — 24 разряда этого слова.

В примере 5.18 значение переменной augment вычисляется по формуле (horsize - 8)*4. Переменные grndcol и symbcol описываются директивой dd как двойные слова, а их содержимое (цвет) кодируется так, как описано в главе 7.

В тексте примера 5.19 изменяемые команды будут выглядеть так:

out_l: mov eax, grndcol ; ! ! еах = цвет точки окружающего фона
mov eax, symbcoi ; ! ! еах = цвет точки контура символа
out_2: stosd ; ! ! запись кода в видеопамять
add di, 32 ; !! позиция для следующего символа

Подчеркнем, что в примере 5.19 заменять надо только те команды, комментарий для которых начинается с двух восклицательных знаков, не нарушая общей последовательности команд.

Рассмотренный вариант знакогенератора работает с символами, ширина которых составляет 8 точек. Для того чтобы подпрограмма примера 5.19 выводила символы шириной в 16 точек, код строки можно считывать в регистр bx, а константу выделения хранить в dx, ее исходное значение зоооь. Наконец, можно усложнить знакогенератор так, чтобы он выводил символы переменной ширины. Об этом следует поговорить особо.

Пропорциональные шрифты

В рукописном тексте символы имеют разную ширину. Такая форма записи текста привычна для человеческого глаза, поэтому она применяется при оформлении печатной продукции различного назначения. Все текстовые редакторы позволяют использовать при подготовке документов пропорциональные шрифты. Свое название они получили потому, что при размещении на экране (или на бумаге) выделяется место, пропорциональное ширине символа. Например, для размещения символа достаточно четырех столбцов, а для буквы щ их надо намного больше.

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

Для вывода пропорциональных символов вам придется составить специальный знакогенератор. Его основные отличия от описанного в примере 5.19 заключаются в следующем:

  • во внешнем цикле, кроме адреса начала заготовки символа, надо определять его ширину, которая хранится в отдельном массиве, прилагаемом к таблице;
  • количество повторов внутреннего цикла равно ширине символа, поэтому для управления его повторами придется использовать счетчик;
  • исходный код константы выделения зависит от размера строки, например если она занимает 1 слово, то код константы равен 8000h;
  • после построения рисунка при вычислении адреса позиции следующего символа, содержимое регистра di надо увеличивать не на восемь, а на ширину нарисованного символа.

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

Масштабируемые шрифты

Область применения таблиц ограничена тем, что в них хранятся готовые точечные (растровые) рисунки символов. Изменить размер такого рисунка, а тем более повернуть его без ущерба для качества изображения, достаточно сложно. Кроме того, рисунки рассчитаны на определенное разрешение устройства вывода: чем оно выше, тем больше точек должен содержать рисунок при том же размере символа. Разрешение современных принтеров превышает 1000 точек на дюйм, поэтому размеры таблиц, используемых при печати текста, будут очень большими. Пожалуй, именно стремление получать высококачественную печать текста стимулировало разработку масштабируемых шрифтов.

Идея заключается в том, чтобы использовать безразмерную заготовку, которую при выводе можно преобразовать в точечный рисунок конкретного размера, расположенный под заданным углом. Масштабируемые шрифты различаются по способу описания заготовки символа. В настоящее время наибольшее распространение получили шрифты форматов PostScript и True Type. Postscript — это язык программирования печатающих устройств. Первый интерпретатор этого языка для лазерных принтеров был разработан Adobe Systems inc. Позже появилась возможность вывода символов шрифтов PostScript на экран. True Type — это масштабируемые шрифты, стандарт на которые был разработан Microsoft для Windows и ее приложений. В настоящее время существует множество шрифтов, подготовленных в формате True туре и содержащих символы различного начертания (Typeface) и/или специальные значки. Однако при компьютерной верстке предпочтение отдается языку Postscript. В этом случае можно создать файл (а не распечатку) готового документа, структура которого не зависит от разрешающей способности принтера. Его можно преобразовать в нужную для размножения документа форму на специализированном типографском оборудовании.

Рассмотрение программирования вывода масштабируемых шрифтов выходит за рамки данной книги, поэтому мы заканчиваем их краткую характеристику и переходим к следующему разделу.

 
Назад Начало Вперед