Воспроизведение сжатых рисунков
Для сокращения размера файлов образы рисунков могут храниться в сжатом виде. Частным случаем является упаковка точек 16- и 2-цветных рисунков, когда в байте располагаются коды двух или восьми подряд расположенных точек. Здесь нас будут интересовать способы упаковки и распаковки 256-цветных рисунков.
Сразу отметим, что в этой области нет никакой унификации, и разработчики стандартов для хранения и передачи файлов выбирают способ сжатия по своему усмотрению. В данном разделе основное внимание уделено способу сжатия, получившему название RLE (Run-Length-Encoding), который предусмотрен в стандартах PCX, BMP и некоторых других. Он дает далеко не лучшие результаты, но имеет одно неоспоримое преимущество, которое заключается в простоте распаковки. Это позволяет привести исчерпывающее описание способа построения рисунка. Стандарт BMP описан в приложении А данной книги, здесь описан стандарт PCX.
Стандарт создала фирма ZSoft разработчик графических редакторов PaintBrush, PhotoFinish и пр. Ему, как и многим другим стандартам, присущи некоторые разночтения, вызванные тем, что улучшать устаревающие версии пыталась не только ZSoft, но и некоторые другие фирмы, например Genius Microprogramming.
Заголовок PCX-файла имеет фиксированный размер 80h байтов, сразу после него (начиная с адреса) располагается образ рисунка. Нас будут интересовать лишь некоторые байты и слова заголовка.
Байт 0 должен содержать код ОАb, являющийся признаком того, что файл соответствует стандарту PCX.
Байт 1 содержит версию стандарта (от 0 до 5), в частности код 5 соответствует третьей версии стандарта, в которой впервые было введено использование 256-цветной палитры.
Байт 2 содержит 1, если образ рисунка хранится в сжатом виде, или 0 – в противном случае (распаковка не требуется).
Байт 3 содержит размер точки изображения в битах, для 256-цветных рисунков его значение равно 8.
Слова 4, 6, 8 и OAh содержат минимальные и максимальные значения координат рисунка (xmin, Ymin, xmax, Ymax). Ширина и высота рисунка вычисляются так: iwidth = Xmax – Xmin + 1, iheight = Ymax – Ymin + 1.
Слово 42h содержит размер строки рисунка в байтах, мы обозначим его содержимое fwidth. При четном количестве точек в строке iwidth = fwidth, при нечетном количестве точек в строке fwidth = iwidth + 1. В этом случае строка содержит дополнительный байт, который учитывается при распаковке, но не выводится на экран, т. к. его содержимое не определено.
Заголовок файла содержит и другие величины, но в данном разделе они нам не понадобятся. Более подробную информацию о заголовке рсх-файлов вы найдете в книге, а мы вернемся к рассмотрению стандарта PCX при описании работы с палитрой и построения полноцветных рисунков.
Техника распаковки строки
Признаком упакованного рисунка является во втором байте заголовка файла. Результаты упаковки по способу RLE интерпретируются так: если в текущем байте установлены два старших разряда (коды ocoh – OFFh), то шесть его младших разрядов указывают, сколько раз надо повторить следующий байт. В противном случае (один или оба старших разряда очищены) текущий байт содержит код одной точки.
При упаковке строки исходного рисунка обрабатываются независимо друг от друга, т. е. цикл сжатия останавливается в конце каждой строки и начинается заново с началом следующей. Соответственно, цикл распаковки должен продолжаться до тех пор, пока количество полученных точек (байтов) не совпадет с размером строки fwidth.
Прежде чем рассматривать конкретный пример, обсудим некоторые общие вопросы. Нам предстоит написать программу, которая манипулирует с двумя потоками байтов. Входной поток содержит сжатый образ рисунка, а выходной – образ того же рисунка, но уже распакованный.
Будем считать, что входной поток находится в буфере обмена, адрес начала которого задают переменные swpOffs и SwpSeg. При распаковке из этого буфера выбираются один или два очередных байта. Очевидно, что при этом надо следить за тем, чтобы нужные байты находились в буфере и при необходимости пополнять буфер новыми данными. Исходя из опыта (и не только автора) целесообразно составить специальную подпрограмму, которая при каждом обращении возвращает очередной байт данных, следит за состоянием буфера и в нужный момент пополняет его новыми данными.
Выходной поток, в конечном итоге, направляется в видеопамять, но объединять в одной подпрограмме действия, связанные с распаковкой и записью кодов точек в видеопамять, нецелесообразно – эти функции должны выполнять разные процедуры. Поэтому мы рассмотрим подпрограмму, которая помещает коды точек в специально выделенный буфер.