Растровые файлы
Растровые файлы, отличаясь друг от друга деталями, имеют общую структуру. Растровые файлы содержат заголовок, растровые данные и прочую информацию, в том числе и о цветовой палитре. По непонятной причине продолжаются разработки программ, использующих так называемые неструктурированные форматы. Такие файлы содержат только данные изображения, не оставляя нам никаких шансов разобраться в их структуре. О том, как организованы данные в этих файлах, имеют представление только их разработчик и программа визуализации, которая их использует. Поскольку обычно невозможно определить, чем, кроме физического размера, один неструктурированный файл отличается от другого, мы будем обсуждать только растровые файлы, которые содержат хотя бы заголовки.
Как организованы растровые файлы
Основными компонентами простого растрового файла являются:
Заголовок |
Растровые данные |
Если файл не содержит данных изображения, то должен быть представлен только заголовок. Дополнительную информацию, которая не помещается в заголовке, размещают в концовке файла:
Заголовок |
Растровые данные |
Концовка |
Если применяется палитра, то ее можно сохранить в заголовке файла, но удобнее разместить ее в середине файла, после заголовка:
Заголовок |
Палитра |
Растровые данные |
Концовка |
Кроме того, палитру можно хранить после данных изображения на месте концовки файла или непосредственно в ее составе:
Заголовок |
Растровые данные |
Палитра |
Таблицы строк развертки и таблицы цветной коррекции могут располагаться после заголовка как перед данными изображения, так и после них.
Заголовок |
Палитра |
Таблица строк развертки |
Таблица цветовой коррекции |
Растровые данные |
Таблица цветовой коррекции |
Концовка |
Если файловый формат позволяет хранить несколько изображений, то после заголовка в файле может размещаться каталог изображений (индекс изображений), который содержит информацию о смещении начальных позиций всех изображений в файле:
Заголовок |
Палитра |
Каталог изображений |
Растровые данные изображения 1 |
Растровые данные изображения 2 |
… |
Растровые данные изображения n |
Концовка |
Если формат позволяет каждому изображению иметь свою собственную палитру, то ее принято сохранять непосредственно перед данными того изображения, с которым она связана:
Заголовок |
Палитра |
Каталог изображений |
Палитра 1 |
Растровые данные изображения 1 |
Палитра 2 |
Растровые данные изображения 2 |
|
Палитра n |
Растровые данные изображения n |
Концовка |
Теперь рассмотрим компоненты растрового файла более подробно.
Заголовок
Заголовок — это раздел двоичных или символьных (в формате ASCII) данных. Обычно он располагается в начале файла и хранит общую информацию о растровых данных, которые в этом файле содержатся. Все структурированные растровые файлы имеют заголовки, структура и содержимое которых определяются конкретным форматом. Обычно заголовок растрового файла состоит из фиксированных полей. Ни одно из этих полей не является обязательным, но определенный набор полей типичен для большинства популярных на сегодняшний день форматов. Ниже приведена информация, обычно содержащаяся в заголовке:
Заголовок |
Палитра |
Каталог изображения |
Палитра 1 |
Идентификатор файла |
Версия файла |
Количество строк в изображении |
Количество пикселей в строке |
Количество битов в пикселе |
Количество цветовых плоскостей |
Тип сжатия |
Х-координата начала изображения |
Y-координата начала изображения |
Текстовое описание |
Неиспользуемое пространство |
Идентификатор файла
Обычно заголовок начинается с определенного уникального идентифицирующего значения, называемого идентификатор формата файла, файловый ID или ID-значение. Идентификатор позволяет программе определить формат графического файла, с которым она работает. Идентификаторы форматов часто называют магическими числами, подразумевая под этим, что они выбирались разработчиком формата произвольно. В качестве идентификатора может использоваться последовательность символов ASCII (например, ВМ или GIF), либо двух- или четырехбайтовое слово (например, 4242h или 596aa695h), либо произвольная последовательность данных, понятная только разработчику формата. Предполагается, что идентификатор должен быть уникальным даже для форматов, используемых на различных платформах, но, как вы увидите дальше, это условие далеко не всегда соблюдается. Как правило, если значение, прочитанное из определенного места в файле, совпадает с ожидаемым идентификационным значением, то программа, читающая заголовок файла, предполагает, что ей известен данный формат. Однако существуют три обстоятельства, препятствующие тому, чтобы этот простой и быстрый способ идентификации обеспечил абсолютную надежность при определении формата. Во-первых, в некоторых форматах идентификатор файла опущен, а на его месте находятся данные, индивидуальные для каждого файла. Эти данные могут случайно повторить одно из магических значений другого файлового формата, известного данной программе. К счастью, вероятность такого совпадения незначительна.
Второе обстоятельство заключается в том, что при создании нового формата его автор может нечаянно полностью или частично воспроизвести магические значения другого формата. Хотя такое совпадение и кажется невероятным, это все же иногда происходит. Известен случай, когда программисты, заимствуя идеи с других платформ, были уверены в том, что их усилия защищены "китайской стеной" архитектурной несовместимости. Очевидно, что подобное наивное предположение разработчиков — не более чем недостаток квалификации. Раньше проблемы с форматами, имеющими похожие идентификационные поля, возникали крайне редко и разрешались в основном путем анализа контекста. Можно ожидать, что в будущем таких проблем у пользователей прибавится вследствие более широкого применения локальных, региональных и глобальных сетей, которые позволяют получать доступ к данным, созданным на других платформах.
Третье обстоятельство проявляется в тех случаях, когда распространитель формата (не обязательно разработчик) умышленно или случайно изменяет его спецификацию, сохраняя при этом идентификатор, определенный документацией данного формата. В этом случае программа распознает формат, но не всегда может прочесть его данные. Если распространитель сделал это умышленно, то изменения не документировались. К сожалению, специалисты уже не раз сталкивались с некорректно документированными изменениями форматов. Так было, например, с файловыми форматами GIF, TIFF и TGA. Распространители форматов GIF и TGA, которые не всегда являются разработчиками, расширяют или изменяют их для того, чтобы включить в них новые типы данных. В формат TIFF были внесены таким образом изменения, названные "удобными обновлениями", предназначенные, по-видимому, специально для того, чтобы вызывать ошибки кодирования и случайные сбои прикладных программ.
Версия файла
После идентификатора в заголовке файла обычно располагается поле версии файла. Естественно, версии одного и того же формата могут иметь различные характеристики (размер заголовка, поддерживаемые данные и цвета). Поэтому после идентификации формата с помощью ID-значения программа обычно проверяет номер версии, чтобы определить, сможет ли она обработать данные, содержащиеся в этом файле.
Информация, описывающая изображение
После полей идентификатора и версии файла следуют несколько полей, описывающих само изображение. Как правило, растры физически или логически организованы в строки пикселей. Поле количество строк в растровом изображении, также называемое длиной изображения, высотой изображения или количеством строк развертки, содержит значение, определяющее количество строк в реальных растровых данных. Количество пикселей в строке, также называемое шириной изображения или шириной строки развертки, определяет количество пикселей, сохраненных в каждой строке.
Количество битов на пиксель определяет размер данных, необходимых для описания каждого пикселя в цветовой плоскости. Иногда в этом поле в действительности сохраняется информация о количестве байтов на пиксель. Это поле характеризует пиксельную глубину. Наиболее распространенной ошибкой при разработке программ чтения форматов является неправильная интерпретация программистами значения этого поля. Если растровые данные были записаны в виде последовательности плоскостей, то поле количество цветовых плоскостей определяет количество используемых цветовых плоскостей. Чаще всего его значение равно единице, что свидетельствует о тенденции сохранения растров в одноплоскостном формате. В то же время многоплоскостные форматы продолжают применяться для поддержки специального оборудования и альтернативных цветовых моделей. Количество битов в строке изображения можно рассчитать, умножив значение поля количество битов на пиксель на количество пикселей в строке и количество цветовых плоскостей. Кроме того, разделив полученный результат на восемь, можно определить количество байтов в строке развертки.
Тип сжатия
Если с целью уменьшения объема файла формат поддерживает какой-нибудь вид кодирования, то в заголовок должно быть включено поле тип сжатия (тип компрессии). Некоторые форматы поддерживают несколько алгоритмов компрессии, включая необработанные и несжатые данные. Часто модификации форматов — это главным образом дополненные или измененные уже используемые схемы сжатия. Проблема сжатия данных постоянно привлекает внимание разработчиков, поэтому достаточно часто появляются новые, более совершенные алгоритмы компрессии.
Координаты изображения
Поля х-координата начала изображения и у-координата начала изображения определяют координаты точки начала изображения на устройстве вывода. Чаще всего они имеют значения (0, 0), что позволяет совмещать начало изображения с точкой отсчета системы координат устройства. Если же применяются другие координаты, то при визуализации изображение начнет воспроизводиться с другой точки. Большинство растровых форматов изначально спроектированы для различного рода устройств вывода. Растровый формат можно рассматривать как модель реального или виртуального устройства, имеющего так называемую поверхность отображения. Такая поверхность содержит неявную точку отсчета, относительно которой определяется размещение начальной точки изображения, и неявную ориентацию, задающую направление черчения линий при его воспроизведении. Различные форматы и разные устройства отображения по-разному определяют позицию точки отсчета и ориентацию. Во многих случаях точку отсчета системы координат устройства помещают в левый верхний угол поверхности отображения, хотя есть варианты, когда эта точка находится в центре или в левом нижнем углу. Значительно реже точка отсчета размещается в правом верхнем либо в правом нижнем углу поверхности отображения. Координатные модели, в которых точка начала координат размещается в левом верхнем углу поверхности отображения, исторически сложились как средство поддержки оборудования. Люди, обладающие математическими и естественно-научными знаниями, предпочитают, однако, применять координатные модели, в которых начало координат находится в левом нижнем углу или в центре поверхности отображения. Проанализировав размещение точки начала изображения и его ориентацию в конкретном формате, можно достаточно точно угадать, какими базовыми знаниями обладал его разработчик. Некоторые форматы требуют явного задания точки отсчета и ориентации. Если программа обработки графического файла построена на некорректных предположениях об используемой системе координат, то изображение может появиться "вверх ногами", в зеркальном отражении, либо может быть смещено по горизонтали или вертикали. Иногда в заголовок включают поле текстового описания растра. Это поле представляет собой комментарий, содержащий произвольные символьные (в формате ASCII) данные, например название изображения, имя файла, имя автора изображения и/или имя программы, использованной для его создания. Чтобы обеспечить возможность переносить информацию заголовка на другие платформы, это поле содержит только 7-битовые данные в формате ASCII.
Неиспользуемое пространство
В конце заголовка могут располагаться неиспользуемые поля, иногда называемые набивкой, заполнителе зарезервированным пространством или зарезервированными полями. Зарезервированные поля не содержат данных, описываются и не структурируются. Их размеры и местоположение в заголовке известны. Если возникнет необход мость расширить формат, то сведения о новых данных заносятся в зарезервированное пространство. Таким образ< сохраняется совместимость с программами, поддерживающими старые версии этого формата, а проблемы, связанн) с появлением новых версий, сводятся к минимуму. Заголовок формата имеет фиксированную длину и структу! В процессе модификации формата его структура усложняется, при этом новые поля добавляются в зарезервированн] области заголовка без изменения его размеров. Часто заголовок специально расширяется зарезервированными поля» до общей длины 128, 256 или 512 байтов. Это связано с необходимостью учитывать размеры буферов ввода/выво для повышения производительности системы. Наличие таких полей свидетельствует о том, что автор формата забыл о проблемах производительности и кэширования файлов. Иногда зарезервированные поля являются просто артефактами, которые возникают в процессе развития форма или остаются от рабочих версий. Распространитель обычно изменяет или расширяет файловый формат только п давлением обстоятельств или в ответ на требования рынка, обусловленные непредвиденным развитием технологи Как в одном, так и в другом случае развитие формата крайне трудно планировать, что обуславливает стремлен производителя минимизировать усилия на "встраивание" новых данных. Зачастую первое, чем приходится жертв вать, — это совместимость с предыдущими версиями.
Примеры растровых заголовков
Пример 1: Заголовок формата Microsoft Windows Bitmap, версия 1.х
II
II Структура заголовка формата MS Windows l.x Bitmap Format
// BYTE — это однобайтовое беззнаковое символьное значение
// WORD — это короткое беззнаковое целое (16 битов)
//
typedef struct _WinHeaderlx
{
//
// Тип Имя Смещение Комментарий
//
WORD Type; /* OOh Идентификатор типа файла (всегда 0) */
WORD Width; /* 02h Ширина растра в пикселях */
WORD Height; /* 04h Высота растра в пикселях */
WORD Width; /* 06h Ширина растра в байтах */
BYTE Planes; /* 08h Количество цветовых плоскостей */
BYTE BitsPixel; /* 09h Количество битов на пиксель */
} OLDWINHEAD;
Как видно из комментариев, этот заголовок содержит идентификатор типа файла, а также информацию о шири и высоте изображения, ширине одной строки изображения (в байтах), количестве цветовых плоскостей и количестве битов на пиксель. Это необходимый минимум информации, позволяющий описать растровое изображение таю образом, чтобы оно могло быть прочитано и визуализировано на произвольно выбранном оборудовании. Обратите внимание на то, что заголовок Windows Bitmap l.x не содержит информации о цветах и сжатии дани изображения. Расширенный формат изображений должен предусматривать возможности описания цветовой информации и хотя бы простой схемы сжатия. Следующий пример — более сложный заголовок формата файла изображения Sun Raster
Пример 2: Заголовок формата Sun Raster
II
II Структура заголовка формата Sun Raster Image File Format
// WORD — это длинное целое без знака (32 бита)
//
typedef struck _SunRasterHead
{
//
//Тип Имя Смещение Комментарий
//
WORD Magic; /* OOh Магическое число (59a66a95h) */
WORD Width; /*04h Ширина изображения в пикселях */
WORD Height; /*Q8h Высота изображения в пикселях. */
WORD Depth;. /*Och Количество битов на пиксель */
WORD Length; /*10h Длина изображения в байтах .*/
WORD Type; /*14h Тип кодирования */
WORD MapType; /*18h Тип цветовой таблицы */
WORD MapLength; ICh Длина цветовой таблицы в байтах */
} SUNRASHEAD;
Заголовок формата Sun Raster, кроме информации, описанной в заголовке Windows Bitmap 1 .х, содержит сведения о типе кодирования, а также о типе и размере цветовой таблицы, или палитры, связанной с этими растровыми данными. Ни в одном из этих двух заголовков нет поля текстового описания. Теперь рассмотрим заголовок файлового формата Kofax Raster.
Пример 3: Заголовок формата Kofax Raster
//
// Структура заголовка формата Kofax Raster Image File Format
// LONG — это длинное целое со знаком (32 бита)
// SHORT — это короткое целое со знаком (16 битов)
//
typedef struct _KofaxHeader
{
//
//Тип Имя Смещение. Комментарий
//
LONG Magic; /* Ooh Магическое число (68464B2Eh) */
SHORT HeaderSize; /* 04h Размер заголовка */
SHORT HeaderVersion; /* 06h Номер версии заголовка */
LONG Image Id; /* Oah Идентификатор изображения */
SHORT Width; /* Och Ширина изображения в байтах */
SHORT Length; /* Oeh Длина изображения в строках развертки */
SHORT Format; /* 10h Кодирование */
CHAR Bitsex; /* llh He 0, если Bitsex инвертирован */
CHAR Color; /* 12h He 0, если цвет инвертирован */
SHORT Xres; /* 14h Количество точек на дюйм по горизонтали */
SHORT Yres; /* 16h Количество точек на дюйм по вертикали */
CHAR Planes; /* 18h Количество плоскостей */
CHAR BitsPerPixel; /* 19h Количество битов на пиксель */
SHORT PaperSize; /* lAh Исходный размер бумаги */
CHAR Reservedl[20]; /* Ich Резервное поле */
LONG Dcreated; /* 30h Дата создания */
LONG Dmodified; /* 34h Дата модификации */
LONG Daccessed; /* 38h Дата доступа */
CHAR Reserved2[4]; /* 3Ch Резервное поле */
LONG loffset /* 40h Смещение Index Text Info */
LONG Ilength /* 44h Длина Index Text Info */
LONG Coffset /* 48h Смещение комментария */
LONG Clength /* 4Ch Длина комментария в байтах */
LONG Uoffset /* 50h Смещение данных пользователя */
LONG Ulength /* 54h Длина данных пользователя в байтах */
LONG Doffset /* 58h Смещение данных изображения */
LONG Diength /* 5Ch Длина данных изображения в байтах */
CHAR Reserved3[32]; /* 60h Резервное поле */
} KFXHEAD;
Обратите внимание на то, что заголовок формата Kofax Raster значительно больше, чем заголовки Windows Bitmap или Sun Raster. Он включает поля, задающие горизонтальное и вертикальное разрешения, размер бумаги, на которую будет выведено изображение, смещения различных вспомогательных данных в файле, время и дату создания изображения, его последней модификации и доступа. Несколько полей в этом заголовке помечены как резервные. Заголовок формата Kofax Raster специально дополнен до 128 байтов, чтобы можно было использовать часто применяемый размер буфера для чтения и записи, хотя в представленной здесь модификации заголовок занимает всего 72 байта. Спецификация формата Kofax Raster гарантирует, что первые 128 байтов каждого файла изображения Kofax можно интерпретировать как заголовок в любой модификации формата. Программа может просто игнорировать зарезервированные поля. Общая информация о зарезервированных полях представлена в разделе "Неиспользуемое пространство".
Оптимизация чтения заголовка
Чтение данных заголовка может осуществляться различными способами. Проанализировав, как ваша программа использует имеющиеся данные, вы можете оптимизировать скорость чтения. Если вам нужны не все данные из заголовка, то программа может рассчитать смещение требуемых данных относительно некоторого контрольного ориентира, например относительно начала файла, найти и прочесть их. Смещения полей от начала заголовка, приведенные в комментариях к примерам, могут быть использованы для поиска нужных данных. Если программе требуется большинство из содержащихся в заголовке данных, то, вероятно, целесообразно прочесть весь заголовок в буфер или специально выделенную для этих целей структуру данных. Такое чтение, как правило, выполняется очень быстро. После этого все данные заголовка становятся доступными в памяти и при необходимости могут быть кэшированы для дальнейшего использования. Однако если порядок байтов в словах в системе, в которой записывался файл, отличается от принятого в системе, в которой файл читается, может возникнуть проблема. Например, большинство функций блочного чтения файлов не предусматривают автоматического преобразования данных. Другая проблема может возникнуть в том случае, если компилятор или среда исполнения программы выравнивают элементы структуры по определенной границе.
Растровые данные
Реальные растровые данные обычно занимают большую часть растрового файла. В большинстве форматов растровых файлов растровые данные располагаются непосредственно после заголовка, но могут размещаться и в любом другом месте файла. Вместе с ними могут храниться палитра и другие данные. В таком случае в заголовке в поле смещения данных изображения (либо в документации) указывается местоположение начала данных изображения в файле. Структура растровых данных в большинстве форматов довольно проста. Растровые данные состоят из пиксельных значений. На устройстве вывода пиксели обычно выводятся в виде строк развертки по всей ширине поверхности отображения, и этот факт, как правило, определяет порядок расположения данных в файле. Поэтому информация о том, на какое устройство вывода ориентировался разработчик формата, возможно, поможет вам "вычислить" точный порядок расположения данных. Строки развертки объединяют пиксельные данные в двухмерную сетку, что позволяет нам рассматривать местоположение каждого пикселя растра в заданных логических координатах. Растр может быть представлен и в виде последовательности значений, которые логически отображают в файле растровые данные, соответствующие картинке на поверхности отображения устройства вывода. Реальные растровые данные обычно составляют большую часть любого растрового файла.
Как растровые данные записаны в файле … Продолжение »