ПОИСК
Категории книг
ОПРОС
Вопрос: Какой язык программирования вы предпочитаете
С/C++
Delphi
Visual Basic
Perl
Java
PHP
ASP
Другой
ЭТО ПОЛЕЗНО!
ОБРАТНАЯ СВЯЗЬ

/ Главная / Программирование / Иллюстрированный самоучитель по SVGA
Иллюстрированный самоучитель по SVGA

 

Воспроизведение не сжатых рисунков

Строки образа рисунка могут храниться в файле в прямом или обратном порядке. В первом случае они расположены по возрастанию номеров, т. е. сначала в файле записаны точки первой строки, затем второй и так вплоть до последней. Во втором случае они расположены по убыванию номеров, т. е. сначала в файле записаны точки последней строки, затем предпоследней и так до первой строки. Первый способ хранения образа рисунка применяется, например, в файлах, соответствующих стандарту PCX, а второй — в файлах, соответствующих стандарту BMP. Распознать принадлежность файла к этим стандартам можно по их типу (расширению), который совпадает с названием стандарта. Например, файл ieaves.bmp подготовлен в стандарте BMP.

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

Построение рисунка небольшого размера. Важной характеристикой, влияющей на выбор варианта построения рисунка, является его размер. В первую очередь нас будут интересовать такие рисунки, образ которых помещается в одном сегменте оперативной памяти, т. е. их размер не превышает 65 536 байт. Этому требованию удовлетворяет большинство рисунков, предназначенных для оформления рабочей области экрана. В частности, стандартные пиктограммы занимают на экране квадрат размером 32x32 точки.

Текст подпрограммы, выполняющей построение рисунка, образ которого целиком помещается в одном сегменте оперативной памяти, а строки расположены в естественном порядке, приведен в примере 3.21. Перед обращением к подпрограмме должно быть установлено окно видеопамяти, содержащее левый верхний угол рисунка, а адрес этого угла указан в регистрах es:di. Адрес начала образа рисунка в оперативной памяти задает пара fs:si. В регистрах dx и сх указываются ширина и высота рисунка.

Пример 3.21. Работа с прямоугольной областью небольшого размера

draw:
PushReg
<di, si, cx,b>
;,Cur win>; сохранение исходных величин
mov
bx, horsize
; копируем в bx значение horsize
sub
bx, dx
; и вычитаем из него ширину рисунка
drwout:
push
ex
сохраняем счетчик повторов
mov
ex, dx
задаем размер строки рисунка
call
drawline
! ! или call bp, пояснения в тексте
pop
ex
восстанавливаем счетчик повторов
add
di , bx
адрес начала следующей строки
jnc
@F
-> адрес в пределах сегмента
call
NxtWin
установка следующего окна
@@:
loop
drwout
управление повторами цикла
PopReg
<Cur win,bx,
cx,si,di>; восстановление исходных величин
call
setwin
восстановление исходного окна
ret
возврат из подпрограммы

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

Выполнение примера 3.21 начинается с сохранения в стеке тех величин, которые могут измениться в процессе построения. Затем две команды формируют константу для переадресации строк. Ее назначение обсуждалось в разделе 3.2.2 перед описанием примера 3.13.

Цикл построения рисунка имеет имя drwout. Он начинается с сохранения в стеке значения счетчика повторов (регистра сх) и записи в него размера строки. Затем происходит вызов подпрограммы drawiine для вывода на экран очередной строки рисунка. После возврата из подпрограммы восстанавливается сохраненное в стеке значение счетчика повторов и вычисляется адрес начала следующей строки. Если при сложении будет получен признак переполнения, то произойдет обращение к подпрограмме Nxtwin для установки следующего окна видеопамяти. Последняя команда цикла loop повторяет его выполнение до тех пор, пока не будут построены все строки рисунка.

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

Выбор вспомогательной подпрограммы

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

Лучше всего его задавать в регистре Ьр, в виде адреса нужной подпрограммы, а в тексте примера 3.21 вместо команды call drawiine записать call bp, как это указано в комментарии. Если вспомогательные подпрограммы
включены в текст задачи, то для формирования адреса используется команда lea, например:

lea bp, drawline ; для рисования 256-цветных рисунков
lea bp, drwlin4 ; для рисования 16-цветных рисунков
lea bp, drwlinl ; для рисования двухцветных рисунков
lea bp, horline ; для закрашивания прямоугольной области

Таким образом, мы получили универсальную процедуру, позволяющую:

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

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

Особенности работы с большими рисунками

Большие рисунки не помешаются в одном сегменте оперативной памяти, и их приходится считывать и выводить на экран по частям. В этом случае при построении основное время затрачивается не на рисование строк, а на чтение данных из файла в оперативную память. Очевидно, что чем больше размер порции данных, считываемых за одно обращение к файлу, тем меньше повторных обращений к процедуре чтения и тем быстрее будет построен рисунок. Стандартные средства DOS, например функция 3Fh прерывания int 2ih, позволяют прочитать за одно обращение к диску от 1 до 65 535 байт. Однако считывать каждый раз по 65 535 байтов не рационально, и вот почему.

Размер считываемой порции

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

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

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

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

SwpOf fs
dw 0
адрес (смещение) в буфере обмена
SwpSeg
dw 0
значение сегмента, содержащего буфер обмена
iwidth
dw 0
ширина строки рисунка
iheight
dw 0
количество строк в рисунке
numbyte
dw 0
количество байтов в считываемой порции данных
part
dw 0
количество строк в считываемой порции данных
remline
dw 0
остающееся не выведенным количество строк

Переменные Swpoffs и Swpseg указывают полный адрес буфера обмена, в который считываются данные из файла. Как резервируется пространство оперативной памяти, описано в приложении Б данной книги. Значения переменных iwidth и iheight получаются при обработке заголовка файла, содержащего образ строящегося рисунка. Значения переменных numbyte, part и remline формирует сама подпрограмма BigDraw.
Текст подпрограммы, выполняющей построение рисунка произвольного размера, приведен в примере 3.22. Перед ее вызовом в регистре di надо указать адрес левой верхней точки рисунка в видеопамяти и установить окно, которому принадлежит этот адрес. Напоминаем, что регистр es должен содержать код видеосегмента (содержимое переменной vbuff).

Пример 3.22. Построение рисунка произвольного размера

SwpOf fs
dw 0
адрес (смещение) в буфере обмена
SwpSeg
dw 0
значение сегмента, содержащего буфер обмена
iwidth
dw 0
ширина строки рисунка
iheight
dw 0
количество строк в рисунке
numbyte
dw 0
количество байтов в считываемой порции данных
part
dw 0
количество строк в считываемой порции данных
remline
dw 0
остающееся не выведенным количество строк
jnc sucread
-> чтение без ошибок
i
Здесь должны выполняться действия при ошибке чтения
sucread:
mov ex, part
сх = стандартное количество строк
cmp remline, ex
осталось меньше строк ?
jae @F
-> нет, обходим команду пересылки
mov ex, remline
сх = оставшееся число строк
@@:
sub remline, ex
уменьшаем оставшееся число строк
xor si, si
адрес начала в буфере обмена
drwout :
push ex
сохраняем счетчик повторов
mov ex, iwidth
задаем размер строки рисунка
call drawline
построение очередной строки
pop ex
восстанавливаем счетчик повторов
add di , bx
адрес начала следующей строки
jnc @F
-> адрес в пределах сегмента
call NxtWin
установка следующего окна
@@:
loop drwout
управление повторами цикла
cmp remline, 0
все строки выведены ?
jne NewPart
-> нет, продолжаем построение
PopReg <Cur win, fs>
восстановление Cur win и fs
popa
восстановление всех регистров
call setwin
восстановление исходного окна
ret
возврат из подпрограммы

Выполнение подпрограммы примера 3.22 начинается с подготовительных действий. Две первые команды сохраняют в стеке содержимое используемых регистров и значение переменной Cur_win. Затем в регистр fs помещается сегмент буфера обмена, а переменная Swpoffs очищается для расположения считываемых из файла данных с начала буфера обмена. Следующие восемь команд формируют значение переменных part, numbyte, и remline, последняя является счетчиком еще не выведенных строк, поэтому ее исходное содержимое равно высоте рисунка. Остается сформировать в регистре bx константу horsize — iwidth для коррекции адресов строк в видеопамяти.
Построение рисунка выполняют два вложенных цикла. Внешний имеет метку NewPart, а внутренний — drwout. Во внешнем цикле производится чтение из файла очередной порции данных, уточнение размера прочитанной порции (содержимого регистра сх), оставшегося количества строк (переменная remline) и очистка регистра si. После этого выполняется внутренний цикл, выводящий на экран прочитанную порцию строк.

Внутренний цикл полностью совпадает с аналогичным циклом примера 3.21, поэтому мы опустим его описание.

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

Подпрограмма чтения с диска. Во внешнем цикле происходит обращение к подпрограмме Readf. Она считывает в буфер обмена порцию данных, размер которой (в байтах) задается в регистре сх. Ниже (см. пример 3.23) приведен один из возможных примеров такой подпрограммы.

Пример 3.23. Чтение фрагмента файла в буфер обмена

Readf: PushReg <bx,dx,ds> ; сохраняем в стеке bx и ds
mov bx, handler ; указываем заголовок файла
Ids dx, dword ptr SwpOffs; задаем адрес буфера для чтения
mov ax, 3FOOh ; код функции DOS "чтение файла"
int 21h ; обращение к DOS
PopReg <ds,dx,bx> ; восстанавливаем из стека bx и ds
ret ; возврат из подпрограммы

В примере 3.23 адрес буфера обмена выбирается из переменных SwpOffs и swpseg, описанных выше. Если при чтении данных возникнет ошибка, то после возврата из int 2in и из подпрограммы будет установлен С-разряд регистра флагов (признак переполнения). При успешном чтении DOS возвращает в регистре ах размер прочитанной порции данных в байтах. Если при чтении обнаружен конец файла, то эта величина может быть меньше указанной в регистре сх.

В примере 3.23 используется еще одна переменная handler, содержащая ссылку на файл (file handle). Эту величину формирует DOS при открытии файла по указанной спецификации и передает задаче в регистре ах. Ее надо сохранить, например в переменной handler и использовать при дальнейшей работе с файлом.

Способ открытия файла для чтения описан в приложении А в примере А. 1. Для получения более подробной информации на эту тему рекомендуем обратиться к электронной справочной системе Tech Help, или к любому руководству по программированию MS DOS.

Рисунок не помещается на экране

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

Прежде чем обрезать рисунок, имеет смысл определить его размеры. Возможно, что вам попалась одна из заставок, предназначенная для вывода при высоком разрешении, например 800x600 или 1280x1024 точки. Если вас устраивает работа в таких видеорежимах, то проблемы не существует, достаточно просто устанавливать в задаче нужный видеорежим.

Обрезать рисунок можно и в процессе его построения. Если ширина рисунка превосходит Horsize, то при построении строк в видеопамять записывается ровно Horsize точек, а остатки отбрасываются. Если высота рисунка превосходит versize, то выводится ровно versize строк, а остальные отбрасываются. Изменить подпрограмму построения рисунка не сложно, вопрос в том, целесообразно ли это делать?

Более гибкий способ заключается в принудительном изменении размера сканируемой строки (scaniine). Эта величина задает количество точек, после вывода которых видеоконтроллер переходит на новую строку. После установки видеорежима scaniine и Horsize равны. В разделе описана функция BIOS 4F06h, которая позволяет установить нужное значение Scaniine, но не меньшее чем Horsize. Если Scaniine > Horsize, то в процессе отображения каждой строки видеоконтроллер выводит на экран Horsize точек, а остальные (scaniine — Horsize) пропускает.

Поэтому можно просто копировать рисунок в видеопамять, предварительно установив значение scaniine равным его ширине. После построения на экране будет видна левая верхняя часть рисунка, размер которой равен Horsize Versize. Только не забывайте, что Изменение значения Scaniine сказывается на работе с другими рисунками, в том числе с курсором и текстом. Для учета нового значения надо либо ввести специальную переменную, либо изменить значение переменной Horsize.

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

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

 


Компьютерные книги © 2006-2013
computers.plib.ru