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

         

Анализ основных полей заголовка

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

Будем считать, что в разделе данных задачи описаны переменные:

iwidth dw 0 ; количество точек в строке рисунка
iheight dw 0 ; количество строк в рисунке
fwidth dw 0 ; количество байтов в строке в файле
rmndr dw 0 ; количество дополнительных байтов в строке файла
bitcnt db 0 ; количество разрядов в коде точки

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



Описание следующего шага

Расположение полей, содержащих значения для переменных iwidth, iheight и bitcnt, зависит от того, какому формату соответствует заголовок — Windows или OS/2. Напомним, что эти форматы различаются размером информационной части заголовка, указанным в поле bisize или bcsize (его смещение ОЕb).

Шаг 3. Выбираем содержимое полей заголовка biwidth, biHeight и biBitCnt с учетом значения, указанного в поле bisize, и сохраняем выбранные величины в переменных iwidth, iheight и bitcnt. В заключение проверяем значение bitcnt, и если оно равно ish (24), то обработка заголовка закончена, и выполнение подпрограммы Bitmap завершается. В соответствии со стандартом BMP поле biBitCnt может содержать значения 1, 4, 8 или ish. Последнее значение соответствует полноцветным рисункам, не использующим палитру цветов, поэтому никакие манипуляции с палитрой не требуются, что и позволяет просто завершить подпрограмму.

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

Пример А.З. Формирование исходных значений основных переменных

Part 2 : mov ax, fs: [si+12h] ax = biwidth, формат Windows и OS/2
mov bx, fs: [si+16h] bx = biHeight, формат Windows
mov ex, fs: [si+ ICh] ex = biBitCnt, формат Windows
cmp byte ptr fs: [si+01 ]h) , 28h; заголовок формата Windows ?
je @F -> да, переходим на запись значений
mov bx, fs: [si+14h] bx = biHeight, формат OS/2
mov ex, fs: [si+18h] сх = biBitCnt, формат OS/2
Э @ : mov iwidth, ax iwidth = biwidth
mov f width, ax fwidth = biwidth
mov iheight, bx iheight = biHeight
mov bitcnt, cl bitcnt = biBitCnt
cmp cl, 18h cl = 18h ?
jne Part_3 -> нет, переход на продолжение
ret возврат из подпрограммы

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

Здесь уместно напомнить, что в стандарте PCX значение переменной fwidth фанится в заголовке файла и вычислять его не надо (см. раздел).

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

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

Следующие 4 шага. Мы опишем более простой способ, основанный на том что адрес начала строки в файле должен быть кратен четырем. Поэтому если количество точек в строке рисунка не кратно четырем, то при записи в файл после каждой строки добавляется необходимое количество байтов, содержимое которых не определено. При построении образа рисунка эти байты не используются, их просто пропускают. Таким образом, одна из причин различия значений переменных iwidth и fwidth связана с возможным наличием дополнительных байтов в строке файла. Кроме того, вследствие упаковки точек 2- и 16-цветных рисунков, строка в файле будет в 2 или в 8 раз короче строки рисунка (без учета дополнительных байтов).

Для получения нужного результата выполняются следующие 4 шага.

Шаг 4. Предполагаем, что fwidth = iwidth. Округляем это значение до ближайшего целого числа, кратного четырем. Очищаем константу сдвига. Если bitcnt = 8, то переходим к шагу 7, иначе следующий шаг.

Шаг 5. Полученное на предыдущем шаге значение округляем до ближайшего целого, кратного 8. Присваиваем константе сдвига значение 1. Если bitcnt = 4, то переходим к шагу 7, иначе следующий шаг.

Шаг 6. Если мы дошли до этого шага, то bitcnt = 1, т. е. рисунок двухцветный (но не обязательно черно-белый). Округляем полученное на предыдущем шаге значение fwidth до ближайшего целого, кратного 32. Константе сдвига присваиваем значение 3.

Шаг 7. Округленное значение сдвигаем вправо на константу, значение которой выбиралось на предыдущих шагах, и присваиваем его переменной fwidth. Вычисляем количество дополнительных байтов в строке файла (значение переменной rmndr). Нужные величины сформированы.

Программная реализация описанных шагов показана в примере А.4, который является продолжением примеров А.2 и А.З.

Пример А.4. Вычисление значений переменных fwidth и rmndr

Part_3: xor cl, cl ; cl = 0, значение константы сдвига
add ax, 03 ; ax = ax + 3 (ax содержит iwidth)
and al, OFCh очищаем 2 младших разряда ах
cmp bitcnt, 08 bitcnt = 8 ?
je @F -> да, переход на локальную метку @@
add ах, 04 ах = ах + 4
and al, OF8h очищаем 3 младших разряда ах
inc cl cl = 1, значение константы сдвига
cmp bitcnt, 04 bitcnt = 4 ?
je @F -> да, переход на локальную метку @@
add ax, 18h ах = ах + 24
and al, OEOh очищаем 5 младших разрядов ах
mov cl, 03 cl = 3, значение константы сдвига
?: mov bx, ax bx = ах (округленное значение iwidth)
sub bx, iwidth bx = bx — \width
shr bx, cl сдвиг bx вправо на содержимое cl
mov rmndr, bx количество дополнительных байтов
shr ax, cl сдвиг ах вправо на содержимое cl
mov fwidth, ax сохраняем значение fwidth

Рисунок не помещается па экране. Вполне вероятно, что размеры (или один из размеров) рисунка превышают размеры рабочей области экрана, соответ-ствующие установленному видеорежиму. В таких случаях возможны, по крайней мере, три варианта действий, не считая отказа от построения рисунка:

  • выводится только часть рисунка, помещающаяся на экране;
  • увеличивается логический размер строки (раздел, функция 4F06h);
  • устанавливается видеорежим с большим геометрическим разрешением.

двух первых случаях на экране будет видна только часть, а в третьем случае — все изображение, если удастся подобрать подходящий видеорежим. Наиболее универсален второй способ, но для получения всех его преиму-щecTB в задачу надо включить механизм перемещения области видеопамяти, отображаемой на экране. В приложениях для Windows таким механизмом являются горизонтальный и вертикальный "лифты".
Изменять установленный видеорежим или его характеристики в описывае-мой здесь подпрограмме не целесообразно, это надо делать на более высоком уровне. Если же вас устраивает построение части рисунка, размер кото-рой зависит от установленного видеорежима, то в данной подпрограмме можно Принудительно изменитьЬ значения iwidth и iheight.

Дополнепие к примеру А.З.

Для выполнения описанных действий, в тексте примера А.З команда, выполняющая проверку размера кода точки mр ci, I8h), заменяется группой команд, приведенных в примере А.З.

Пример А.5. Ограничение значений переменных iwidth и iheight

mov bx, horsize bx = размер экрана по горизонтали
cmp bx, ax iwidth > horsize ?
jae @F -> нет
mov iwidth, bx iwidth = horsize (уменьшаем iwidth)
@@: mov bx, versize bx = размер экрана по вертикали
cmp bx, iheight iheight > versize ?
jae @F -> нет
mov iheight, bx iheight = versize (уменьшаем iheight)
@@: cmp cl, 18h cl = 18h ?

При построении рисунка с таким ограничением значений iwidth и iheight на экране будет видна его левая нижняя часть размером horsize*versize. Мы не включили эти команды в текст примера А.З потому, что ограничение размера рисунков не относится к основным действиям, выполняемым при обработке заголовка файла.


Содержание раздела