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

Рисунки, подготовленные в стандарте PCX

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

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

Новое поле заголовка

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

В байте со смещением 41h указано количество цветов (битовых плоскостей), на которое разложена каждая строка образа рисунка. Если оно равно 3, то мы имеем дело с полноцветным рисунком. Никакого другого признака, указывающего на то, что рисунок полноцветный, не существует.

Напоминаем
В байте со смещением 2 хранится "ключ кодирования", значение которого может быть равно 0 или 1. В первом случае образ рисунка не упакован, а во втором упакован по способу RLE, который описан ранее
.

Способ распаковки строки

Перед упаковкой строка рисунка разлагается на три подстроки, размер каждой из которых равен размеру строки. Одна из них содержит коды красного базового цвета, другая – зеленого и третья – синего. Другими словами, производится разложение строки по компонентам базовых цветов. Затем каждая подстрока упаковывается по способу RLE, и результат записывается в файл. Если исходный рисунок состоял из к строк, содержащих трехбайтовые коды точек, то упакованный рисунок содержит зк групп однобайтовых кодов цвета. Зачем это делается, описано в следующем разделе, а здесь нас интересует способ распаковки.

Итак, в файле формата PCX, содержащем упакованный полноцветный рисунок, начиная с адреса 80h, записаны группы упакованных однобайтовых кодов базовых цветов в такой последовательности:

  • коды красного базового цвета первой строки рисунка
  • коды зеленого базового цвета первой строки рисунка
  • коды синего базового цвета первой сроки рисунка
  • коды красного базового цвета второй строки рисунка
  • коды зеленого базового цвета второй строки рисунка
  • и т. д. вплоть до коды синего базового цвета последней строки рисунка

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

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

Для того чтобы не усложнять подпрограммы построения строки, надо изменить порядок записи результатов распаковки так, чтобы базовые цвета одной точки оказались в трех подряд расположенных байтах оперативной памяти. Другими словами, подпрограмма распаковки должна восстанавливать формат rgb или bgr, по усмотрению программиста. Мы выберем формат bgr для того, чтобы при построении строки можно было использовать подпрограммы примера 7.26.

Подпрограмма Unpack

Текст подпрограммы распаковки строки рисунка с преобразованием в формат bgr показан в примере 7.27. Распакованная строка записывается в свободную часть буфера общего назначения, поэтому перед вызовом подпрограммы в регистр gs копируется содержимое переменной Genseg. Адрес в буфере общего назначения подпрограмма выбирает из переменной GenOffs. Для чтения байтов упакованной строки вызывается вспомогательная подпрограмма Nxt_sym (см. пример 3.25, раздел 3.3.3), которая помещает в регистр ai код очередного байта из буфера обмена и следит за тем, чтобы этот буфер не был пустым.

Пример 7.27. Распаковка строки и преобразование в формат bgr.

Unpack: PushReg <ax, dx, ex, di> сохранение используемых регистров
mov di, GenOffs адрес начала строки в GenSeg
add di, 02 начинаем с записи красных цветов
mov ex, 03 количество цветов
Unpckl: PushReg <di,cx> сохранение содержимого di и сх
mov dx, f width логический размер строки
Unpck2: call nxt sym возвращает в al – текущий код
rnov ex, 01 предполагаем одиночный символ
cmp al, OCOh одиночный символ?
jbe Unpck3 › да, на запись символа
mov ex, ax пересылка ах в счетчик
and ex, 3Fh выделяем число повторов
call Nxt sym читаем повторяемый код
Unpck3: sub dx, ex кол-во байтов до конца строки
Unpck4: mov gs: [di], al запись кода цвета
add di, 03 коррекция адреса
loop Unpck4 управление повторами записи

Подпрограмма примера 7.27 состоит из двух вложенных циклов, внешний имеет метку Unpck1, а внутренний unpck2.

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

Внешний цикл управляет трехкратным повторением внутреннего. Кроме того, он формирует в регистре di адрес для записи результатов так, чтобы строка соответствовала формату bgr.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.