Построение рисунка снизу вверх
При работе с BMP-файлами произвольного размера основным способом является построение изображения снизу вверх. В таком случае строки образа рисунка считываются в порядке их расположения в файле, а выводятся на экран начиная с последней строки рисунка.
Такой способ уже использовался для построения полноцветных рисунков формата BMP, он описан в соответствующем разделе, а текст соответствующей подпрограммы показан в примере 7.25. Отличие рассматриваемого здесь случая только в том, образ рисунка использует палитру, а коды его точек могут занимать 1, 4 или 8 разрядов.
Описание предварительных действий
Перед началом построения рисунка подпрограмма вычисляет адрес начала последней строки в видеопамяти, размер считываемой из файла порции данных в байтах, количество содержащихся в ней строк образа рисунка и значение константы для переадресации строк видеопамяти. Опишем, как это делается.
Адрес начала последней строки рисунка в видеопамяти вычисляется следующим способом. Расстояние между первой и последней строкой равно (iheight -i)*bperiine байтов. В общем случае произведение занимает два слова. Содержимое младшего слова прибавляется к адресу начала первой строки. Содержимое старшего слова преобразуется в номер окна, который прибавляется к номеру окна, в котором находится первая строка. Вычисленное значение окна надо установить.
Количество строк в порции считываемых данных (part) вычисляется как частное от деления числа 65 535 на размер строки в файле (fwidth). Умножив part на fwidth, получим размер порции для чтения в байтах.
Замечание
Вместо умножения можно вычесть остаток от деления из числа 65 535.
Константа переадресации строк, видеопамяти.
После записи кодов точек текущей строки в видеопамять определяется адрес начала предыдущей. Для этого текущий адрес видеопамяти уменьшается на величину, вычисляемую по формуле (iwidth + horsize) *bytppnt. Если при вычитании вырабатывается признак переноса, то устанавливается предыдущее окно видеопамяти, в противном случае текущее окно не изменяется.
Подпрограмма BigBmp
Текст подпрограммы, выполняющей построение рисунка описанным способом, приведен в примере А.10. Перед ее вызовом адрес левого верхнего угла рисунка помещается в регистр di и устанавливается окно видеопамяти, которому принадлежит этот адрес. Регистр ез должен содержать код видеосегмента. Если в тексте вместо call drawiine записана команда call bx, то в регистре bх указывается адрес подпрограммы построения строки.
Пример А.10. Построение рисунка формата BMP снизу вверх.
BigBmp: pusha сохранение "всех" регистров PushReg <gs,fs,Cur w in>; сохранение gs, fs и Cur win mov ax, iheight ax = iheight, количество строк в рисунке mov remline, ax remline = ах, количество строк в рисунке dec ax учет нумерации строк с нуля mul bperline dx:ax = (iheight – l)*bperline add di, ax di = адрес последней строки рисунка adc dx, 00 учитываем возможный перенос mov ax, GrUnit ах = GrUnit (единица измерения окон) mul dl вычисляем добавку к номеру окна add Cur win, ax номер окна для последней строки call Setwin установка вычисленного окна mov ax, – 1 ах = 65535 xor dx, dx очистка старшей части делимого div fwidth ах = 65535 / fwidth (частное от деления) mov part, ax part = число строк в порции для чтения mul fwidth ах = ах* fwidth mov numbyte, ax размер порции считываемой в байтах mov ax, iwidth ах = iwidth add ax, horsize ах = iwidth + horsize mul bytppnt ах = (iwidth + horsize) *bytppnt, dx = 0 mov dx, ax сохраняем для коррекции адресов mov fs, SwpSeg fs = сегмент буфера обмена mov SwpOffs, 0 очистка смещения в сегменте mov gs, GenSeg!! gs = сегмент таблицы цветов NewPart: mov ex, numbyte сх = количество считываемых байтов call Readf чтение порции в буфер обмена jnc sr › чтение прошло без ошибок ; Здесь должны выполниться действия при ошибке чтения sr: mov ex, part сх = кол-во строк в полной порции cmp remline, ex считана полная порция данных? jae @F › да, обходим следующую команду mov ex, remline нет, сх = оставшееся число строк @@: sub remline, ex уменьшаем значение счетчика строк xor si, si si = начало буфера обмена drwout: push зх сохраняем значение счетчика строк mov ex, iwidth ex = размер строки (в точках) call drawline!! или call bx – построение строки pop ex восстанавливаем счетчик строк add si, rmndr корректируем адрес в буфере обмена sub di, dx di = адрес начала предыдущей строки jnc @F › адрес в пределах текущего окна call PrevWin установка предыдущего окна @@: loop drwout управление циклом построения строк cmp remline, 0 остались не обработанные строки? jne NewPart › да, на чтение следующей порции PopReg <Cur_win,fs,gs>; восстановление Cur_win, fs и gs рора восстановление "всех" регистров call Setwin восстановление исходного окна ret возврат из подпрограммы
Выполнение подпрограммы примера А.10. начинается с подготовительных действий, смысл и назначения которых описаны выше. Основной цикл имеет метку NewPart. Если вы сравните его с одноименным циклом примера 7.25, то убедитесь в их полном совпадении, поэтому мы не будем повторять описание выполняемых действий.
Таким образом, основной цикл построения ВМР-файлов произвольного размера не зависит от того, как подготовлен образ исходного рисунка, – с использованием или без использования палитры цветов. От этого зависят только подпрограммы drawline, вызываемые для построения строк рисунков.