О формате PCX — Архив WASM.RU
  Коротко о том, почему возникла эта статья.
  О формате файлов PCX написано довольно много. Это совершенно различная по своему характеру и содержанию литература. Краткие описания формата, подробнейшее изложение способов работы с огромным количеством всеохватывающих функций в фирменных пакетах, библиотеках и многое, многое другое. Вся эта немалая по объему информация хранится на тот случай, когда может возникнуть необходимость создать что-нибудь красочное и впечатляющее для глаз пользователя, желающего украсить экран своего дисплея изображениями, схожими по красоте и точности воспроизведения с фотографическим отпечатком.
Надо сказать, что в работе системного программиста такие задачи практически не возникают. Но вот наступил момент... Перечитав всю информацию, наличествовавшую в тот момент в личном архиве, стало понятно, что есть готовность задавать вопросы по теме, но отсутствует готовность осуществить поставленную задачу. Связано это было с тем, что с одной стороны, в разных источниках приводилась противоречащая друг другу информация, а с другой - нигде не обсуждались вопросы возможных непринципиальных, но важных с точки зрения дешифрации отличий формирования данных в файле PCX. И поэтому, как и большинству программистов нашего времени, пришлось провести многочисленные эксперименты и приобрести недостающую информацию и опыт. В результате были написаны процедуры обработки файлов PCX на ассемблере, позволившие создать компактную, быструю, легко модифицируемую программу вывода изображения, исходный текст которой будет приведен в конце статьи.  Цель данной статьи - дать достаточное количество информации для того, чтобы, приступая к написанию программ обработки PCX файлов, не испытывать сомнений в принципиальных вопросах.
ФОРМАТ PCX
  Не претендуя на полноту описания форматов, обрисуем общую структуру файла, структуру заголовка файла, поля заголовка файла, способ упаковки данных и некоторые тонкости обработки данных.
Формат PCX постоянно совершенствуется, а также в зависимости от программного продукта может быть несколько модифицирован.  Общую структуру файла можно условно разбить на две части: заголовок файла и упакованные данные (рис.1).
В новых, 256-цветных форматах, присутствует третья часть.
раздел файла размер, байт заголовок файла 128 упакованные данные размер файла-128 дополнительные данные
для 256-цветных режимов769 Рис.1. Общая структура файла
  Заголовок файла - это набор структурированных полей фиксированной длины. На рисунке 2 представлена схема заголовка файла:
 
N смещение название размер дополнительная информация 01 00 00h manuf byte Изготовитель 02 01 01h hard byte Информация о версии 03 02 02h encod byte Способ кодирования 04 03 03h bitpx byte Бит на точку 05 04 04h x1 2 bytes Размеры образа 06 06 06h y1 2 bytes 07 08 08h x2 2 bytes 08 10 0Ah y2 2 bytes 09 12 0Ch hres 2 bytes Разрешение дисплея по горизонтали 10 14 0Eh vres 2 bytes Разрешение дисплея по вертикали 11 16 0Fh clrma 48 bytes Палитра 12 64 40h vmode byte Видео режим 13 65 41h nplanes byte Количество слоев 14 66 42h bplin 2 bytes Байтов на строку 15 68 44h palinfo 2 bytes Тип палитры 16 70 46h shres 2 bytes Разрешение сканера по горизонтали 17 72 48h svres 2 bytes Разрешение сканера по вертикали 18 74 4Ah xtra 54 bytes Обычно не используется Рис.2. Заголовок PCX файла
В первой графе указывается порядковый номер поля, который приведен для более легкой ориентации в таблице и более легкого изложения материала. Во второй - смещение до начала поля в десятичном и шестнадцатиричном исчислении. Третья содержит название, которое сохранено таким же, как и в пакете PCX Programmer's Toolkit фирмы Genus Microprogramming.  Рассмотрим подробнее каждое из полей.
  Поле 01 (manuf) содержит некоторое число (например 10 для "PC Paintbrush" Zsoft Corp.), говорящее о том, в каком из редакторов создан этот PCX-файл.
  Поле 02 (hard) - информация о версии формата.
  Поле 03 (encod) позволяет определить, изменился или нет способ сжатия данных. До сих пор большинство редакторов заполняет это поле значением равным 01, свидетельствующим о том, что используется метод кодирования длинными сериями или метод группового кодирования (см. описание ниже).
Эти три поля, как очевидно, не нужны непосредственно при дешифрации данных, но при возникновении проблем с расшифровкой позволят сориентироваться программисту в том, как осуществлять дешифрацию, если есть достаточно подробное описание форматов, или к какой фирме обращаться за разъяснениями.  Поле 04 (bitpx) показывает, сколько бит отводится для сохранения информации о яркости пикселя в слое. Является достаточно удобным признаком определения (в дополнение к другим признакам) содержит ли данный файл 256-цветную палитру. При значении равном 08 - содержит.
Пиксел - минимальный графический объект. Обычно соответствует точке на экране, что в общем случае необязательно.Слой (plan) - совокупность байтов видео-памяти. Количество слоев зависит от номера установленного видеорежима и, естественно, от физической организации видеопамяти.  Поля 05...08 (x1, y1, x2, y2) определяют геометрические размеры картинки в пикселах. Например, если размер картинки 640 пикселов по горизонтали и 350 по вертикали, то в этих полях будут записаны следующие числа: 0, 0, 639, 349.
  Поля 09,10 (hres, vres) позволят узнать разрешающую способность дисплея, при "участии" которого создавалась та или иная картинка.
  Поле 11 (clrma) хранит информацию о палитре картинки. Данные хранятся 16-ю триплетами, определяющими значение каждого из 16 регистров палитры:
Рис.3. Формат поля номер 11
Для 256-цветных режимов количество байтов, необходимое для хранения всей палитры, равно 768, и понятно, что в поле 11 не хватает места для размещения этого массива. Поэтому эти триплеты располагаются в конце файла после байта-"маяка", равного 0Ch:
Рис.4. Расположение данных 256 - цветной палитры
Для того, чтобы попасть на это поле, необходимо:Делать это, конечно, необходимо в том случае, если вы уверены, что pcx-файл содержит 256-цветную палитру.
- установить указатель в конец файла;
- передвинуть его на 769 байтов назад;
- проверить, равен ли адресуемый байт значению 0Сh или 0Ah (зависит от программы, формировавшей pcx-файл).
  Байты RGB поля 11 могут принимать значения в диапазоне от 0 до 255. Но не каждый адаптер дисплея сможет воспроизвести заданное значение. Например, для EGA адаптеров диапазон этих значений лежит в пределах от 0 до 63. Поэтому для правильной интерпретации палитры необходимо учитывать характеристики оборудования, на котором будут воспроизводиться изображения.
Прим.ред.: Не забывайте, что статья была написана в начале 90-х годов. В настоящее время адаптер EGA - в далеком прошлом, и практически весь парк современных компьютеров общего применения свободно воспроизводит 256-цветную палитру.  Кроме того, в настоящее время появились программные продукты (например, PCX Programmer's Toolkit фирмы Genus Microprogramming), в которых значения палитры "нормализованы", т.е. лежат в диапазоне от 0 до 63, и значащими являются только младшие 6 битов каждого байта.
  Способ декодирования данных поля 11 в байт для инициализации регистра палитры прост, и потому отошлем читателя к исходному тексту процедуры CPALEGA (см.ниже). Заметим только, что для адаптера VGA имеет смысл использовать другой способ установки необходимой палитры, связанный с инициализацией DAC-регистров.
  Поле 12 (vmode) подскажет, какой видеорежим необходимо установить.
  Поле 13 (nplanes) позволит определить, сколько слоев видеопамяти в этом режиме, и алгоритм вывода данных на экран.
Подразумевается, что возникает необходимость отслеживания ситуации заполнения строки и переключения вывода на другой слой.  Поле 14 (bplin) определяет количество байтов на строку внутри слоя. Под строкой подразумевается последовательность байтов, содержащих графические данные, из которых строится изображение.
  Поле 15 (palinfo) интерпретирует палитру. Если байт равен 01, то палитра цветная, если 00 - то передаются градации серого.
  Поля 16,17,18 (shres, svres, xtra) могут содержать различного рода дополнительную информацию, которая сильно специфична и, как правило, не нужна для простых программ, выводящих рекламные картинки. Обычно эти поля заполняются нулями.
  Как было уже сказано, при упаковке данных изображения используется метод, носящий название "кодирование длинных серий". Суть метода довольно проста. Каждой повторяющейся последовательности байтов можно поставить в соответствие код, состоящий из двух байт. Первый из них является счетчиком повторений байта, стоящего вторым в этом коде. Например, если есть последовательность из 34 (22h) байтов типа 55h, то вместо этих 34(22h) байтов в закодированном файле будут стоять два числа: 22h,55h:
Рис.5. Кодирование длинных серий
  В файлах PCX возникает необходимость различать байт-счетчик и байт-эталон. Это связано с тем, что отдельные части изображения могут состоять из неповторяющихся данных и байт-счетчик в этом случае отсутствует. Поэтому он должен быть каким-либо способом помечен. Это можно сделать, установив два старших бита в 01, а оставшиеся 6 битов будут хранить значение счетчика. Следовательно в файле PCX та же последовательность из 34(22h) байтов будет представлена как 0E2h,55h.
  Очевиден и способ декодирования данных:
- Проверить равны ли оба старших бита считанного байта 01. Если равны, то следующий байт необходимо повторить столько раз, сколько получится из байта-счетчика после обнуления двух его старших битов.
- В противном случае это - байт-эталон, и его нужно повторить один раз.
Отметим, что в случае, когда байт-эталон имеет установленные стаpшие биты в единицу (напpимеp, чеpточка длиной в 8 пикселей и следом за ней 8 чеpных пикселей пpедставляются в виде двух байтов 0FFh,00h), то из-за этого он похож на байт-счетчик, и его пpедваpяют байтом-повтоpителем, pавным единице. Этим снимается неоднозначность опpеделения типа данных.  Теперь, для завершения обсуждения вопроса о кодировании, покажем, каким образом располагаются в файле данные, хранящие изображение.
  Вначале идут байты, относящиеся к нулевому слою, затем - к первому, и так далее до четвертого включительно, после чего все повторяется сначала:
Рис.6. Порядок следования данных
ПРОГРАММА ОБРАБОТКИ ФАЙЛА PCX
  В общем случае программы должны обладать возможностью и создавать, и интерпретировать файл этого формата.
Под интерпретацией здесь понимается возможность правильно понимать данные, хранящиеся в заголовке pcx-файлов, и в соответствии с ними (данными заголовка) строить на экране изображение.  Как правило - это мощные графические редакторы или утилиты, им сопутствующие. Но есть задачи, не требующие создания файлов формата PCX. Необходимо только второе - интерпретировать. Как правило, это универсальные программы-вьюеры. Есть задачи и более простые - показать на экране рекламное изображение. Для этого надо совсем мало, так как в связи с неизменностью условий работы программы практически отпадает необходимость подробно анализировать заголовок файла PCX. Такая задача и предлагается вашему вниманию.
  Наилучший способ объяснить - это привести пример. Поэтому приступим к изложению задачи, которую необходимо решить и к описанию программы, ее реализующей.
  Построение любой программы начинается с четкого уяснения условий, поставленных задачей. Каковы же эти условия?
- минимальный размер кода
- минимально возможный и фиксированный размер занимаемого пространства при выполнении программы
- быстрота вывода
- способность "понимать", возможна ли обработка данного pcx-файла
- разбор палитры и инициализация регистров палитры видеоадаптера
- независимость от того, каким из графических редакторов создавался pcx-файл (полной независимости конечно, не бывает)
- режим работы монитора с разрешением 640х350 (режим 10h для адаптеров EGA/VGA)
- pcx-файл должен находиться отдельно от программы вывода
  Первые два условия объясняются желанием не увеличивать "безгранично" размеры программы*), к которой пристыковывается этот модуль, и, во-вторых, быть независимым от размеров pcx-файла и от типа (.com или .exe) основной программы. Предваряя результат, скажем, что размер исполняемого модуля менее одного килобайта. А процедуры, относящиеся непосредственно к декодированию и выводу изображения, занимают около 600 байт.
*)Это ухудшило бы потребительские характеристики программы. Например, если вы хотите использовать какой-либо популярный драйвер или утилиту (с разрешения автора) для рекламы то было бы совершенно неприемлемо увеличивать размер программы на 10 или больше килобайт.  Это объясняется тем,что программа написана на языке ассемблера, и тем, что поставленная задача проста, и поэтому количество процедур мало. Это же обеспечивает выполнение и третьего условия.
  Под способностью "понимать" имелась ввиду реализация программного блока, анализирующего необходимые поля заголовка pcx-файла, и, в зависимости от их содержимого, формирующего команды, позволяющие программе ветвиться.
  Выполнение пятого условия необходимо для того, чтобы обеспечить некоторую свободу маневра и запас "прочности" при "встрече" с различной техникой с одной стороны, а с другой - возможности более полно использовать палитру.
  Говоря о шестом условии, подчеркнем, что существует большое разнообразие нюансов при записи данных в pcx-файл.
Например, автор столкнулся с тем, что достаточно часто графические редакторы или утилиты формируют pcx-файл, считая некоторые характеристики изображения неизменными (например, размер текстовой строки считается величиной постоянной и равной 80 символам в графическом редакторе PMTV, поставляемом совместно с ручным сканером "A4SCAN" фирмы A4TECH CO.ltd.(U.S.A.)).Это дает определенные преимущества авторам вышеупомянутого программного обеспечения при его создании, так как сокращается контроль разнообразных условий, и по той же причине упрощается работа непосредственно в графическом редакторе.Поясним это утверждение следующим примером.Предположим, мы нарисовали линию белого цвета длиной в 35 пикселей. Размер же всего изображения примем равным 67x1 пикселей, для упрощения рисунков и рассуждений:
Рис.7. Структура линии на экране
Данные о 8 точках умещаются в одном байте. Подсчитав количество байтов, видим, что нужно 5 байтов для хранения информации о всех точках линии одного слоя. Причем в пятом байте используются только три бита. Для хранения же информации о всех точках изображения необходимо [67/8]·4=9·4=36 байтов (здесь квадратные скобки означают операцию округления в большую сторону).  Посмотрим теперь, как выглядит закодированное изображение в pcx-файле, формируемом редакторами PC Paintbrush и PMTV A4TECH (рис.8).
  Логично предположить, что pcx-файл должен содержать 5·4 байтов (рис.8а) без учета размера заголовка. Линия белого цвета, и поэтому требуется инициализация 4-х слоев видео-памяти. Но практика показывает (рис.8б,в), что оба редактора поступают по-другому и размеры pcx-файла больше, чем ожидалось. За счет чего же происходит увеличение размера?
  В файле, созданном редактором PMTV (A4TECH) видим (рис.8в), что для каждого слоя строка содержит (начиная с 4 колонки и до конца) дополнительную информацию, относящуюся к незанятой нашим изображением части экрана. То есть, иными словами, в файле хранится дополнительная информация о всей строке экрана независимо от размеров изображения по горизонтали.
  В файле же, созданном PC Paintbrush, мы наблюдаем то же самое, за исключением того, что хранимая информация зависит от размеров изображения по горизонтали и выбирается кратной целому числу.
  Казалось бы, во втором случае подход более рационален, так как размер файла меньше. К сожалению, дело омрачается тем обстоятельством, что в байте, расположенном после после байтов с изображением (рис. 8б, колонка 4, выделено жирным), оказывается "мусор", и если не принимать никаких мер, то справа от изображения появится красивая, но ненужная бахрома. "Мусор" образуется из-за того, что буфер с записываемыми данными предварительно не очищается, и неинициализированные байты могут содержать любую информацию.
Код (Text):
С4h,FFh,07h,C3h,00H - 0-й слой С4h,FFh,07h,C3h,00H - 1-й слой С4h,FFh,07h,C3h,00H - 2-й слой С4h,FFh,07h,C3h,00H - 3-й слой</pre> а) предполагаемый результат <pre>С4h,FFh,07h,01h,C5h,00H - 0-й слой С4h,FFh,07h,03h,C5h,00H - 1-й слой С4h,FFh,07h,21h,C5h,00H - 2-й слой С4h,FFh,07h,32h,C5h,00H - 3-й слой</pre> б) PC Paintbrush Zsoft Corp. <pre>С4h,FFh,07h,FFh,00H ... - 0-й слой С4h,FFh,07h,FFh,00H ... - 1-й слой С4h,FFh,07h,FFh,00H ... - 2-й слой С4h,FFh,07h,FFh,00H ... - 3-й слой</pre> в) PMTV фирмы A4TECH.</blockquote> <p align="center"><b>Рис.8. Содержимое pcx-файлов</b> <blockquote>Значение поля 14 (bplin) в случае PC Paintbrush равно здесь 11 байтам, оно зависимосит от размеров изображения. Для редактора PMTV оно постоянно и всегда равно 80 байтам.</blockquote> <p>  Принятие мер выражается в увеличении программного кода, что конечно же пустяки для PC Paintbrush или другой большой по размеру программы, но что плохо для задач типа той, которую решал автор (см. второе условие в приведенном выше списке требований к программе). <p>  Автору кажется, что в этом смысле подход, реализованный в PMTV (A4TECH) более рационален. Во-первых, потому, что алгоритм кодирования информации, принятый для pcx-файлов, далек от совершенства и выигрыш так мал, что его можно и не заметить. Во-вторых, сокращается размер кода программы и упрощается обработка pcx-файла. <blockquote>Основная цель кодирования - сжатие информации. Метод кодирования в файлах PCX дает результат намного худший, чем например метод, принятый в файлах типа GIF, TIFF и других.</blockquote> <p>  На этом завершим комментарии к условиям задачи и перейдем к составлению и обсуждению блок-схемы: <ul><li>первое, что необходимо сделать - это проверить, передается ли имя файла, и если да, то проверить, существует ли такой файл. <li>при положительном результате проверки прочитать в буфер программы заголовок pcx-файла. <li>затем посмотреть поле 03 (encode) и убедиться, что это известный нам способ кодирования. Далее прочитать поле 12 (vmode) и проверить, сможем ли мы обслужить обозначенный видео-режим. <li>в завершение проверить поля 01 и 02 и убедиться, что это известные нам фирма и номер версии. После этого можно приступить к подготовке данных, необходимых для дальнейшей работы. </ul> <blockquote>В исходном тексте нашей программы отсутствует такой подробный разбор, так как для данной задачи вышеописанные условия известны заранее. Поэтому после подготовки данных можно установить необходимый видеорежим дисплея, вывести изображение и остановиться в ожидании команды пользователя. По команде восстановить исходный режим и завершить программу (см. блок-схемы на рис.9).</blockquote> <p align="center"><b>Основная программа OPCX#4. Процедура EGAP</b> <p align="center"><img src="/archive/pub/8/pic/p01.gif"> <p align="center"><b>Рис.9. Блок-схемы</b> <p>  Рассмотрим теперь, что происходит в процедуре EGAP. <p>  Поскольку к данному моменту заголовок файла PCX прочитан, мы приступаем к подготовке данных. <p>  Определяем количество байтов, отведенных на строку. Это позволит определить, когда заканчивается строка и нужно ли переключать слой видеопамяти. Формируем маску для очистки "мусора". Неизбежность этого связана с тем, что "мусор" может присутствовать и в последнем байте, относящемся к изображению, а нам необходимо очистить только "загрязненные" биты. Например, для байтов в колонке номер 7 белой линии длинною в 75 пикселов необходима маска "07h": <blockquote><pre>1 2 3 4 5 6 7 С4h,FFh,С4h,FFh,C1h,FFh,17h - 0-й слой С4h,FFh,С4h,FFh,C1h,FFh,37H - 1-й слой С4h,FFh,С4h,FFh,C1h,FFh,07H - 2-й слой С4h,FFh,С4h,FFh,C1h,FFh,47H - 3-й слойРис.10
  Преобразовываем и устанавливаем палитру. "Сообщаем" адаптеру дисплея о том, что вывод изображения будет происходить в послойном режиме. И начинаем ...
  Вывод изображения
  Блок-схема вывода изображения, представленная на рисунке 11, достаточно подробна и не требует пояснений. Следует только сказать, что в этой процедуре есть дополнительные проверки, связанные с необходимостью отслеживать количество прочитанных и выведенных байтов. Это необходимо для того, чтобы правильно осуществлять постепенную подкачку данных из файла PCX.
Внимание не заострялось на этом моменте, так как это не являлось основной темой.
Рис.11. Процедура SETSCR
  На этом можно закончить описание блок-схем программы, а читателю посоветовать приступить к изучению исходного текста программы и экспериментам с ним: opcx.zip (3588 байт).
Чтобы упростить читателю знакомство с исходным текстом программы, он снабжен комментариями и оформлен в виде программы типа .COM с возможностью передачи программе имени обрабатываемого pcx-файла через командную строку, и полностью готов к ассемблированию.  Литература:
  1. Описание пакета PCX Programmer's Toolkit Genus Microprogramming, February 1, 1989. © Андрей Бордачев
О формате PCX
Дата публикации 16 июн 2002