МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ УКРАИНЫ ДОНЕЦКИЙ НАЦИОНАЛЬНЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ МЕТОДИЧЕСКИЕ УКАЗАНИЯ И ЗАДАНИЯ К КУРСОВОЙ РАБОТЕ ПО КУРСУ “МЕТОДЫ И СПОСОБЫ КОМПЬЮТЕРНЫХ ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ ” для студентов специальности 6.050101 “ Компьютерный эколого-экономический мониторинг” Утверждено на заседании кафедры “Компьютерные системы мониторинга” протокол № 3 от 26.11.10 Утверждено на заседании учебно-издательского совета ДонНТУ протокол № __ от __________ Донецк – ДонНТУ - 2010 УДК 681.3 Методические указания и задания к курсовой работе по курсу “Методы и способы компьютерных информационных технологий“, (для студентовзаочников специальности 7.080403 “Программное обеспечение автоматизированных систем”/ сост.: доц. Губенко Н.Е., асс. Миргород В.С. – Донецк: ДонНТУ, 2010 - 73 с. Приведены теоретические сведения, методические рекомендации, примеры и задания для выполнения курсовой работы на тему «Разработка программных средств для просмотра, преобразования и создания графических эффектов в файлах графических форматов»: Составители: Губенко Н.Е., к.т.н., доцент Миргород В.С., ассистент Рецензент: Светличная В.А., к.т.н., доц. каф. АСУ 3 Тема: Разработка программных средств для просмотра графических файлов, создание графических эффектов. Целью курсовой работы является изучение форматов графических файлов, алгоритмов сжатия графической информации, алгоритмов создания различных графических эффектов и реализация программы-просмотрщика файлов графических форматов. Методические указания к выполнению курсовой работы В настоящие время проблема компактного хранения информации очевидна. С каждым годом появляется всё более совершенная графическая аппаратура и более сложные графические приложения. Это предъявляет жесткие требования к форматам хранения графической информации. За прошедшие два десятилетия родились и умерли сотни форматов. Для хранения графической информации, данные должны быть представлены в удобном виде для их последующей обработки. Существует множество графических форматов, таких как: BMP, PCX, GIF, TGA, IMG, TIFF и др. И у каждого формата есть свои сильные и слабые стороны. Более сложные форматы, обеспечивая хорошую степень сжатия, требуют и больших вычислительных ресурсов для их чтения и вывода, но, в то же время они дают более качественное изображение, чем простые, при малой степени сжатия и более легком способе представлении данных. Форматы отличаются не только способом хранения информации на носителе, но и кодируемыми данными, что также формирует определённые трудности при перенесении информации из файлов одного формата в другой. Среди этого разнообразия стоит выделить форматы GIF и BMP. 4 Формат BMP – основной формат Windows. Это несжатый формат, хотя для него предусмотрено сжатие простым байт-ориентированным алгоритмом, которое более развито в формате PCX. Формат BMP легко конвертируется в другие форматы без каких либо промежуточных форм, если для него не было применено сжатие. Более прогрессивный алгоритм JPEG способен уменьшать объём графической информации в десятки раз. Его принцип основан на восприимчивости зрения к основному цвету нежели к его тону. При достаточно большом сжатии может ухудшиться качество изображения. Формат JPEG стал стандартом для сети Internet. 1 ФОРМАТ ФАЙЛА BMP Файл BMP может содержать изображения, размером 2**32х 2**32 пикселей и глубину цвета от 1 до 24 бит. Основными элементами файла являются: - заголовок; - палитра (если нужна); - изображение. 1.1 Заголовок файла Файл начинается заголовком. Структура заголовка представлена ниже: TBMHeader=record Sign:integer; {Подпись} Size:longint; {Длина файла} Reserv1:integer; {-} Reserv2:integer; {-} Lock:longint; {Местонахождение растрового массива} HeadLen:longint; {Длина заголовка} Width:longint; {Ширина изображения} Height:longint; {Высота изображения} PlNum:integer; {Количество цветовых плоскостей} BitPix:integer; {Бит/пиксель} Compr:longint; {Метод сжатия} 5 MassLen:longint; HorRazr:longint; VerRazr:longint; ColNum:longint; MainColNum:longint; end; {Длинна растрового массива} {Горизонтальное расширение} {Вертикальное расширение} {Число цветов изображения} {Число основных цветов} Рассмотрим подробнее структуру заголовка файла BMP. Sign - подпись, говорящая о том, что это файл BMP. Поле всегда имеет значение 'BM' = 424Dh. (Вернее было бы сказать, что несовпадение этой подписи с 'BM' говорит о том, что это не BMP-файл.) Size - размер файла. Позволяет судить о целостности данных файла. Reserv1,Reserv2 - Резерв Поля имеют нулевое значение, однако, значения программой чтения не проверяются. Lock - Местонахождение растрового массива. Смещение данных изображения относительно начала файла. HeadLen - Длина заголовка в байтах. Во многих источниках принято отделять все поля начиная с Sing и до Lock включительно от остальных полей заголовка и называть первые пять полей "Заголовком файла", а остальные "Заголовком изображения". "Заголовком файла" - всегда 16 байт. В поле HeadLen указан размер "Заголовком изображения" и в большинстве случаев содержит значение 28h (40). Width - Ширина изображения в пикселях. Height - Высота изображения в пикселях. PlNum - Количество цветовых плоскостей изображения. BitPix - бит на пиксель. По этому полю определяется количество цветов. Compr - Поле это указывает тип сжатия информации. 0 - без сжатия. 1 – RLE алгоритм. MassLen - Длина растрового массива. HorRazr,VerRazr - разрешение горизонтальное и вертикальное. ColNum - количество цветов изображения. 6 MainColNum - количество "главных" цветов. Если вдруг программа просмотра обнаружила, что она не может отобразить 256 цветов (а изображение, предположим, содержит именно столько), ей следует отображать максимальное количество "главных" цветов, информация о которых содержится в первых элементах палитры. 1.2 Палитра Палитра расположена сразу за заголовком. Её наличие определяется количеством цветов в изображении. Если их больше 256 - палитра не хранится (пиксели представлены триплетами прямо в растровом массиве). На каждый цвет палитра отводит 4 байта (R,G,B,Rs) - Red,Green,Blue,Reserv. Reserv всегда имеет значение 0. 1.3 Чтение BMP файла Размер каждой строки растровой матрицы выровнен по 32-х битной границе. Для определения этого размера используется очевидная формула – size = (4-(Width mod 4)) and 3; Но следует помнить, что: 1.изображение в файле BMP храниться начиная с нижней строки. 2. При 256 цветах 1 байт = 1 пиксель, при 16 - 1 байт = 2 пикселя, при 2 - 1 байт = 8 пикселей. 2 ФОРМАТ ФАЙЛА PCX Формат PCX был разработан фирмой ZSoft для PC Paintbrush под MSDOS. Формат по соглашению с фирмой M$ перешел в ее собственность вместе с программой и получил широкое распространение. Файл PСХ может содержать одно изображение размером не более 65535х65535 пикселей. Количество цветов может быть 2,16,256,16777215. Тип изображения - растровое. 7 Файл PCX состоит из следующих частей: - заголовок; - изображение; - палитра VGA. 2.1 Заголовок файла PCX Рассмотрим структуру заголовка файла PCX: TPCXHeader = record ID: byte; {Идентификатор} Vers: byte; {Версия файла} Encode: byte; {Кодирования} BitPerPix: byte; {Количество бит на пиксел} Xstart: word; {Левая граница} Ystart: word; {Верхняя граница} Xend: word; {Правая граница} Yend: word; {Нижняя граница} HorRez: word; {Гор. разрешение} VerRez: word; {Вер. разрешение} EGAPal: array [1..48] of byte;{Палитра EGA} Res1: byte; {-} NumPl: byte; {Количество битовых плоскостей} BytePerLine: word; {Байт на строку развертки} PallType: word; {Тип палитры} HorScSize: word; {Размер экрана по горизонтали} VerScSize: word; {Размер экрана по вертикали} Res2: array[1..54] of byte; {-} end; ID - идентификатор файла PCX. Значение всегда 0Ah. Если значение отлично от 0Ah, на этом можно заканчивать обработку изображения. Vers - значение этого поля указывает на версию PCX. Каждая версия подразумевает определенные требования для программ чтения (таблица 1). 8 Таблица 1 Значение Версия формата 0 Версия 2.5 с фиксированной палитрой EGA 2 Версия 2.8 с модифицируемой палитрой EGA 3 Версия 2.8 без палитры 4 Версия PC Paintbrush для Windows 5 Версия 3.0 Encode - указывает на схему кодирования. Согласно спецификации PCX, это поле может иметь два значения: 0 - данные не кодируются 1 - данные кодируются с использованием байт-ориентированной RLE-схемы. Следует отметить, что данные кодируются всегда, а значение этого поля большинством программ игнорируется. BitPerPix - количество бит, отводимых на пиксель в одной цветовой плоскости. Значением поля может быть 1,2,4,8. Важно помнить, что данные строки развертки дополняются нулями до четного количества байт. Значение этого поля можно использовать для отделения данных от заполнителя. Xstart,YStart,XEnd,YEnd - Описывают размеры изображения и его положение на экране. Большинство программ игнорирует возможность размещения изображения в произвольной части экрана. Но следует отметить важную особенность: изображение может иметь фактический размер отличный от описанного этими полями. Пример: Xstart=0,XEnd=100, а длинна строки 108 пикселей. В изображение могут быть включены лишние строки. В любом случае программа чтения файла должна отображать только ту часть изображения, которая находится в прямоугольнике, описанном (Xstart,YStart) и (XEnd,YEnd). HorRez,VerRez - горизонтальное и вертикальное разрешение изображения. Для декодирования изображения эти поля не нужны и носят лишь информативный характер. EGAPal - массив из 48 байт. Представляют собой палитру. Res1 - поле не используется начиная с Версии 2. Раньше обозначало режим дисплея, на котором создавалось изображение. 9 NumPl - задает количество цветовых плоскостей изображения. Возможные значения: 1,3,4. Комментарии по использованию этого значения представлены в таблице 2. Таблица 2 NumPl BitPerPix 1 1 1 2 3 1 4 1 1 8 3 8 Максимальное число цветов 2 4 8 16 256 16777216 Видеорежим Монохромный CGA EGA EGA и VGA Расширенный VGA Расширенный VGA и XGA BytePerLine - размер незакодированной строки развертки одной цветовой плоскости в байтах. Умножая это значение на значение поля NumPl, получаем общую длину строки развертки в байтах. PallType - тип палитры. 1-цветная или монохромная палитра, 2-градации серого цвета. Это поле игнорируется практически всеми программами, использующими PCX. HorScSize,VerScSize - содержат информацию о разрешении экрана, на котором было создано изображение. Res2 - 54 байта должны содержать нули. Дополняют заголовок до 128 байт. 3 ФОРМАТ ФАЙЛА TGA Файл TGA начинается с заголовка, затем идет необязательное поле идентификации изображения, необязательная цветовая таблица, растровые данные. Но есть и формат TGA 2.0, который полностью повторяет оригинальный формат, дополняя его рядом новых элементов. Все они, кроме концовки, являются необязательными и включаются в файл по желанию 10 разработчика изображения. Концовка необходима для того, чтобы отличить один формат от другого. Ниже приведены элементы: - директория разработчика; - область разработчика; - область расширения; - таблица цветовой коррекции; - почтовая марка (уменьшенное изображение); - таблица строк развертки; - концовка. 3.1 Заголовок файла TGA TTGAHeader = record IDLength: byte; ColorMapType: byte; ImageType: byte; CMapStart: word; CMapLength: word; CMapDepth: byte; XOffset: word; YOffset: word; Width: word; Height: word; PixelDepth: byte; ImageDesc: byte; end; {Размер поля ID-изображения} {Тип цветовой палитры} {Код типа изображения} {Начало палитры} {Длинна палитры} {Глубина элементов палитры} {Смещение по горизонтали} {Смещение по вертикале} {Ширина} {Высота} {Размер пикселя} {Дескриптор изображения} IDLength - указывает размер поля идентификации изображения, которое идет сразу за заголовком. Eсли это поле имеет значение 0, то области идентификации изображения в файле нет. ColorMapType - определяет наличие цветовой таблицы. Если это поле равно 1 - таблица есть, 0 -нет, если лежит в пределах от 2 до 255 - таблица есть, но формат ее понятен только программе, создавшей файл. ImageType - тип изображения. 11 Таблица 3 Значение 0 1 2 3 9 10 11 Тип данных изображения Цвет таблицы Кодировка В файле нет данных Нет изображения Изображение с таблицей Есть TrueColorImage Нет Монохромное Нет Изображение с таблицей Есть TrueColorImage Нет Монохромное Нет Нет Нет Нет Нет Есть Есть Есть Файлы TGA кодируются алгоритмом RLE. CMapStart - Смещение первого элемента в таблице цветов. CMapLength - Количество элементов цветовой таблицы. CMapDepth - Количество битов в элементе таблицы. ImageDesc - Описание изображения. Несет в себе следующую информацию: 7-6 биты - резерв, всегда 0. 4-5 биты - определяют позицию начала изображения. Если оба бита равны 0, то изображение начинается в левом нижнем углу. 0-3 биты - количество битов атрибутов в пикселе (альфа-канал, оверлейные биты и биты прерывания). 4 ФОРМАТ ФАЙЛА TIFF TIFF - это новый формат для файлов, удобный своей открытостью. Любые новые характеристики изображений могут быть включены в TIFF-файл (то есть в файл изображений в стандарт TIFF) без изменения программ, работающих с форматом TIFF. Кроме того, в отличие от других форматов, TIFF поддерживает одновременно как несжатые изображения, так и сжатые большим 12 количеством разных способов. TIFF быстро становится мировым стандартом. Многие известные компании сообщили о поддержке этого стандарта. 4.1 TAGовая архитектура Tagged architecture - организация, при которой с каждым словом памяти связан аппаратно или программно-реализуемый TAG, указывающий тип хранимой информации и определяющий множество применимых операций и способ их выполнения. TAG - часть элемента данных, определяющая их тип (поле записи, один или несколько разрядов слова). 4.2 Различия между TIFFом и другими форматами Традиционные форматы файлов изображений используют фиксированную организацию, то есть каждый параметр картинки имеет точный адрес относительно начала файла. В случае ненужности какого-либо параметра место для него все равно резервируется, но не используется. При использовании стандарта TIFF в файл входят только те параметры, которые необходимы пользователю. При этом файл получается меньше по объему, и ускоряет поиск нужного параметра. Структура TIFF аналогична структуре базы данных. Ниже приведена примерная структура TIFF-файла. Каждый tag TIFF-файла представляет собой заголовок информации, описанной где-то в файле. TIFF HEADER pointer Заголовок TIFF-файла колTAGов Tag 1 Tag 2 pointer Пример TAGа TAG TYPE SIZ LENGHT DATA Указатель на первую директорию TAGов Тип TAGa Размер Длина Данные или 13 Tag 3 pointer LONG TAG DATA BIT-MAP IMAGE DATA IMAGE DATA (continue) OR POINTER указатель на них Содержимое (значение) TAG 2 (не уложилось в 12 байт размер TAGa) Само изображение 4.3 Преимущества формата TIFF - Практически неограниченное количество параметров изображения; - возможность использования различных цветов, палитр, оттенков серого, приемов сжатия и прочих разнообразных возможностей; - экономия памяти на диске - дисковое пространство занимают только поля, содержащие информацию; - широкое распространение TIFFa как мирового стандарта. 4.4 Недостатки формата TIFF - некоторая сложность в понимании и восприятии формата (в сравнении с фиксированным); - нет ни одного стандартного TIFF-файла. Различные версии имеют некоторые отличия и поддерживают разные наборы полей; Различные версии TIFFa все поддерживают некоторый стандартный набор полей, а дополнительными полями нужно пользоваться с некоторой долей осторожности. Недостатки преодолимы. 4.5 Заголовок файла TIFF Заголовок - информация о всем TIFF-файле, как о едином целом. BYTE ORDER VERSION POINTER Порядок следования файлов Hомер версии TIFFa Адрес первой директории TAGов 14 FIRST DIRECTORY Порядок следования файлов: 49 49 INTEL-формат ASCII I; 4D 4D Motorola-формат ASCII M INTEL : AB CD означает число CDAB; Motorola: AB CD означает число ABCD. 4.6 Directory (оглавление) Оглавление состоит из трех частей A ENTRY COUNT Количество TAGов A+2 TAG 0 A+14 TAG 1 TAG 1 вместо данных содержит их адрес A+2+12n TAG A+14+12n OFFSET TO Адрес следующего оглавления или если NEXT DIRECTORY его нет (if any) TAG DATA Данные, не уместившиеся NOT FITTING в TAGе 1 IN TAG 1 ENTRY COUNT показывает, сколько TAGов находятся в оглавлении. Далее идут TAGи (параметры изображения). Все TAGи фиксированной длины (12 байт). Последнее поле - адрес следующего оглавления. Если эта последняя директория, то это поле должно быть заполнено нулями. 4.7 Tag entry TAG - основная базовая единица формата TIFF. Образец TAGa представлен ниже. Каждый TAG имеет размер 12 байт и строго определенную структуру. A A+2 A+4 A+8 TAG TYPE DATA TYPE LENGTH VALUE OR POINTER Тип TAGa Тип данных Длина данных Данное или адрес другого данного Первые 2 байта описывают тип информации, связанной с данным TAGом. Например, значение 282 (11А) говорит о том, что этот TAG несет информацию о разрешении изображения по оси Х. 15 Следующие 2 байта показывают, какой тип данных используется в TAGе. Очередные 4 байта содержат в себе длину информации TAGa, измеряемую в предыдущем поле единицах. Последние 4 байта могут быть использованы в двух целях. Они могут быть адресом относительно начала файла, по которому находятся данные TAGa, а могут быть и самими данными. Если данные вмещаются в 4 байта, то они могут быть расположены в четвертом поле, в противном случае, эти байты представляют собой адрес данных. Чтобы определить какой из двух принципов применен, необходимо посмотреть длину данных в байтах (умножив длину поля на количество байтов в данном типе данных). Если результат больше 4 байт, это означает, что в TAGе адрес данных, иначе - сами данные. 4.8 Совместимости TAG имеют интересную особенность. Они могут быть как общие (определенные стандартом TIFF), так и особенные (определенные некоторыми фирмами для своих целей). Общие TAGи поддерживаются всеми фирмами, а особенные лишь создателями и пользователями. 4.9 Список типов TAGов TAGи в директории должны быть расположены в порядке возрастания их номеров. Это позволяет быстро находить нужный TAG или адрес данных TAGa. OFF (H) 100 101(H) Subfile type. Тип данных - 3. Во всех примерах имеет значение 1. Встречается во всех примерах. Image width. Ширина изображения (в пикселах). Тип данных - 3, длина данных - 1. Данные всегда находятся в TAGе Данные сдвинуты влево и последние 2 байта значимой информации не несут. Image length. Длина изображения (в пикселах). 16 102(H) 103(H) 106(H) 107(H) 108(H) 109(H) 10A 10D 10Е(H) 10F(H) 110(H) 111(H) 112(H) Дале полностью аналогично 100 (H). Bits per sample. Количество бит на точку. Тип данных - 3. Например: черно-белое бинарное изображение - 1 бит на точку, 16 цветов - 4 бита на точку и т.д. Compression. Тип сжатия (если изображение сжато). Тип данных - 3. 1=несжатое изображение 2=сжатие CCITT/3 и т.д. Photometric Interp Фотометрическая интерпритация. тип данных - 3, длина данных - 1. 0 - "1" в файле соответствует черному цвету, 1 - "1" белое и т.д. Thresholding. Порог. Информация об этом TAGе не имеется. Cell width. Ширина ячейки. Информация об этом TAGуе не имеется. Cell lenght. Длина ячейки. Информации об этом TAGе не имеется. Fill order. Порядок заполнения. Имеет тип 3, длину 1. 1=заполнение MSB в LSB. MSB - старший бит, LSB - младший бит. Например: пусть имеем 3 бита на точку, тогда есть два варианта заполнения байта Document name. Название документа. Image description. Описание изображения. Тип данных - 2. Make. Производство. Тип даных - 2. Model. Модель. Тип данных - 2. Strip offset. Адрес начала изображения. Тип данных - 4. Всегда содержит адрес начала непосредственно самого изображения. Orientation. Ориентация. Тип данных - 3, длина данных - 1. 1=normal orientation. 17 118(H) 119(H) 11A(H) его выводе. 11B(H) 11C(H) 11D(H) 11E(H) 11F(H) 120(H) 121(H) 122(H) 123(H) 124(H) 125(H) 128(H) Предположительно, позволяет поворачивать изображение не изменяя самого изображения, а изменяет лишь данные, связанные с этим TAGом. Min sample value. Минимальное значение точки. Тип данных - 3, длина данных - 1. Например, в черно-белом бинарном изображении принимает значение 0. Max sample value. Максимальное значение точки. Аналогично 118(H). X Resolution. Разрешение по оси Х. Тип данных - 5, длина - 1. Так как дробь требует минимально 8 байт, то дробь не умещается в TAGе. Так что последние 4 байта всегда содержат указатель на 8 байт информации. Предположительно обозначает количество точек на дюйм, имевшееся при вводе изображения или необходимое при Y Resolution. Разрешение по оси Y. Аналогично 11А(H). Planar configuration. Тип данных - 3, длина - 1. 1=planar config is normal. Page name. Название страницы. Тип данных - 2. X Position. Координата Х. Смещение изображения по оси Х относительно всей страницы (предположительно левый верхний угол). Y Position. Координата Y. Аналогично 11Е(H). Free offsets. Free byte counts. Аналогично 121(H). Gray response unit. Блок представления серого цвета. Gray response curve. Огибающая серого цвета. Содержит указатель на шкалу серого. Group 3 options. Используется при сжатии. Group 4 options. Используется при сжатии. Resolution unit. 18 Блок разрешения. 129(H) Page number. Количество страниц. Color response unit. Блок цветного представления. Color response curves. Огибающая цвета. 12C(H) 12D(H) 4.10 Тип данных Существуют 5 различных типов данных. 1 = byte 2 = ascii 8-bit bytes байт из 8 бит 8-bit ASCII codes символы в ASCII коде (8 бит) 116-bit (2 bytes) 16 бит (2 байта) unsigned integer беззнаковое целое 32-bit (4 bytes) 32 бита (4 байта) unsigned integer беззнаковое целое два числа: первое - числитель, второе - знаменатель дроби. 3 = short 4 = long 5 = rational Например, тип данных TAGа "Разрешение" это дробь. Так, чтобы задать 300 точек на дюйм числитель нужно установить в 300, а знаменатель в 1. Формат ASCII нуждается информация в TIFF-файлах в некотором объяснении. Вся заканчивается символом NULL (0). ASCII Вся информация после этого символа не воспринимается. 5 ФОРМАТ ФАЛОВ GIF 'GIF' (tm) - это стандарт фирмы CompuServe для определения растровых цветных изображений. Этот формат позволяет высвечивать на оборудовании графические различном высококачественные изображения с большим разрешением и подразумевает механизм обмена и высвечивания изображений. Данный формат изображений настоящей и будущей технологии был разработан обработки для изображений поддержки и будет в 19 дальнейшем служить основой для будущих графических продуктов CompuServe. 5.1 Общий формат файла - идентификатор GIF; - дескриптор экрана; - глобальная таблица цветов; - дескриптор изображения; - локальная таблица цветов - повторяется от 1 до n раз; - растровые данные; - терминатор GIF. 5.2 Идентификатор gif Наличие в начале последующие данные файла специальной "подписи" являются действительно указывает, что потоком данных изображения в формате GIF. Эта "подпись" состоит из следующих шести символов: GIF87a Три последних символа '87a' могут рассматриваться как номер версии для данного конкретного определения GIF и будут использоваться в дальнейшем в качестве ссылки на документ с описанием GIF в зависимости от номера версии. 5.3 Дескриптор экрана Дескриптор экрана описывает последующих изображений в формате пространства изображения или общие GIF. требуемого параметры для всех Он определяет размеры логического экрана, 20 существование информации о таблице цветов и "глубине" экрана. информация запоминается в виде серии 8-битовых байтов, Эта как показано ниже. Таблица 4 биты 7654 3 210 Ширина экрана Высота экрана М Cr 0 Pixel Background 00000000 Номер байта 1 Ширина растра в пикселах (сначала LSB) 2 3 Высота растра в пикселах (сначала LSB) 4 5 М=1, за дескриптором следует глобальная таблица цветов cr +1 = число битов цветового разрешения pixel+1 = число бит/пиксел в изображении 6 фон = цветовой индекс фона экрана (цвет определяется из глобальной таблицы цветов или из таблицы по умолчанию) 7 Ширина и высота логического экрана могут быть больше размеров физического экрана. Способ высвечивания изображений больших, чем размеры физического экрана зависит от реализации и может использовать преимущества конкретного оборудования. В противном случае изображение будет усечено по краям экрана. Значение 'pixel' также определяет число цветов в изображении. Диапазон значений 'pixel' составляет от 0 до 7, что соответствует от 1 до 8 битам. Это транслируется в диапазон от 2 (черно-белые изображения) до 256 цветов. Бит 3 в байте 5 зарезервирован для будущих определений и должен быть нулевым. 5.4 Глобальная таблица цветов Глобальная таблица цветов является необязательной и рекомендуется для изображений, где требуется точная передача цветов. На существование этой таблицы указывает поле 'M' в байте 5 дескриптора экрана. 21 Цветовая таблица может быть также связана с каждым изображением в GIFфайле. Флаг 'M' в дескрипторе конкретного изображения обычно равен 0. Если глобальная таблица цветов присутствует, ее определение следует непосредственно за дескриптором экрана. Число элементов цветовой таблицы, следующей за описателем экрана равно 2**(число бит/пиксел), причем каждый элемент состоит из трех байтов, значения которых описывают соответственно относительную интенсивность красного, зеленого и синего цветов. Структура блока цветовой таблицы представлена в таблице 5. Таблица 5 Биты 76543210 Интен. красного Интен. зеленого Интен. синего Интен. красного Интен. зеленого Интен. синего : : Получаемое Байт Комментарии 1 2 3 4 5 6 Значение красного для цвета 0 Значение зеленого для цвета 0 Значение синего для цвета 0 Значение красного для цвета 1 Значение зеленого для цвета 1 Значение синего для цвета 1 (Продолжение для остальных цветов) значение каждого изображения будет соответствовать пиксела при высвечивании ближайшему доступному цвету из цветовой таблицы дисплея. Цветовые компоненты представляют собой значение относительной интенсивности от нулевой (0) до полной (255). Белый цвет может быть представлен как (255,255,255), черный как (0,0,0) и желтый как (180,180,0). При высвечивании на дисплеях, которые поддерживают менее 8 бит на цветовую компоненту, используются старшие биты. При создании элементов цветовой таблицы GIF на аппаратуре, поддерживающей менее 8 бит на компоненту, значение аппаратной компоненты должно конвертировано в 8-битный формат по следующей формуле: быть 22 <значение_в_таблице> = <компонента>*255/(2**<число_бит> -1) Это обеспечивает точный перевод цветов для всех дисплеев. В случае создания изображения GIF на аппаратуре без возможности цветовой палитры, должна быть создана фиксированная палитра на основе доступных для данного оборудования цветов. Если указано отсутствие глобальной таблицы цветов, цветовая таблица по умолчанию генерируется внутренним образом так, что каждый цветовой индекс равен аппаратному цветовому индексу modulo <n>, где <n> - число доступных цветов на оборудовании. 5.5 Дескриптор изображения Дескриптор изображения определяет действительное расположение и размеры последующего изображения внутри в дескрипторе экрана. присутствие локальной пространства, определенного Также определяются флаги, указывающие на таблицы для поиска цветов и определения последовательности высвечивания пикселов. Каждый дескриптор изображения начинается с символа- разделителя изображений. Роль разделителя изображений состоит просто в синхронизации при входе в дескриптор изображения. Это желательно, если GIF-файл состоит более, чем из одного изображения. Этот символ определен как шестнадцатиричное 0x2C или ',' (запятая). Как только встречается между этот символ изображениями, непосредственно за ним следует дескриптор изображения. Любой символ, встреченный между концом предыдущего изображения и символом-разделителем изображения игнорируется. позволит при последующих модификациях GIF допускать Это присутствие нескольких форматов и правильно игнорировать их старыми декодерами. 23 Таблица 6 Биты Байт 76543210 00101100 1 Левый край 2 3 Верхний край 4 5 Ширина 6 7 Высота 8 9 10 М I 0 0 pixel Комментарии ‘,’ – символ-разделитель изображения Начало изображения в пикселах относительно левого края экрана (сначала LSB) Начало изображения в пикселах относительно верхнего края экрана (сначала LSB) Начало изображения в пикселах (сначала LSB) Высота изображения в пикселах (сначала LSB) M=0 – Использовать глобальную таблицу цветов, игнорировать «pixel» M=1 – Далее следует локальная таблица цветов, использовать «pixel» I=0 – Изображение отформатировано в последовательном порядке I=1 – Изображение отформатировано в порядке переплетения pixel+1 – число бит на пиксел в данном изображении Описание положения и размеров экрана должно быть находиться внутри матрицы, определенной в дескрипторе экрана. С другой стороны, нет необходимости, чтобы изображение полностью заполняло весь экран. 5.6 Локальная таблица цветов Локальная таблица цветов необязательна и определена здесь для будущего использования. Если установлен бит 'M' байта 10 в дескрипторе изображения, то вслед за дескриптором изображения следует локальная таблица цветов, которая относится только к последующему изображению. После обработки изображения цветовую таблицу следует привести к той, которая была определена после дескриптора экрана. Заметим, что поле 'pixel' байта 10 в дескрипторе изображения используется только в том случае, если указана локальная таблица цветов. Она определяет не только размер пиксела (число битов в нем), но число элементов последующей 24 цветовой таблицы. Число битов на пиксел также следует восстановить к тому значению, которое было определено в дескрипторе экрана, после того, как закончится обработка изображения. 5.7 Растровые данные Формат самого изображения определен как серия значений номеров пикселов, которые образуют изображение. Пикселы запоминаются слева направо последовательно по строкам изображения. По умолчанию строки записываются последовательно, сверху вниз. В том случае, если установлен бит 'I' в байте 10 дескриптора изображения, то порядок строк при записи изображения соответствует четырех проходному процессу. При первом проходе записывается каждая 8-ая строка, начиная с верхней строки окна изображения. При втором проходе записывается каждая 8-ая строка, начиная с пятой строки сверху. На третьем проходе записывается каждая 4-ая строка, начиная с третьей строки окна. Четвертый проход завершает изображение, строку, начиная со записывая второй строки с сверху. каждую вторую Ниже приведено графическое описание этого процесса. Таблица 6 Стр. 0 1 2 3 4 5 6 7 8 9 10 Прох.1 **1а** Прох.2 Прох.3 Прох.4 **4а** **3а** **4b** **2а** **4c** **3b** **4d** **1b** **4e** **3c** Результат **1а** **4а** **3а** **4b** **2а** **4c** **3b** **4d** **1b** **4e** **3c** 25 11 12 … **4f** **2b** Значения пикселов изображения **4f** **2b** обрабатываются как цветовые индексы, указывающие на существующую таблицу цветов. В получается цветовое значение из таблицы, которое результате реально воспроизводится на экране. Эти серии цветовых индексов, число которых равно ширине_изображения*высоту_изображения, пропускаются через поток данных изображения GIF по одному значению на пиксел, сжимаются и упаковываются в соответствии с версией алгоритма сжатия LZW. 5.8 Терминатор gif Для того, чтобы обеспечить синхронизацию с окончанием файла изображения GIF, декодер GIF должен обрабатывать окончание режима GIF по символу шестнадцатиричное обработки изображения. 0x3B или По ';', найденному после окончания соглашению декодирующие программы должны делать паузу и ждать действий, указывающих, что пользователь готов к продолжению. Это может быть возврат каретки, введенный с клавиатуры или щелчок кнопкой мыши. Для интерактивных приложений эти действия пользователя должны быть переданы в ядро программы как перевод каретки, для того, чтобы вычислительный процесс мог продолжаться. декодирующая программа Обычно покидает графический режим и возвращается к предыдущему процессу. 5.9. Расширенный блок gif Для того, чтобы обеспечить аккуратное расширение определения GIF, необходим механизм для определения упаковки внутри потока данных GIF. Расширенный блок GIF пакуется способом, похожим на тот, который 26 использовался для растровых данных, но не сжимается. Основная структура блока приведена в таблице 7. Таблица 7 76543210 Байт 00100001 1 Функц.код 2 Байт-счетчик Функ.байты данных … … 00000000 Расширенный Комментарии ‘!’ – Идентификатор расширенного блока Расширенный функциональный код (0-255) Повторяется столько раз, сколько необходимо Нулевой байт-счетчик (терминатор блока) блок GIF может непосредственно предшествовать дескриптору изображения или находиться перед терминатором GIF. Все декодеры GIF должны быть способны распознавать присутствие расширенного блока GIF и затем читать его, если они не могут обработать функциональный код. Это гарантирует, что старые декодеры смогут обрабатывать файлы изображений GIF в будущем, хотя и без дополнительных функциональных возможностей. 6 ФОРМАТ ФАЛОВ PNG PNG (англ. portable network graphics, произносится "Пинг") — растровый формат, предназначенный для хранения и передачи растровых изображений: черно-белых и альфа данных - до 16 бит, а цветных - до 48 бит (truecolor). Он использует прогрессивный метод сжатия без потерь, позволяет сохранять в файле палитру, текстовую информацию и обеспечивает прозрачность. Он специально предназначен для передачи графических данных в сети. PNG был создан как свободный формат для замены GIF. 6.1 Общие сведения 27 Формат PNG создан, как альтернатива формату GIF от CompuServe, потому что фирма CompuServe, владея правами на этот формат, запрещало свободное использование метода сжатия LZW (сжатие, используемое в GIF файле) в программных продуктах. В шутку аббревиатуру PNG рекурсивно расшифровывают - "PNG's Not GIF" ("ПНГ - Не ГИФ"). PNG создавался как простой и легко распространяемый формат, содержащий в себе все преимущества формата GIF, абсолютно бесплатный и без всяких лицензионных прав и разногласий. PNG и GIF89a обладают следующими свойствами: формат организован в виде потока данных; "сжатие без потерь"; позволяет хранить индексированные изображения с палитрой до 256 цветов; прогрессивное отображение чересстрочных данных; Поддержка "прозрачного цвета"; возможность хранить данные общего и ограниченного доступа; не зависят от "железа" и платформы; Ниже перечислены преимущества PNG над GIF в общих чертах: метод сжатия данных не обременён юридическими проблемами; более быстрое прогрессивное отображение чересстрочных схем; расширенные возможности хранения пользовательских данных; А следующие возможности PNG в формате GIF вообще отсутствуют: 28 xранение полноцветных 48-битовых изображений; xранение 16-битовых чёрно-белых изображений; полный Альфа-канал; указатель на контрастность; CRC - метод обнаружения ошибок в потоке данных; стандартный инструментарий для разработки приложений чтения и записи PNG; стандартный приложений. набор тестовых изображений для проверки этих Но, всё же, некоторые особенности GIF не найдены в PNG версии 1.0: возможность хранения нескольких изображений в одном файле. анимация В отличие от многих других форматов, создатели которых (2-3 программиста) не заботятся о дальнейшем его развитии, PNG был создан особым комитетом, в состав которого вошли заинтересованные в этом специалисты и противники GIF (в список авторов спецификации PNG версии 1.0 вошли 23 фамилии) во главе с Томасом Бутеллом. PNG считается одним из лучших форматов, так как позволяет дополнять формат возможностями, не нарушая его функциональности и не требуя изменения уже существующих программных пакетов, работающих с форматом PNG, а спецификация формата является наиболее полной и понятной. 29 6.2 Организация файла PNG файл или поток данных состоит из 8-байтовой опознавательной подписи, за которой следуют 3 или более независимых блоков данных, соответствующих определённой структуре. Каждый блок имеет своё собственное определение внутреннего формата. Они читаются по очереди, от начала к концу файла или потока данных. Некоторые другие форматы также используют структуру из блоков данных. Наиболее известные среди них: GIF, IFF и RIFF. Данные в этих форматах читаются от начала к концу. Это избавляет от надобности прыгать по файлу, используя начальную адресацию. Это также позволяет без проблем использовать эти форматы с сетевыми протоколами и протоколами передачи данных. Несмотря на то, что эти форматы обычно описываются, как форматы файлов, более точным определением будет поток данных, сохранённый в файле. В формате PNG определено 4 типа стандартных блоков, иначе именуемых критические блоки, которые должны поддерживаться любой программой чтения и записи PNG. Далее следует перечень этих блоков: Заголовочный блок (IHDR) Заголовочный блок содержит основную информацию о данных изображения и должен быть первым блоком в потоке данных PNG (не допускается более одного заголовочного блока). Блок палитры (PLTE) Палитра несёт в себе данные таблицы цветов, связанный с данными изображения. Этот блок присутствует только если данные изображения используют палитру и должен находиться перед этими данными. 30 Данные изображения (IDAT) Блок данных изображения содержит в себе само изображение, и допускается несколько таких блоков в потоке данных, причём все они должны вплотную примыкать друг к другу. Замыкающий блок изображения (IEND) Замыкающий блок изображения должен находиться в конце файла или потока данных PNG. Среди этих блоков, IHDR, IDAT и IEND должны присутствовать в любом потоке данных PNG. Необязательные блоки, именуемые вспомогательные блоки, могут быть игнорированы программой чтения и необязательны для включения в файл программами записи PNG файлов. Тем не менее, отсутствие поддержки вспомогательных блоков может сказаться на непрвальном отображении изображения PNG. Оно может быть слишком затемнённым, слишком светлым или вообще отображаться в совершенно другом виде, не задуманном создателем этого изображения. Рекомендуется поддержка и использование большинства стандартных и вспомогательных блоков (в частности, блока Контрастности Изображения) программами, работающими с PNG. Вместе критические и вспомогательные блоки, определённые в спецификации PNG, соответствуют термину стандартные блоки. Люди, создающие разные спецификации PNG, ведут список дополнительных блоков, именуемых иначе специальные блоки, подлежащие огласке. Эти блоки имеют специальное применение и используются гораздо реже стандартных блоков. Список этих специальных блоков время от времени должен обновляться. Некоторые приложения могут создавать частные, закрытые для общего 31 доступа блоки для данных, которые не должны читаться другими приложениями. Ниже вкратце описаны все стандартные и специальные блоки, объявленные в издании 1.0 спецификации PNG и связанной с ней документации. Блоки распределены в относительном (но не единственно возможном) порядке, в котором они могут быть организованы в потоке данных PNG. Таблица 8 PNG-1: Блоки PNG Тип блока Многократный Необязательный Положение в файле IHDR Нет Нет Первый блок cHRM Нет Да Перед PLTE и IDAT gAMA Нет Да Перед PLTE и IDAT sBIT Нет Да Перед PLTE и IDAT PLTE Нет Да Перед IDAT bKGD Нет Да После PLTE и перед IDAT hIST Нет Да После PLTE и перед IDAT tRNS Нет Да После PLTE и перед IDAT oFFs Нет Да Перед IDAT pHYs Нет Да Перед IDAT sCAL Нет Да Перед IDAT 32 Вместе с IDAT Да Нет tIME Нет Да В любом месте tEXt Да Да В любом месте zTXt Да Да В любом месте fRAc Да Да В любом месте gIFg Да Да В любом месте gIFt Да Да В любом месте gIFx Да Да В любом месте IEND Нет Нет Последний блок остальными блоками IDAT 6.3 Детальное описание файла Подпись PNG длиной в 8 байт содержит информацию для определения файла или потока данных, в согласии со спецификацией PNG. typedef struct _PngSignature { BYTE Signature[8]; /* Идентификатор (всегда 89504E470D0A1A0Ah) */ } PNGSIGNATURE; Подпись содержит 8 байт со значениями: 89h 50h 4Eh 47h 0Dh 0Ah 1Ah 0Ah ("‰PNGrnn"). Эта на вид беспорядочная последовательность значений имеет довольно много практических назначений. Значение первого байта - 89h 8-битовое значение, указывающее на то, что файл содержит двоичные данные. Если бы каждый 8-й бит был бы вырван из файла (7-битовый канал данных), то 33 первый байт принял бы значение 09h, что указало бы на причину, по которой испорчен файл. Остальные байты имеют следующее назначение: Позволяют визуально определить поток данных (50h 4Eh 47h - "PNG") Определяют передачу файла, изменяющую последовательность символов "новой строки" ("rn" становится "r", "n" или "nr") Останавливает чтение потока данных PNG в операционной системе MSDOS (Control-Z [""]) Определяет CR/LF преобразовательные ошибки (завершающий символ новой строки) передачи файлов После подписи следуют 3 или более блоков данных PNG. Все блоки PNG имеют одинаковый основной формат и могут содержать переменное количество данных. typedef struct _PngChunk { DWORD DataLength; /* Размер поля данных в байтах */ DWORD Type; /* Код, идентифицирующий тип блока */ BYTE /* Собственно данные, хранящиеся в блоке */ Data[]; DWORD Crc; /* CRC-32 значение полей Type и Data */ } PNGCHUNK; DataLength - число байтов в поле Data. Это значение может варьироваться от 0 до 231-1. Type - 4-х байтовый код, идентифицирующий тип хранящихся данных в блоке. Каждый байт в этом поле может содержать значение заглавного или прописного латинского символа таблицы ASCII (A-Z, a-z). На пример, тип блока IHDR будет выражен значением 69484452h в поле Type. Программа чтения PNG должна рассматривать коды Type как 32-битовые буквенные значения, не являющиеся символьными строками. Возможность чтения кодов типов как символов таблицы ASCII существует лишь для удобства человеку. 34 Поле Data - собственно данные, хранящиеся в блоке. Это поле может иметь нулевую длину, если не существует связанных с ним данных. Crc - CRC-32 значение, просчитываемое для полей Type и Data. Это значение используется для определения, являются ли данные повреждёнными. В PNG используется алгоритм CRC, определённый в ISO 3309 и ITU-T V.42. Блоки бывают размером от 12 байт (не содержат данных) до (231-1)+12 байт. Блоки всегда выравниваются по границам байтов, и поэтому никогда не требуется выравнивание заполнением. Критические блоки Этот раздел описывает стандартные блоки, которые должны поддерживаться любой программой чтения и записи PNG. Заголовочный блок Заголовочный блок содержит информацию о данных изображения в PNG файле. Этот блок должен быть первым блоком в потоке данных PNG и следует непосредственно за подписью PNG. Область данных заголовочного блока составляет 13 байт и имеет следующий формат: typedef struct _IHDRChunk { DWORD Width; /* Ширина изображения в пикселях */ DWORD Height; /* Высота изображения в пикселях */ BYTE BitDepth; /* Количество битов на пиксель и образец */ BYTE ColorType; /* Индикатор интерпретации цвета */ BYTE Compression; /* Индикатор типа сжатия */ BYTE Filter; /* Индикатор типа фильтра */ BYTE Interlace; /* Тип использованной схемы чересстрочной развёртки */ } IHDRCHUNK; Поля Width и Height - высота и ширина растрового изображения в пикселях. Принимают значения от 1 до 231-1. 35 BitDepth - количество битов на пиксель для изображений с индексированными цветами и количество битов на образец для чёрно-белых изображений и полноцветных изображений (24 бита). У индексированных изображений BitDepth может принимать значения 1, 2, 4 и 8. У чёрно-белых - 1, 2, 4, 8 и 16. У полноцветных изображений без альфа данных, а также у чёрнобелых изображений с альфа данными, BitDepth может принимать только значения 8 и 16. ColorType определяет способ интерпретации данных изображения. Принимаемые значения (вид изображения): 0 (чёрно-белое), 2 (полноцветное), 3 (индексированное изображение), 4 (чёрно-белое с альфа данными) и 6 (полносветное с альфа данными). Compression определяет вид сжатия данных изображения. В настоящее время единственное допустимое значение - 0, означающее, что использован метод сжатия Defalte. Другие методы сжатия будут определены в будущих добавлениях PNG. Filter определяет вид фильтрования, применённый к данным изображения перед сжатием. На сегодняшний день, единственное допустимое значение - 0, означающее, что был применён метод фильтрования adaptive, описанный в спецификации PNG. Другие методы фильтрования будут определены в будущих добавлениях PNG. Значение поля filter не указывает, были ли данные изображения профильтрованы; на это указывает байт filter type в начале каждой строки развёртки. Данные изображения не обязательно должны быть профильтрованы перед сжатием. Interlace определяет чересстрочный алгоритм, используемый для хранения данных изображения, или, если быть более точным, порядок передачи пиксельных данных. Принимаемые значения - 0 (нет чересстрочности) и 1 (чересстрочность Adam7). 36 Палитра Палитра (PLTE) всегда присутствует в потоках данных PNG, содержащих изображения с индексированными цветами (когда поле Color заголовочного блока имеет значение 3). Полноцветные потоки данных PNG (значения поля Color - 2 и 6) также могут содержать палитру, предназначенную для разбития данных изображения на подгруппы приложениями, не поддерживающими полноцветную палитру. Поток данных PNG не может содержать более одной палитры. Палитра может быть размером от 3 до 768 байт и имеет следующий формат: typedef struct _PLTEChunkEntry { BYTE Red; /* Красный компонент (0 = чёрный, 255 = максимум оттенка) */ BYTE Green; /* Зелёный компонент (0 = чёрный, 255 = максимум оттенка) */ BYTE Blue; /* Синий компонент (0 = чёрный, 255 = максимум оттенка) */ } PLTECHUNKENTRY; PLTECHUNKENTRY PLTEChunk[]; PLTEChunk - массив, содержащий от 1 до 256 элементов, каждый из которых содержит 3 поля: Red, Green и Blue, хранящие соответственно значения красного, зелёного и синего цветов для данного элемента палитры. Блок данных изображения блок данных изображения (IDAT) содержит собственно данные изображения. В соответствии со спецификацией PNG эти данные всегда хранятся в сжатом виде. Данные изображения могут быть разбиты на несколько IDAT блоков, чтобы программе записи PNG было легче буферизировать сжатые данные изображения. У сжатого потока данных нет пределов, потому IDAT блок может быть в размере от 0 до 231-1 байт. 37 Замыкающий блок изображения Последний блок потока данных PNG - замыкающий блок изображения (IEND). Этот блок не содержит никаких данных. Вспомогательные блоки В PNG v1.0 определено 10 вспомогательных блоков, которые могут присутствовать в потоке данных PNG. Информация некоторых из этих блоков обеспечивает правильную интерпретацию данных изображения (например, Image Gamma - контрастность изображения). Вспомогательными блоками являются следующие блоки: блок фонового цвета; блок основных цветов и белой точки; блок контрастности изображения; блок значимых битов; блок текстовых данных; блок времени последнего изменения изображения; блок прозрачности; блок сжатых текстовых данных. Полная информация об этих блоках содержится в спецификации формата PNG. Данные изображения Данные Изображения PNG представлены в растровом виде со строками развёртки, направленными слева направо и сверху вниз. Пиксели всегда уплотнены в этих строках и не дополняются битами для выравнивания границы байтов между пикселями. Пиксели размером менее 8 бит упакованы в байт крайнего левого пикселя, занимая наиболее значимые биты в байте. Строки развёртки всегда начинаются на стыках байтов и всегда должны дополняться до ближайшего стыка байтов в конце. Перед каждой строкой 38 развёртки также находится байт типа фильтра, который используется при сжатии и извлечении изображения. Этот байт определяет тип алгоритма фильтрования, использованного при обработке данной линии развёртки. Этот байт присутствует всегда, даже когда фильтрование не было применено. Значения данных изображения глубиной цвета до 8 бит могут быть преобразованы в цветовую палитру либо сохранены в растровых данных в виде чёрно-белых значений. Полноцветные пиксели всегда хранятся в виде 3-х составляющих (красный, зелёный, синий соответственно). Также 4-я составляющая (Альфа канал) может быть включена в каждый полноцветный пиксель. Чёрно-белые и цветные индексированные растровые изображения содержат по одной составляющей на пиксель, образуя односоставные пиксели. Каждая составляющая в изображении всегда одного и того же размера. Этот размер называется битовой глубиной, равной количеству битов в составляющей. Одиночная составляющая может быть глубиной от 1 до 16 битов. Для изображений с индексированными цветами, битовая глубина определяет максимальное количество цветов в палитре. Форматом PNG не определяется, но и не устраняется двухуровневое растровое отображение. Многосоставные пиксели содержат 2 или более составляющих на пиксель. Эти составляющие могут быть 8 и 16 битовые, но все составляющие изображения должны быть одного и того же размера. Многосоставные пиксели могут быть от 16 до 64 битов. Например, типичный чёрно-белый пиксель содержит одну составляющую. Типичный 24-битовый пиксель в формате RGB - три 8-битовых составляющих, а нетипичный 64-битовый пиксель в формате RGBA будет содержать 4 16-битовых пикселя. Обратите внимание, что односоставные и многосоставные пиксели, использующие отличные от 8- и 16-битовых составляющие, должны использовать составляющие ближайшей допустимой 39 глубины. Например, для хранения 10-битовой составляющей, вы должны использовать 16-битовую. Неиспользуемые биты либо забиваются нолями (не рекомендовано для составляющих глубиной менее 8 бит, но для больших глубин забивание нолями позволит значительно улучшить сжатие), либо линейным увеличением масштаба заполняют диапазон допустимых значений (рекомендовано). Создатели PNG рекомендуют быстрый метод увеличения масштаба путём дублирования самых крайних слева значащих битов. Альфа канал Чёрно-белые и полноцветные изображения глубиной от 8 до 16 битов также могут содержать не сопоставленные данные альфа канала, называемые альфа маской. Если используются данные альфа маски, каждый чёрно-белый или полноцветный пиксель содержит дополнительно значение альфа канала для данного пикселя. Изображения с индексированными цветами могут содержать альфа канал в блоке прозрачности. Альфа значение определяет уровень прозрачности пикселя. Минимальное значение битовой глубины (всегда 0) указывает на абсолютную прозрачность, а максимальное значение либо отсутствие как таковое альфа маски указывает на полную непрозрачность. 7 АЛГОРИТМ СЖАТИЯ RLE Данные файла PCX/BMP сжимаются с помощью простого байториентированного алгоритма (RLE) группового кодирования. Ниже представлен алгоритм декодирования, алгоритм кодирования выглядит с точностью до наоборот. После прочтения заголовка и вычисления всех необходимых величин, таких как размеры изображения, количества цветов и установки палитры, начинаем читать данные изображения, которые идут сразу за заголовком по одному байту. Алгоритм выглядит так: 40 1 Читаем байт 2 Если два старших бита установлены в 1,т.е. "байт">=0С0h(192), преобразовать байт в счетчик группы по формуле (("байт"-192)+1). Иначе, 4. 3 Прочитать следующий байт и записать этот байт столько раз, сколько указанно в счетчике. 4 Записать литерал один раз. 5 Если буфер не полон, 1. 8 АЛГОРИТМ СЖАТИЯ LZW Данные файлов GIF хранятся в упакованном виде сжатым алгоритмом LZW (Lempel-Ziv Welch). Для того что бы лучше уяснить суть метода необходимо ввести ряд определений: "Символ": фундаментальный элемент данных. В обычных текстовых файлах это отдельный байт. В растровых изображениях, это который указывает цвет данного индекс, пиксела. Будем ссылаться на произвольный символ как на "K". "Поток символов": поток символов такой, как файл данных. "Цепочка": несколько последовательных символов. Длина цепочки может изменяться от 1 до очень большого числа символов. Можно указывать произвольную цепочку как "[...]K". "Префикс": почти то же самое, что цепочка, но подразумевается, что префикс непосредственно предшествует символу, и префикс может иметь нулевую длину. Будем ссылаться на произвольный префикс, как на "[...]". "Корень": односимвольная цепочка. Для большинства целей это просто символ, но иногда это может быть иначе. Это [...]K, где [...] пуста. "Код": число, определяемое известным количеством бит, которое кодирует цепочку. 41 "Поток кодов": выходной поток кодов, таких как "растровые данные". "Элемент": код и его цепочка. "Таблица цепочек": список элементов обычно, но не обязательно, уникальных. LZW это - преимущества при способ сжатия повторяющихся данных, цепочках который данных. извлекает Поскольку растровые данные обычно содержат довольно много таких повторений, LZW является хорошим методом для их сжатия и раскрытия. Рассмотрим обычное кодирование и декодирование с помощью LZWалгоритма. В GIF используется этот алгоритм. При сжатии и раскрытии LZW манипулирует тремя объектами: потоком символов, потоком кодов и таблицей цепочек. При сжатии поток символов является входным и поток кодов - выходным. При раскрытии входным является поток кодов, а поток символов - выходным. Таблица цепочек порождается и при сжатии и при раскрытии, однако она никогда не передается от сжатия к раскрытию и наоборот. Первое что необходимо сделать при LZW-сжатии является инициализация цепочки символов. Чтобы сделать это, нам необходимо выбрать код размера (количество бит) и знать сколько возможных значений могут принимать наши символы. Положим код размера равным 12 битам, что означает возможность запоминания 0FFF, или 4096, элементов в нашей таблице цепочек. Также предположим, что имееся 32 возможных различных символа. (Это соответствует, например, картинке с 32 возможными цветами для каждого пиксела.) Чтобы инициализировать таблицу, мы установим соответствие кода #0 символу #0, кода #1 to символу #1, и т.д., до кода #31 и символа #31. На самом деле показано, что каждый код от 0 до 31 является корневым. Больше в таблице не будет других кодов, обладающих этим свойством. 42 Теперь начнем сжатие данных. Сначала определим нечто, называемое "текущим префиксом". Этот префикс будем постоянно помнить и проводить сравнение Изначально с ним здесь и в дальнейшем. Будем обозначать его как "[.c.]". текущий префикс ничего не содержит. Также определим "текущую цепочку", которая образуется текущим префиксом и следующим символом в потоке символов. Обозначать текущую цепочку как "[.c.]K", где K - некоторый символ. Теперь посмотрим на первый символ в потоке символов. Назовем его P. Сделаем [.c.]P текущей цепочкой. (В данной точке это, конечно, корень P.) Теперь выполним поиск в таблице цепочек, чтобы определить входит ли нее [.c.]P. в Конечно, сейчас это произойдет, поскольку в нашу таблицу при инициализации были помещены все корни. В этом случае мы ничего не делаем. Теперь делаем текущим префиксом [.c.]P. Берем следующий символ из потока символом. Назовем его Q. Добавим текущий префикс, чтобы сформировать [.c.]Q, т.е. текущую цепочку. Выполняем поиск в таблице цепочек, чтобы определить входит ли в нее [.c.]Q. В данном случае этого, конечно, не будет. Добавим [.c.]Q (которая в данном случае есть PQ) в таблицу цепочек под кодом #32,и выведем код для [.c.] в поток кодов. соответствующего Теперь начнем корню P. опять с текущего префикса, Продолжаем добавление символов к [.c.], чтобы сформировать [.c.]K, до тех пор, пока мы не сможем найти [.c.]K в таблице цепочек. Затем выводим код для [.c.] и добавляем [.c.]K в таблицу цепочек. На псевдокоде алгоритм будет описан приблизительно так: [1] Инициализация таблицы цепочек; [2] [.c.] <- пусто; [3] K <- следующий символ в потоке символов; [4] Входит ли [.c.]K в таблицу цепочек? (да: [.c.] <- [.c.]K; go to [3]; ) (нет: добавить [.c.]K в таблицу цепочек; вывести код для [.c.] в поток кодов; [.c.] <- K; go to [3]; 43 ) Предположим, что мы имеем 4-символьный алфавит: A,B,C,D. Поток символов выглядит как ABACABA. Сначала инициализируем нашу таблицу цепочек: #0=A, #1=B, #2=C, #3=D. Первый символ есть A, который входит в таблицу цепочек, следовательно [.c.] становится равным A. Далее мы берем AB, которая не входит в таблицу, следовательно мы выводим код #0 (для [.c.]), и добавляем AB в таблицу цепочек с кодом #4. [.c.] становится равным B. Далее берем [.c.]A = BA, которая не входит в таблицу цепочек, следовательно выводим код #1, и добавляем BA в таблицу цепочек с кодом #5. [.c.] становится равным A. Далее мы берем AC, которая не входит в таблицу цепочек. Выводим код #0, и добавляем AC в таблицу цепочек с кодом #6. Теперь [.c.] равно C. Далее берем [.c.]A = CA, которая не входит в таблицу. Выводим #2 для C, и добавляем CA к таблице под кодом #7. Теперь [.c.]=A. Далее берем AB, которая входит в таблицу цепочек, следовательно [.c.] становится равным AB, и мы ищем ABA, которой нет в таблице цепочек, поэтому мы выводим код для AB, который равен #4, и добавляем ABA в таблицу цепочек под кодом #8. [.c.] равно A. Нельзя взять более символов, поэтому мы выводим код #0 для A и заканчиваем. Следовательно, поток кодов равен #0#1#0#2#4#0. Это все, о чем следует заботиться при сжатии. Раскрытие более сложно концептуально, однако программная реализация его проще. Опишем как это делается. Начинаем с инициализации таблицы цепочек. Эта таблица образуется исходя из тех знаний, которыми мы располагаем о порождаемом в конце концов потоке символов, например, о возможных значениях символов. В GIF-файлах эта информация находится в заголовке, как число возможных значений пикселов. Однако, прелесть LZW состоит в том, что это все, что нам нужно. Сжатие было выполнено таким образом, что никогда не встретится в потоке кодов код, который нельзя было бы преобразовать в цепочку. 44 Необходимо определить нечто, называемое "текущим кодом", на будем ссылаться ссылаться как как "<code>", и "старым кодом", на который "<old>". Чтобы что будем начать распаковку возьмем первый код. Теперь он становится <code>. Этот код будет инициализировать таблицу цепочек в качестве корневого. Выводим корень в поток символов. Делаем этот код старым кодом <old>. (*) Теперь берем следующий код и присваиваем его <code>. Возможно, что этот код не входит в таблицу цепочек, но пока предположим, что он там есть. символов. Выводим цепочку, соответствующую <code> в поток Теперь найдем первый символ в цепочке, которую только что получили. Назовем его K. Добавим его к префиксу [...], сгенерированному посредством <old>, чтобы получить новую цепочку [...]K. Добавим эту цепочку в таблицу цепочек и установим старый код <old> равным текущему коду <code>. Теперь рассмотрим ту возможность, что <code> не входит в таблицу цепочек. Вернемся обратно к сжатию и постараемся понять, что происходит, если во входном потоке появляется цепочка типа P[...]P[...]PQ. Предположим, что P[...] уже находится в таблице, а P[...]P - нет. Кодировщик выполнит грамматический разбор P[...], и обнаружит, что P[...]P отсутствует в таблице. Это приведет к выводу кода для P[...] и добавлению P[...]P в таблицу цепочек. Затем он возьмет P[...]P для следующей цепочки и определит, что P[...]P есть в таблице и выдаст выходной код для P[...]P, если окажется, что P[...]PQ в таблице отсутствует. Декодировщик всегда находится "на один шаг сзади" кодировщика. Когда декодировщик увидит код для P[...]P, он не добавит этот код к своей таблице сразу, поскольку ему нужен начальный символ P[...]P для добавления к цепочке для последнего кода P[...], чтобы сформировать код для P[...]P. Однако, когда декодировщик найдет код, который ему еще неизвестен, он всегда будет на 1 больше последнего добавленного к таблице. 45 Следовательно, он может догадаться что цепочка для этого кода должна быть и, фактически, всегда будет правильной. Пример: Предположим, что мы имеем растровое изображение в котором первые три пиксела имеют одинаковый цвет. Т.е. поток символов выглядит как : QQQ.... Для определенности давайте скажем, что мы имеем 32 цвета и Q соответствует цвету #12. Кодировщик сгенерирует последовательность кодов 12,32,.... спомним, что код #32 не входит в начальную таблицу, которая содержит коды от #0 до #31. Декодировщик увидит код #12 и транслирует его как цвет Q. Затем он увидит код #32, о значении которого он пока не знает. Но если он подумает о нем достаточно долго, он сможет понять, что QQ должно быть элементом #32 в таблице и QQ должна быть следующей цепочкой вывода. Таким образом, псевдокод декодирования можно представить следующим образом: [1] Инициализация строки цепочек; [2] взять первый код: <code>; [3] вывести цепочку для <code> в поток символов; [4] <old> = <code>; [5] <code> <- следующий код в потоке кодов; [6] существует ли <code> в таблице цепочек? (да: вывод цепочки для <code> в поток символов; [...] <- трансляция для <old>; K <- первый символ трансляции для <code>; добавить [...]K в таблицу цепочек; <old> <- <code>; ) (нет: [...] <- трансляция для <old>; K <- первый символ [...]; вывод [...]K в поток символов и добавление его к его к таблице цепочек; <old> <- <code> ) [7] go to [5]; Если обнаруживается на шаге [5], что нет больше символов, вы необходимо закончить. В формате GIF это реализовано следующим образом. В части заголовка GIF-файла существует поле, называемое в потоке растровых данных "кодом 46 размера". На самом деле это "размер корня". Фактический размер (в битах) кодов сжатия в действительности изменяется в процессе сжатия/раскрытия, и будем ссылаться на него здесь, как на "размер сжатия". Начальная таблица, как обычно, содержит коды для всех корней, но к ее верхней части добавляются два специальных кода. Предположим имеем "размер кода", который обычно равен числу битов на пиксел. Обозначим его N. Если число битов на пиксел равно 1, N должно равняться 2: корни занимают ячейки #0 и #1 в начальной таблице и два специальных кода будут занимать ячейки #4 #5. В любом другом случае N равно числу битов на пиксел, корни занимают ячейки от #0 до #(2**N-1), а специальные коды равны (2**N) и (2**N + 1). Начальный размер сжатия будет равен N+1 биту на код. Если ведётся кодирование, то выводим сначала коды длиной (N+1) бит и, если ведётся декодирование, то выбираем сначала (N+1) бит из потока кодов. В качестве специальных кодов используются: <CC> или код очистки, равный (2**N), и <EOI> или конец кодировщику, информации, равный (2**N что нужно 1). <CC> говорит снова инициализировать таблицу цепочек и переустановить размер сжатия равным (N+1). больше нет. + <EOI> означает что кодов Если вы ведете кодирование или декодирование, вы должны начать добавление элементов в таблицу цепочек с <CC> + 2. Если вы ведете кодирование, вам следует вывести <CC> в качестве самого первого кода, и затем опять каждый раз, как только вы достигните кода #4095 (шестнадцатиричное FFF), поскольку GIF не допускает большего 12 бит. Если вы ведете размера сжатия раскрытие, вам следует реинициализировать вашу таблицу цепочек, как только вы обнаружите <CC>. Переменный размер сжатия на самом деле не доставляет особых трудностей. Если ведётся кодирование то начинаем с размера сжатия в (N+1) битов, и, как только вы выведете код (2**(размер сжатия)-1), вы увеличиваете размер сжатия на один бит. Следовательно, следующий код вашего вывода будет на один бит длиннее. Помните, что наибольший размер сжатия равен 47 12 битам, что соответствует коду 4095. Если вы достигли этого предела, вы должны вывести <CC> в качестве следующего кода и начать сначала. Если вы ведете декодирование, вы должны увеличить ваш размер сжатия как только вы запишите элемент #(2**(размер сжатия) - 1) в таблицу цепочек. Следующий код, который вы прочитаете будет на один бит длиннее. 48 9 СОЗДАНИЕ НЕКОТОРЫХ ВИДЕОЭФФЕКТОВ Существует много прикладных задач в которых необходимо подвергать изображения каким либо изменениям, многие из них принято называть видеоэффектами. Для примера можно назвать задачу обработки аэрофотосьёмки, обработка позволяет определить участки суши на которых происходит эррозия почвы, так же можно определить месторождения полезных ископаемых, области загрязнения. Применение видеоэффектов позволяет визуально улучшить качество фотоснимков и создать интересные эффекты на снимках. В частности эта технология применяется в PhotoShop и других приложениях ориентированных на работу с изображениями. Существует базовый набор видеоэффектов на основе которых строятся другие более сложные эффекты путём последовательного применения базовых. Среди простейших эффектов можно назвать негатив, эффект шума, логические операции над изображениями, выравнивание изображения по контрольному цвету, разложение по цветовым координатам, объединение по цветовому базису, матричная линейная фильтрация. 9.1 Разложение по цветовым координатам Зрение является важнейшей сенсорной системой человека, 90% информации человек получает именно через зрение. Зрение может различать основные цвета, оттенки, яркость и тд. Работа периферийных устройств вывода графической информации (принтеры, мониторы…)основана на особенностях зрения и строения глаза. Светочувствительным элементом глаза является сетчатка. Свет попадает в глаз через роговицу и фокусируется хрусталиком на сетчатке. Сетчатка преобразует свет в импульсы в нервных волокнах и состоит из трех слоев клеток. 49 Внутренний слой сетчатки глаза содержит два типа светочувствительных рецепторов, занимающих область с раствором около 170° относительно зрительной оси: 100 млн. палочек (длинные и тонкие рецепторы ночного зрения), 6.5 млн. колбочек (короткие и толстые рецепторы дневного зрения). Информация от рецепторов передается в мозг по зрительному нерву, содержащему около 800 тысяч волокон. Колбочки и палочки содержат зрительные пигменты. Информация от светочувствительных рецепторов (колбочек и палочек) передается другим типам клеток, которые соединены между собой. Специальные клетки передают информацию в зрительный нерв. Таким образом волокно зрительного нерва обслуживает несколько светочувствительных рецепторов, т.е. некоторая предварительная обработка изображения выполняется непосредственно в глазу, который по сути представляет собой выдвинутую вперед часть мозга. Область сетчатки, в которой волокна зрительного нерва собираются вместе и выходят из глаза, лишена светочувствительных рецепторов и называется слепым пятном. Радужная оболочка действует как диафрагма, изменяя количество света, проходящего в глаз. Диаметр зрачка меняется от ~ 2 мм (при ярком свете) до ~ 8 мм (при малой освещенности). За сетчаткой находится сосудистая оболочка, которая содержит капилляры, снабжающие глаз кровью. Наружная оболочка глаза - склера, состоит их плотных волокон. При ярком свете чувствительность палочек мала, но при низких уровнях освещенности их чувствительность возрастает и обеспечивает нашу способность видеть при тусклом свете. Палочки содержат пигмент с максимальной чувствительностью на длине волны около 510 нм в зеленой части спектра. Пигмент палочек часто называется зрительным пурпуром из-за его цвета. Максимальная плотность палочек приходится на область с раствором около 20° относительно оси. 50 Колбочек существует три типа отличающихся фоточувствительным пигментом. Колбочки обычно называют "синими", "зелеными" и "красными" в соответствии с наименованием цвета, для которого они оптимально чувствительны. Упомянутые три пигмента имеют максимальные поглощения приблизительно на 430, 530 и 560 нм. Этим длинам волн соответствует не синий, зеленый и красный цвета, а фиолетовый, сине-зеленый и желто-зеленый. В силу того, что коэффициент преломления в радужке и хрусталике растет с увеличением частоты света, глаз не избавлен от хроматической аберрации. Т.е. если изображение сфокусировано для одной из частот, то на других частотах изображение расфокусировано. Хрусталик оптимально фокусирует на сетчатке свет с длиной волны около 560 нм. Так как пики чувствительности средне- длинноволновых колбочек (530 и 560 нм, соответственно) близки к друг к другу, поэтому изображения для этих колбочек могут быть одновременно сфокусированными. Изображение же для коротковолновых палочек будет размытым. Так степень фокусировки разная, то не требуется одинаковой разрешающей способности глаза для разных типов колбочек. В глазу человека на одну коротковолновую колбочку приходится 20 средне- и 40 длинноволновых. В этой связи понятно, почему ширина полосы пропускания для "холодных", коротковолновых цветов в телевидении может быть выбрана существенно меньшей без субъективно заметной потери верности воспроизведения. В компьютерной графике имеется два типа цветных объектов самосветящиеся, излучающие объекты, такие как экраны ЭЛТ, плазменные панели, матрицы светодиодов и т.п. и несамосветящиеся объекты, отражающие или преломляющие падающий на них свет, такие как, например, оттиски на бумаге, светофильтры и т.п. Для самосветящихся объектов используется аддитивное формирование оттенков, когда требуемый цвет формируется за счет смешения трех основных 51 оттенков цветов. В этом случае удобно использование модели смешения RGB (Red, Green, Blue - красный, зеленый, синий). Для несамосветящихся объектов используется субтрактивное формирование оттенков, основанное на вычитании из падающего света определенных длин волн. В этом случае удобно использование модели смешения CMY (Cyan, Magenta, Yellow - голубой, пурпурный, желтый). Цвета одной модели являются дополнительными к цветам другой модели. Дополнительный цвет - цвет, дополняющий данный до белого. Дополнительный для красного - голубой (зеленый+синий), дополнительный для зеленого - пурпурный (красный+синий), дополнительный для синего желтый (красный+зеленый) и т.д. При освещении падающим белым светом в слое голубой краски из спектра белого цвета поглощается красная часть, затем из оставшегося света в слое пурпурной краски поглощается зеленая часть спектра, отраженный от поверхности бумаги свет еще раз подвергается поглощению и в результате мы видим синий цвет. Назначение цветовой модели - дать средства описания цвета в пределах некоторого цветового охвата, в том числе и для выполнения интерполяции цветов. Наиболее часто в компьютерной графике используются модели RGB, CMY, YIQ, HSV и HLS. 9.2 Модель RGB RGB (Red, Green, Blue - красный, зеленый, синий) - аппаратноориентированная модель, используемая в дисплеях для аддитивного формирования оттенков самосветящихся объектов (пикселов экрана). Система координат RGB - куб с началом отсчета (0,0,0), соответствующим черному цвету (рисунок 1). Максимальное значение RGB - (1,1,1) соответствует белому цвету. 52 Рисунок 1 – Модель RGB Программная реализация разложения приведена в приложении А. 9.3 Модель CMY CMY (Cyan, Magenta, Yellow - голубой, пурпурный, желтый) - аппаратноориентированная модель, используемая в полиграфии для субтрактивного формирования оттенков, основанного на вычитании слоем краски части падающего светового потока. Цвета модели CMY являются дополнительными к цветам модели RGB, т.е. дополняющими их до белого. Таким образом система координат CMY - тот же куб, что и для RGB, но с началом отсчета в точке с RGB координатами (1,1,1), соответствующей белому цвету. Цветовой куб модели CMY показан на рисунке 2. Рисунок 2 - Цветовой куб модели CMY 53 Программная реализация разложения приведена в приложении А Преобразования между пространствами RGB и CMY определяются следующим образом: [ R G B ] = [1 1 1] – [ C M Y ]. Причем единичный вектор-строка в модели RGB - представление белого цвета, а в модели CMY - черного. 9.4 YIQ YIQ - аппаратно-ориентированная модель, используемая в телевидении и служащая для сокращения передаваемой полосы частот за счет использования психофизиологических особенностей зрения. Преобразования между пространствами RGB и YIQ определяются соотношениями: Y I 0.299 0.596 0.587 -0.274 0.114 -0.322 R G Q 0.211 -0.522 0.311 B R G 1.0 1.0 0.956 -0.272 0.623 -0.648 Y I 1.0 -1.105 0.705 Q = = B 9.5 Модель HSV HSV (Hue, Saturation, Value - цветовой тон, насыщенность, количество света или светлота) - модель, ориентированная на человека и обеспечивающая возможность явного задания требуемого оттенка цвета (рисунок 3). Подпространство, определяемое данной шестигранный конус. моделью - перевернутый 54 По вертикальной оси конуса задается V - светлота, меняющаяся от 0 до 1. Значению V = 0 соответствует вершина конуса, значению V = 1 - основание конуса; цвета при этом наиболее интенсивны. Цветовой тон H задается углом, отсчитываемым вокруг вертикальной оси. В частности, 0° - красный, 60° - желтый, 120° - зеленый, 180° - голубой, 240° - синий, 300° - пурпурный, т.е. дополнительные цвета расположены друг против друга (отличаются на 180°). Насыщенность S определяет насколько близок цвет к "чистому" пигменту и меняется от 0 на вертикальной оси V до 1 на боковых гранях шестигранного конуса. Рисунок 3 – Разложение HSV Точка V = 0, в которой находится вершина конуса, соответствует черному цвету. Значение S при этом может быть любым в диапазоне 0-1. Точка с координатами V = 1, S = 0 - центр основания конуса соответствует белому цвету. Промежуточные значения координаты V при S=0, т.е. на оси конуса, соответствуют серым цветам. Если S = 0, то значение оттенка H считается неопределенным. Программная реализация разложения приведена в приложении А 55 9.6 Модель HLS HLS (Hue, Lightness, Saturation - цветовой тон, светлота, насыщенность) модель ориентированная на человека и обеспечивающая возможность явного задания требуемого оттенка цвета (рис.4). Эта модель образует подпространство, представляющее собой двойной конус, в котором черный цвет задается вершиной нижнего конуса и соответствует значению L = 0, белый цвет максимальной интенсивности задается вершиной верхнего конуса и соответствует значению L = 1. Максимально интенсивные цветовые тона соответствуют основанию конусов с L = 0.5, что не совсем удобно. Цветовой тон H, аналогично системе HSV, задается углом поворота. Насыщенность S меняется в пределах от 0 до 1 и задается расстоянием от вертикальной оси L до боковой поверхности конуса. Т.е. максимально насыщенные цветовые цвета располагаются при L=0.5, S=1. В общем, систему HLS можно представить как полученную из HSV "вытягиванием" точки V=1, S=0, задающей белый цвет, вверх для образования верхнего конуса. 56 Рисунок 4 – Разложение HLS Програмная реализация разложения прирведена в приложении А. 9.7 Использование RGB Растровые дисплеи, как правило, используют аппаратно- ориентированную модель цветов RGB. В наиболее распространенных растровых дисплеях - дисплеях с таблицей цветности значения кодов пикселов, заносимые в видеопамять, представляют собой индексы элементов таблицы цветности. При необходимости отображения некоторого пиксела на экран по его значению выбирается элемент таблицы цветности, содержащий тройку значений - RGB. Эта тройка и передается на монитор для задания цвета пиксела на экране. В полноцветных дисплеях для каждого пиксела в видеопамять заносится тройка значений RGB. В этом случае при необходимости отображения пиксела из видеопамяти непосредственно выбирается тройка значений RGB, которая и передается на монитор (но может и передаваться в таблицу цветности). 57 В модели RGB легко задавать яркости для одного из основных цветов, но по крайней мере затруднительно задать оттенок с требуемым цветовым тоном и насыщенностью. В различного рода графических редакторах эта задача обычно решается с помощью интерактивного выбора из палитры цветов и формированием цветов в палитре путем подбора значений RGB до получения требуемого визуального результата. Более удобно в этом случае использовать модели HVS или HLS, позволяющие непосредственно задать требуемый оттенок. Конечно, при занесении данных в таблицу цветности или для полноцветных дисплеев - в видеопамять требуется перевод в значений в систему RGB. 9.8 Эффект шума Иногда при работе с видеоизображениями необходимо реализовать эффект телевизионного шума. Этот эффект является очень простым. В основе этого метода лежит разложение изображения на базис R G B и затем сумированием к каждому элементу базиса некоторого случайного значения которое может зависить по какому либо закону от уровня шума Пример(миксирование белого шума к изображению): for y := 0 to Ys do for x := 0 to Xs do begin t := GetArrPixel(Xs + 1 , x, Ys-y, PictArrs[Num]); //исходный пиксел r := (t and $FF0000) shr 16; g := (t and $FF00) shr 8; b := t and $FF; nr := Level - random (Level*2); r := r + nr; g := g + nr; b := b + nr; if r < 0 then r := 0 else if r > 255 then r := 255; if g < 0 then g := 0 else if g > 255 then g := 255; if b < 0 then b := 0 else if b > 255 then b := 255; e := b or (g shl 8) or (r shl 16); //новый пиксел SetArrPixel( e, Xs + 1, x, Ys-y, PictArrs[Num]); 58 end; Пример полной программной реализации приведён в приложении А 9.9 Создание негатива Создание негатива также является базовым эффектом. Он может быть полезен при сканировании цветных слайдов. В основе этого метода лежит логическое отрицание значения каждого пиксела изображения. Пример(создание негатива изображения): for y := 0 to Ys do for x := 0 to Xs do begin t := GetArrPixel(Xs + 1 , x, Ys-y, PictArrs[Num]); asm mov eax,t not eax mov e,eax end; SetArrPixel( e, Xs + 1, x, Ys-y, PictArrs[Num]); end; Пример полной программной реализации приведён в приложении А 9.10 Логические операции над изображениями Изображения можно складывать, вычитать, умножать на константу и вообще выполнять все логические операции применимые к числам. Логическое сложение изображенией изображений производится сложением каждой компоненты цветовых координат, т.е. приизводится разложение изображений по базису R G B и затем над каждой компонентой i,j кординаты R первого изображения и соответствующей компонентой координаты R второго изображения призводится операция or. Логическое умножение изображений производится объединением соответствующих компонент цветовых проскостей R G B оператором and 59 Логическое умножение по модулю 2 изображений производится объединением соответствующих компонент цветовых проскостей R G B оператором xor Подобным образом можно производить следующие операции над изображениями sub, mul, imul, div, idiv, nand, nxor, nor …. 9.11 Фильтрация изображений Понятие фильтрации бширно, и включает в себя любое преобразование графической информации. Фильтрация может быть задана не только в виде формулы, но и в виде алгоритма, его реализующая. Человек запоминает графическую информацию, в основном, в виде трех ее составляющих. Низкочастотные составляющие изображения. Они несут информацию о локализации объектов, составляющих изображения. Эта составляющая наиболее важна, так как связка глаз - мозг уделяет ей первостепенное внимание. Высокочастотные составляющие изображения. Они отвечают за цветовые перепады - контуры изображения. Увеличивая их, мы повышаем резкость изображения. Будем рассматривать фильтры в виде квадратной матрицы A. Пусть исходное изображение X, а получаемое как результат фильтрации - Y. Для простоты будем использовать матрицы 3x3: Рекурсивными фильтрами первого рода будут такие фильтры, выход Y которых формируется перемножением весовых множителей A с элементами изображения X. Фильтром низких частот пользуются часто для того, чтобы 60 подавить шум в изображении, сделать его менее резким. Высокочастотные фильтры, напротив используются для подчеркивания резкости изображения. Пример программной реализации фильтрации матричными линейными фильтрами приведён в приложении А. 61 Задание к курсовой работе В соответствии с вариантом написать программу для просмотра файлов заданного графического формата. Для данного формата реализовать специальные эффекты. Формат файла и эффекты, которые необходимо применить заданы в таблицах ниже. № 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Таблица 9 Формат Файла BMP PCX сж BMP TGA TIFF BMP TIFF GIF PCX сж PCX GIF JPG BMP TIFF GIF BMP TGA TIFF PCX сж PCX TGA TIFF BMP GIF PCX 1 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 5 9 11 14 6 10 12 15 7 8 13 16 5 9 11 14 6 10 12 15 7 8 13 16 5 Последовательность действий 3 4 5 17 32 14 18 31 11 19 30 8 20 29 5 21 32 15 22 31 12 23 30 9 24 29 6 25 17 32 26 18 31 27 19 30 28 20 29 29 21 32 30 22 31 31 23 30 32 24 29 17 25 32 18 26 31 19 27 30 20 28 29 21 32 16 22 31 13 23 30 10 24 29 7 25 32 14 6 33 34 34 35 37 35 38 33 35 36 34 35 36 39 35 37 37 33 37 38 36 34 38 36 39 62 Таблица 10 № действия 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 Действие Разложить по цветовому базису R G B Разложить по цветовому базису C M Y Разложить по цветовому базису H S V Разложить по цветовому базису H L S Зашумить состовляющую R Зашумить состовляющую G Зашумить состовляющую B Зашумить состовляющую C Зашумить состовляющую M Зашумить состовляющую Y Зашумить состовляющую H Зашумить состовляющую S Зашумить состовляющую V Зашумить состовляющую H Зашумить состовляющую L Зашумить состовляющую S Негатив изображения Отфильтровать фильтром 1 Отфильтровать фильтром 2 Отфильтровать фильтром 3 Отфильтровать фильтром 4 Отфильтровать фильтром 5 Отфильтровать фильтром 6 Отфильтровать фильтром 7 Отфильтровать фильтром 8 Отфильтровать фильтром 9 Отфильтровать фильтром 10 Отфильтровать фильтром 11 Преобразовать в базис в R G B Преобразовать в базис в C M Y Преобразовать в базис в H S V Преобразовать в базис в H L S Сохранить как BMP Сохранить как PCX несжатый Сохранить как PCX сжатый Сохранить как TGA Сохранить как TIFF Сохранить как GIF Сохранить как PNG Матрицы фильтров: 63 1 -2 1 -2 1 5 1 -2 1 -2 0 -1 0 2 -1 0 5 -1 -1 0 -1 -2 -1 3 -2 -1 13 -2 -2 -1 4 1 1 1 1 1 1 1 1 1 5 1 1 1 1 2 1 1 1 1 6 1 2 1 2 4 2 1 2 1 0 -1 0 7 -1 0 4 -1 -1 0 -1 -2 -2 8 -2 -1 13 -2 -2 -1 -1 -1 -1 9 -1 -1 -8 -1 -1 -1 10 64 1 1 -1 1 -2 -1 1 1 -1 11 2 7 12 7 2 7 31 52 31 7 12 52 127 52 12 7 31 52 31 7 2 7 12 7 2 65 Требования к выполнению курсовой работы: Курсовая работа должна быть выполнена в соответствии с вариантом и техническим заданием, утвержденным преподавателем. Пояснительная записка к курсовой работе должна быть выполнена в соответсвии с правилами и требованиями, предъявляемыми к оформлению курсовых работ, и обязательно содержать следующие разделы: 1 Описание графического формата файла 2 Алгоритм отображения файлОВ 3 Алгоритмы реализации эффектов 4 Структура приложения 5 Выбор инструментальных средств для реализации программы, обоснование выбора 6 Описание основных модулей программы 6.1 Открытие файла 6.2 Использование эффектов 6.3 Сохранение файла 7 Тестирование, результаты работы программы 66 ЛИТЕРАТУРА: 1. «Основы компьютерной графики». Радио и связь 1997. Балашов В.М. 2. «Цветное телевидение». Радио и связь 1989. Жуков В.И. 3. «Растровые изображения». SMP 2001. Самолётов С.Л. 4. «Компьютерная графика» Sams 2000. Гофман В.И. 67 Приложение А - Графическая библиотека, содержащая примеры // Графическая библиотека unit GraphLib; implementation // Считывание цвета пикселя.(DIBits) function GetArrPixel(XMax, x, y : integer; p : pointer) : integer; assembler; begin asm mov ecx,XMax lea ecx,[ecx*4]// ecx = XMax * 4 @@1: mov edx,x lea edx,[edx*4]// edx = x * 4 push edx mov eax,y mul ecx // ecx = z * y pop edx add eax,edx // eax = z*y + x*4; push esi mov esi,p add esi,eax mov eax,[esi] and eax,$00FFFFFF mov Result,eax pop esi end; end; // Запись цвета пикселя.(DIBits) procedure SetArrPixel(pix : cardinal; xmax, x, y : integer; p : pointer); assembler; begin asm mov ecx,XMax lea ecx,[ecx*4]// ecx = XMax * 4 @@1: mov edx,x lea edx,[edx*4]// edx = x * 4 push edx mov eax,y mul ecx // ecx = z * y pop edx add eax,edx // eax = z*y + x*4; mov edx,eax push esi mov eax,pix mov esi,p add esi,edx mov dl,[esi+3] mov [esi],eax mov [esi+3],dl pop esi end; end; 68 // RGB -> HSV ( 0=< (R,G,B,S,V) <=1 и 0=<H<=360 ) Procedure RGB_to_HSV(R,G,B : extended; var H,S,V : extended); const undefined=359; function max_of(Red,Green,Blue : extended) : extended; var max : extended; begin if red>green then max:=red else max:=green; if blue>max then max:=blue; max_of:=max; end; function min_of(Red,Green,Blue : extended) : extended; var min : extended; begin if red<green then min:=red else min:=green; if blue<min then min:=blue; min_of:=min; end; var Max_value, Min_value,diff,r_dist,g_dist,b_dist : extended; begin max_value:=max_of(R,G,B); min_value:=min_of(R,G,B); diff:=max_value-min_value; V:=max_value; if max_value<>0 then s:=(diff / max_value) else s:=0; if s=0 then h:=undefined else begin r_dist:=(max_value-R) / diff; g_dist:=(max_value-G) / diff; b_dist:=(max_value-B) / diff; if R=max_value then H:=b_dist-g_dist else if G=Max_value then H:=2+r_dist-b_dist else if B=max_value then H:=4+g_dist-r_dist; H:=H*60; if H<0 then h:=h+360; end; end; // HSV -> RGB ( 0=< (R,G,B,S,V) <=1 и 0=<H<=360 ) Procedure HSV_to_RGB(H,S,V : extended; var R,G,B : extended); var f,p,q,t : extended ; i:integer; begin if S=0 then begin R:=V; G:=V; B:=V; end else begin if H=360 then H:=0; H:=H/60; I:=trunc(H); { the integer part of H } f:=H-i; p:=V*(1-S); q:=V*(1-(S*f)); t:=V*(1-(S*(1-f))); case i of 0: begin R:=V; G:=t; B:=p; end; 69 1: begin R:=q; G:=V; B:=p; end; 2: begin R:=p; G:=V; B:=t; end; 3: begin R:=p; G:=q; B:=V; end; 4: begin R:=t; G:=p; B:=V; end; 5: begin R:=V; G:=p; B:=q; end; end; end; end; // RGB->YIQ procedure RGB_to_YIQ(R,G,B : byte ; var Y,I,Q : byte); var r1, g1, b1 : extended; begin r1 := R/255; g1 := G/255; b1 := B/255; Y := Trunc(( 0.299 * r1 + 0.587 * g1 + 0.114 * b1)*255); I := Trunc((((0.596 * r1 - 0.275 * g1 - 0.321 * b1)+0.596)/1.192)*255); Q := Trunc((((0.212 * r1 - 0.523 * g1 + 0.311 * b1)+0.523)/1.046)*255); end; // YIQ -> RGB procedure YIQ_to_RGB(Y,I,Q : byte ; var R,G,B : byte); var y1,i1,q1 : extended; rr,gg,bb : integer; begin y1 := Y/255; i1 := I/255; q1 := Q/255; Rr := Trunc(abs((y1 + 0.956 * (i1 * 1.192 -0.596) + 0.621 * (q1 * 1.046 -0.523)))*255); if Rr > 255 then Rr := 255; if Rr < 0 then Rr := 0; R := Lo(Rr); Gg := Trunc(abs((y1 - 0.272 * (i1 * 1.192 -0.596) - 0.647 * (q1 * 1.046 -0.523)))*255); if Gg > 255 then Gg := 255; if Gg < 0 then Gg := 0; G := Lo(Gg); Bb := Trunc(abs((y1 - 1.106 * (i1 * 1.192 -0.596) + 1.703 * (q1 * 1.046 -0.523)))*255); if Bb > 255 then Bb := 255; if Bb < 0 then Bb := 0; B := Lo(Bb); end; // RGB -> CMY procedure RGB_to_CMY(R,G,B : byte; var C,M,Y : byte); begin Y := 255 - B; M := 255 - G; C := 255 - R; end; // CMY -> RGB procedure CMY_to_RGB(C,M,Y : byte; var R,G,B : byte); begin R := 255 - C; G := 255 - M; B := 255 - Y; end; // Негатив изображения function Negative(Num,Xs,Ys : integer) : boolean; var x, y : integer; t, e : cardinal; begin 70 dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t := GetArrPixel(Xs + 1 , x, Ys-y, PictArrs[Num]); asm mov eax,t not eax mov e,eax end; SetArrPixel( e, Xs + 1, x, Ys-y, PictArrs[Num]); end; Result := True; end; // Миксование белого шума к изображению. function Noise(Num,Level,Xs,Ys : integer) : boolean; var x, y : integer; t, e : cardinal; nr : integer; r,g,b : integer; begin dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t := GetArrPixel(Xs + 1 , x, Ys-y, PictArrs[Num]); r := (t and $FF0000) shr 16; g := (t and $FF00) shr 8; b := t and $FF; nr := Level - random (Level*2); r := r + nr; g := g + nr; b := b + nr; if r < 0 then r := 0 else if r > 255 then r := 255; if g < 0 then g := 0 else if g > 255 then g := 255; if b < 0 then b := 0 else if b > 255 then b := 255; e := b or (g shl 8) or (r shl 16); SetArrPixel( e, Xs + 1, x, Ys-y, PictArrs[Num]); end; Result := True; end; // Собственно разложение . procedure ConvertTo3Basis(Conv,XMax,YMax : integer; PSource : pointer; var PDest1, PDest2, PDest3 : pointer); var x,y : integer; R, G, B : byte; Y_,I_,Q_ : byte; h, s, v : extended; t, e1, e2, e3 : integer; begin for y := 0 to YMax do begin for x := 0 to XMax do begin t := GetArrPixel(XMax+1, x, YMax-y, PSource); 71 R := Lo((t and $FF0000) shr 16); G := Lo((t and $FF00) shr 8); B := Lo(t and $FF); case Conv of cRGB : asm mov ecx,t mov eax,ecx and eax,$FF0000 mov edx,eax shr eax,8 mov al,ah add eax,edx mov e1,eax mov eax,ecx and eax,$FF00 mov al,ah xor edx,edx mov dh,al shl edx,8 or eax,edx mov e2,eax mov eax,ecx and eax,$FF mov ah,al xor edx,edx mov dl,al shl edx,16 or eax,edx mov e3,eax end; cCMY : asm mov eax,t mov ecx,eax xor edx,edx and eax,$FF0000 shr eax,16 mov ah,al mov dl,al shl edx,16 add eax,edx not eax and eax,$FFFFFF mov e1,eax mov eax,ecx xor edx,edx and eax,$FF00 mov al,ah mov dl,al shl edx,16 add eax,edx not eax and eax,$FFFFFF mov e2,eax mov eax,ecx xor edx,edx 72 and eax,$FF mov ah,al mov dl,al shl edx,16 add eax,edx not eax and eax,$FFFFFF mov e3,eax end; cYIQ : begin RGB_to_YIQ(R,G,B ,Y_,I_,Q_); e1 := Y_ or (Y_ shl 8) or (Y_ shl 16); e2 := I_ or (I_ shl 8) or (I_ shl 16); e3 := Q_ or (Q_ shl 8) or (Q_ shl 16); end; cHLS : begin RGB_to_HSV(R/255, G/255, b/255, h, s, v); e1 := Round(h*0.7083332); e2 := Round(s*255); e3 := Round(v*255); e1 := e1 or (e1 shl 8) or (e1 shl 16); e2 := e2 or (e2 shl 8) or (e2 shl 16); e3 := e3 or (e3 shl 8) or (e3 shl 16); end; end; SetArrPixel( e1, XMax+1, x, YMax-y, PDest1); SetArrPixel( e2, XMax+1, x, YMax-y, PDest2); SetArrPixel( e3, XMax+1, x, YMax-y, PDest3); end; end; end; // Фильтр Dimension = 3,5 - размерность матрицы фильтра. Iter - порядок фильтра (1 или 2). procedure Filtrate(Pict : pointer; XSize, YSize, Dimension, Iter : integer); var pt2 : pointer; x, y, u, v, x1, x2, x3, x4, x5 , y1, y2, y3, y4, y5 : integer; r, g, b : extended; rc, gc, bc : cardinal; Pix : array[1..5,1..5] of Cardinal; Flag : boolean; begin Flag := True; if Dimension = 5 then Flag := False; // Создаем копию изображения pt2 := AllocMemo(GetMemoSize(Pict)); CopyToMem(Pict,pt2,GetMemoSize(Pict)); // Собственно фильтрация if not Flag then begin // фильтр 5x5 for y := 0 to YSize do begin for x := 0 to XSize do begin asm push esi // x1 - ebx, x2 - ecx, x3 - eax x4 - edx push edi //x1 := x - 2; if x1 < 0 then x1 := x; //x2 := x - 1; if x2 < 0 then x2 := x; mov esi,XSize //x3 := x ; 73 mov edi,YSize //x4 := x + 1; if x4 > XSize then x4 := x; //x5 := x + 2; if x5 > XSize then x5 := x; mov eax,x //y1 := y - 2; if y1 < 0 then y1 := y; mov x3,eax //y2 := y - 1; if y2 < 0 then y2 := y; //y3 := y ; inc eax //y4 := y + 1; if y4 > YSize then y4 := y; cmp eax,esi //y5 := y + 2; if y5 > YSize then y5 := y; jbe @@1 dec eax @@1: mov x4,eax inc eax cmp eax,esi jbe @@2 dec eax @@2: mov x5,eax mov eax,x dec eax jge @@3 inc eax @@3: mov x2,eax dec eax jge @@4 inc eax @@4: mov x1,eax mov eax,y mov y3,eax inc eax cmp eax,edi jbe @@5 dec eax @@5: mov y4,eax inc eax cmp eax,edi jbe @@6 dec eax @@6: mov y5,eax mov eax,y dec eax jge @@7 inc eax @@7: mov y2,eax dec eax jge @@8 inc eax @@8: mov y1,eax pop edi pop esi end; if Iter=1 then begin Pix[1,1] := GetArrPixel(XSize+1,x1,YSize-y1,pt2); Pix[1,2] := GetArrPixel(XSize+1,x1,YSize-y2,pt2); Pix[1,3] := GetArrPixel(XSize+1,x1,YSize-y3,pt2); Pix[1,4] := GetArrPixel(XSize+1,x1,YSize-y4,pt2); Pix[1,5] := GetArrPixel(XSize+1,x1,YSize-y5,pt2); Pix[2,1] := GetArrPixel(XSize+1,x2,YSize-y1,pt2); Pix[2,2] := GetArrPixel(XSize+1,x2,YSize-y2,pt2); 74 Pix[2,3] := GetArrPixel(XSize+1,x2,YSize-y3,pt2); Pix[2,4] := GetArrPixel(XSize+1,x2,YSize-y4,pt2); Pix[2,5] := GetArrPixel(XSize+1,x2,YSize-y5,pt2); Pix[3,1] := GetArrPixel(XSize+1,x3,YSize-y1,pt2); Pix[3,2] := GetArrPixel(XSize+1,x3,YSize-y2,pt2); end else begin Pix[1,1] := GetArrPixel(XSize+1,x1,YSize-y1,Pict); Pix[1,2] := GetArrPixel(XSize+1,x1,YSize-y2,Pict); Pix[1,3] := GetArrPixel(XSize+1,x1,YSize-y3,Pict); Pix[1,4] := GetArrPixel(XSize+1,x1,YSize-y4,Pict); Pix[1,5] := GetArrPixel(XSize+1,x1,YSize-y5,Pict); Pix[2,1] := GetArrPixel(XSize+1,x2,YSize-y1,Pict); Pix[2,2] := GetArrPixel(XSize+1,x2,YSize-y2,Pict); Pix[2,3] := GetArrPixel(XSize+1,x2,YSize-y3,Pict); Pix[2,4] := GetArrPixel(XSize+1,x2,YSize-y4,Pict); Pix[2,5] := GetArrPixel(XSize+1,x2,YSize-y5,Pict); Pix[3,1] := GetArrPixel(XSize+1,x3,YSize-y1,Pict); Pix[3,2] := GetArrPixel(XSize+1,x3,YSize-y2,Pict); end; Pix[3,3] := GetArrPixel(XSize+1,x3,YSize-y3,pt2); Pix[3,4] := GetArrPixel(XSize+1,x3,YSize-y4,pt2); Pix[3,5] := GetArrPixel(XSize+1,x3,YSize-y5,pt2); Pix[4,1] := GetArrPixel(XSize+1,x4,YSize-y1,pt2); Pix[4,2] := GetArrPixel(XSize+1,x4,YSize-y2,pt2); Pix[4,3] := GetArrPixel(XSize+1,x4,YSize-y3,pt2); Pix[4,4] := GetArrPixel(XSize+1,x4,YSize-y4,pt2); Pix[4,5] := GetArrPixel(XSize+1,x4,YSize-y5,pt2); Pix[5,1] := GetArrPixel(XSize+1,x5,YSize-y1,pt2); Pix[5,2] := GetArrPixel(XSize+1,x5,YSize-y2,pt2); Pix[5,3] := GetArrPixel(XSize+1,x5,YSize-y3,pt2); Pix[5,4] := GetArrPixel(XSize+1,x5,YSize-y4,pt2); Pix[5,5] := GetArrPixel(XSize+1,x5,YSize-y5,pt2); r := 0; g := 0; b := 0; for u := 1 to 5 do for v := 1 to 5 do begin r := r + Filtr[u,v]*(Pix[u,v] and $000000FF); g := g + Filtr[u,v]*((Pix[u,v] and $0000FF00) shr 8); b := b + Filtr[u,v]*((Pix[u,v] and $00FF0000) shr 16); end; if r < 0 then r := 0; if g < 0 then g := 0; if b < 0 then b := 0; rc := Round( r * FiltrCoeff);if rc > 255 then rc := 255; gc := Round( g * FiltrCoeff);if gc > 255 then gc := 255; bc := Round( b * FiltrCoeff);if bc > 255 then bc := 255; SetArrPixel( rc or ( gc shl 8) or ( bc shl 16), XSize+1,x,YSize-y,Pict ); end; end end 75 else begin // фильтр 3x3 for y := 0 to YSize do begin for x := 0 to XSize do begin asm push esi push edi //x2 := x - 1; if x2 < 0 then x2 := x; mov esi,XSize //x3 := x ; mov edi,YSize //x4 := x + 1; if x4 > XSize then x4 := x; mov eax,x mov x3,eax //y2 := y - 1; if y2 < 0 then y2 := y; //y3 := y ; inc eax //y4 := y + 1; if y4 > YSize then y4 := y; cmp eax,esi jbe @@1 dec eax @@1: mov x4,eax mov eax,x dec eax jge @@3 inc eax @@3: mov x2,eax mov eax,y mov y3,eax inc eax cmp eax,edi jbe @@5 dec eax @@5: mov y4,eax mov eax,y dec eax jge @@7 inc eax @@7: mov y2,eax pop edi pop esi end; if Iter=1 then begin Pix[2,2] := GetArrPixel(XSize+1,x2,YSize-y2,pt2); Pix[2,3] := GetArrPixel(XSize+1,x2,YSize-y3,pt2); Pix[2,4] := GetArrPixel(XSize+1,x2,YSize-y4,pt2); Pix[3,2] := GetArrPixel(XSize+1,x3,YSize-y2,pt2); end else begin Pix[2,2] := GetArrPixel(XSize+1,x2,YSize-y2,Pict); Pix[2,3] := GetArrPixel(XSize+1,x2,YSize-y3,Pict); Pix[2,4] := GetArrPixel(XSize+1,x2,YSize-y4,Pict); Pix[3,2] := GetArrPixel(XSize+1,x3,YSize-y2,Pict); end; Pix[3,3] := GetArrPixel(XSize+1,x3,YSize-y3,pt2); Pix[3,4] := GetArrPixel(XSize+1,x3,YSize-y4,pt2); Pix[4,2] := GetArrPixel(XSize+1,x4,YSize-y2,pt2); Pix[4,3] := GetArrPixel(XSize+1,x4,YSize-y3,pt2); Pix[4,4] := GetArrPixel(XSize+1,x4,YSize-y4,pt2); 76 r := 0; g := 0; b := 0; for u := 2 to 4 do for v := 2 to 4 do begin r := r + Filtr[u,v]*(Pix[u,v] and $000000FF); g := g + Filtr[u,v]*((Pix[u,v] and $0000FF00) shr 8); b := b + Filtr[u,v]*((Pix[u,v] and $00FF0000) shr 16); end; if r < 0 then r := 0; if g < 0 then g := 0; if b < 0 then b := 0; rc := Round( r * FiltrCoeff);if rc > 255 then rc := 255; gc := Round( g * FiltrCoeff);if gc > 255 then gc := 255; bc := Round( b * FiltrCoeff);if bc > 255 then bc := 255; SetArrPixel( rc or ( gc shl 8) or ( bc shl 16), XSize+1,x,YSize-y,Pict ); end; end end; FreeMemo(pt2); end; // Сложение изображений ( или изображения с константой) function PAdd(Num1, Num2, Num3, Oper2, Xs, Ys : integer; Coeff1, Coeff2 : extended) : boolean; var x, y : integer; t1, t2, e : cardinal; r, g, b, r1, g1, b1, r2, g2, b2 : integer; begin dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t1 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num1]); if Num2>0 then t2 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num2]) else t2 := Oper2; r1 := Trunc(((t1 and $FF0000) shr 16) * Coeff1); g1 := Trunc(((t1 and $FF00) shr 8) * Coeff1); b1 := Trunc((t1 and $FF) * Coeff1); r2 := Trunc(((t2 and $FF0000) shr 16) * Coeff2); g2 := Trunc(((t2 and $FF00) shr 8) * Coeff2); b2 := Trunc((t2 and $FF) * Coeff2); asm // if (r1,g1,b1,r2,g2,b2) > 255 then (r1,g1,b1,r2,g2,b2)=255 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r1 and eax,ecx jz @@1 77 mov r1,edx @@1: mov eax,r2 and eax,ecx jz @@2 mov r2,edx @@2: mov eax,g1 and eax,ecx jz @@3 mov g1,edx @@3: mov eax,g2 and eax,ecx jz @@4 mov g2,edx @@4: mov eax,b1 and eax,ecx jz @@5 mov b1,edx @@5: mov eax,b2 and eax,ecx jz @@6 mov b2,edx @@6: or eax,eax end; r := r1 + r2; g := g1 + g2; b := b1 + b2; asm // if (r,g,b) > 255 then (r,g,b)=255 if (r,g,b) < 0 then (r,g,b)=0 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r cmp eax,edx jl @@1 mov r,edx @@1: mov eax,g cmp eax,edx jl @@2 mov g,edx @@2: mov eax,b cmp eax,edx jl @@3 mov b,edx @@3: xor edx,edx mov eax,r and eax,eax jg @@4 mov r,edx @@4: mov eax,g and eax,eax jg @@5 78 mov g,edx @@5: mov eax,b and eax,eax jg @@6 mov b,edx @@6: or eax,eax end; e := b or (g shl 8) or (r shl 16); SetArrPixel( e, Xs+1, x, Ys-y, PictArrs[Num3]); end;{for} end; // Вычитание изображений ( или изображения с константой) function PSub(Num1, Num2, Num3, Oper2, Xs, Ys : integer; Coeff1, Coeff2 : extended) : boolean; var x, y : integer; t1, t2, e : cardinal; r, g, b, r1, g1, b1, r2, g2, b2 : integer; begin dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t1 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num1]); if Num2>0 then t2 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num2]) else t2 := Oper2; r1 := Trunc(((t1 and $FF0000) shr 16) * Coeff1); g1 := Trunc(((t1 and $FF00) shr 8) * Coeff1); b1 := Trunc((t1 and $FF) * Coeff1); r2 := Trunc(((t2 and $FF0000) shr 16) * Coeff2); g2 := Trunc(((t2 and $FF00) shr 8) * Coeff2); b2 := Trunc((t2 and $FF) * Coeff2); asm // if (r1,g1,b1,r2,g2,b2) > 255 then (r1,g1,b1,r2,g2,b2)=255 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r1 and eax,ecx jz @@1 mov r1,edx @@1: mov eax,r2 and eax,ecx jz @@2 mov r2,edx @@2: mov eax,g1 and eax,ecx jz @@3 mov g1,edx @@3: mov eax,g2 79 and eax,ecx jz @@4 mov g2,edx @@4: mov eax,b1 and eax,ecx jz @@5 mov b1,edx @@5: mov eax,b2 and eax,ecx jz @@6 mov b2,edx @@6: or eax,eax end; r := r1 - r2; g := g1 - g2; b := b1 - b2; asm // if (r,g,b) > 255 then (r,g,b)=255 if (r,g,b) < 0 then (r,g,b)=0 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r cmp eax,edx jl @@1 mov r,edx @@1: mov eax,g cmp eax,edx jl @@2 mov g,edx @@2: mov eax,b cmp eax,edx jl @@3 mov b,edx @@3: xor edx,edx mov eax,r cmp eax,$0 jg @@4 mov r,edx @@4: mov eax,g cmp eax,$0 jg @@5 mov g,edx @@5: mov eax,b cmp eax,$0 jg @@6 mov b,edx @@6: or eax,eax end; e := b or (g shl 8) or (r shl 16); SetArrPixel( e, Xs+1, x, Ys-y, PictArrs[Num3]); 80 end;{for} end; // Перемножение изображений ( или изображения с константой) function PMul(Num1, Num2, Num3, Oper2, Xs, Ys : integer; Coeff1, Coeff2 : extended) : boolean; var x, y : integer; t1, t2, e : cardinal; r, g, b, r1, g1, b1, r2, g2, b2 : integer; begin dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t1 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num1]); if Num2>0 then t2 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num2]) else t2 := Oper2; r1 := Trunc(((t1 and $FF0000) shr 16) * Coeff1); g1 := Trunc(((t1 and $FF00) shr 8) * Coeff1); b1 := Trunc((t1 and $FF) * Coeff1); r2 := Trunc(((t2 and $FF0000) shr 16) * Coeff2); g2 := Trunc(((t2 and $FF00) shr 8) * Coeff2); b2 := Trunc((t2 and $FF) * Coeff2); asm // if (r1,g1,b1,r2,g2,b2) > 255 then (r1,g1,b1,r2,g2,b2)=255 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r1 and eax,ecx jz @@1 mov r1,edx @@1: mov eax,r2 and eax,ecx jz @@2 mov r2,edx @@2: mov eax,g1 and eax,ecx jz @@3 mov g1,edx @@3: mov eax,g2 and eax,ecx jz @@4 mov g2,edx @@4: mov eax,b1 and eax,ecx jz @@5 mov b1,edx @@5: mov eax,b2 and eax,ecx jz @@6 mov b2,edx 81 @@6: or eax,eax end; r := r1 * r2; g := g1 * g2; b := b1 * b2; asm // if (r,g,b) > 255 then (r,g,b)=255 if (r,g,b) < 0 then (r,g,b)=0 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r cmp eax,edx jl @@1 mov r,edx @@1: mov eax,g cmp eax,edx jl @@2 mov g,edx @@2: mov eax,b cmp eax,edx jl @@3 mov b,edx @@3: xor edx,edx mov eax,r and eax,eax jg @@4 mov r,edx @@4: mov eax,g and eax,eax jg @@5 mov g,edx @@5: mov eax,b and eax,eax jg @@6 mov b,edx @@6: or eax,eax end; e := b or (g shl 8) or (r shl 16); SetArrPixel( e, Xs+1, x, Ys-y, PictArrs[Num3]); end;{for} end; // Деление изображений ( или изображения на константу) function PDiv(Num1, Num2, Num3, Oper2, Xs, Ys : integer; Coeff1, Coeff2 : extended) : boolean; var x, y : integer; t1, t2, e : cardinal; r, g, b, r1, g1, b1, r2, g2, b2 : integer; begin dec(Xs); 82 dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t1 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num1]); if Num2>0 then t2 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num2]) else t2 := Oper2; r1 := Trunc(((t1 and $FF0000) shr 16) * Coeff1); g1 := Trunc(((t1 and $FF00) shr 8) * Coeff1); b1 := Trunc((t1 and $FF) * Coeff1); r2 := Trunc(((t2 and $FF0000) shr 16) * Coeff2); g2 := Trunc(((t2 and $FF00) shr 8) * Coeff2); b2 := Trunc((t2 and $FF) * Coeff2); asm // Проверки для исключения деления на 0; mov edx,$FF mov ecx,1 mov edx,r2 or edx,edx jnz @@1 mov r2,1 mov r1,$FF @@1: mov edx,g2 or edx,edx jnz @@2 mov g2,1 mov g1,$FF @@2: mov edx,b2 or edx,edx jnz @@3 mov b2,1 mov b1,$FF @@3: or eax,eax end; asm // if (r1,g1,b1,r2,g2,b2) > 255 then (r1,g1,b1,r2,g2,b2)=255 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r1 and eax,ecx jz @@1 mov r1,edx @@1: mov eax,r2 and eax,ecx jz @@2 mov r2,edx @@2: mov eax,g1 and eax,ecx jz @@3 mov g1,edx @@3: mov eax,g2 83 and eax,ecx jz @@4 mov g2,edx @@4: mov eax,b1 and eax,ecx jz @@5 mov b1,edx @@5: mov eax,b2 and eax,ecx jz @@6 mov b2,edx @@6: or eax,eax end; r := r1 div r2; g := g1 div g2; b := b1 div b2; asm // if (r,g,b) > 255 then (r,g,b)=255 if (r,g,b) < 0 then (r,g,b)=0 mov edx,$FF mov ecx,$FFFFFF00 mov eax,r cmp eax,edx jl @@1 mov r,edx @@1: mov eax,g cmp eax,edx jl @@2 mov g,edx @@2: mov eax,b cmp eax,edx jl @@3 mov b,edx @@3: xor edx,edx mov eax,r and eax,eax jg @@4 mov r,edx @@4: mov eax,g and eax,eax jg @@5 mov g,edx @@5: mov eax,b and eax,eax jg @@6 mov b,edx @@6: or eax,eax end; e := b or (g shl 8) or (r shl 16); SetArrPixel( e, Xs+1, x, Ys-y, PictArrs[Num3]); 84 end;{for} end; // Логическое Сложение изображений ( или изображения с константой) function POr(Num1, Num2, Num3, Oper2, Xs, Ys : integer; Coeff1, Coeff2 : extended;Not_ : boolean) : boolean; var x, y : integer; t1, t2, e : cardinal; r, g, b, r1, g1, b1, r2, g2, b2 : integer; begin dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t1 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num1]); if Num2>0 then t2 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num2]) else t2 := Oper2; r1 := Trunc(((t1 and $FF0000) shr 16) * Coeff1); g1 := Trunc(((t1 and $FF00) shr 8) * Coeff1); b1 := Trunc((t1 and $FF) * Coeff1); r2 := Trunc(((t2 and $FF0000) shr 16) * Coeff2); g2 := Trunc(((t2 and $FF00) shr 8) * Coeff2); b2 := Trunc((t2 and $FF) * Coeff2); r := r1 or r2; g := g1 or g2; b := b1 or b2; e := b or (g shl 8) or (r shl 16); if Not_ then e := (not e) and $FFFFFF; SetArrPixel( e, Xs+1, x, Ys-y, PictArrs[Num3]); end;{for} end; // Логическое умножение изображений ( или изображения с константой) function PAnd(Num1, Num2, Num3, Oper2, Xs, Ys : integer; Coeff1, Coeff2 : extended;Not_ : boolean) : boolean; var x, y : integer; t1, t2, e : cardinal; r, g, b, r1, g1, b1, r2, g2, b2 : integer; begin dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t1 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num1]); if Num2>0 then t2 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num2]) else t2 := Oper2; r1 := Trunc(((t1 and $FF0000) shr 16) * Coeff1); 85 g1 := Trunc(((t1 and $FF00) shr 8) * Coeff1); b1 := Trunc((t1 and $FF) * Coeff1); r2 := Trunc(((t2 and $FF0000) shr 16) * Coeff2); g2 := Trunc(((t2 and $FF00) shr 8) * Coeff2); b2 := Trunc((t2 and $FF) * Coeff2); r := r1 and r2; g := g1 and g2; b := b1 and b2; e := b or (g shl 8) or (r shl 16); if Not_ then e := (not e) and $FFFFFF; SetArrPixel( e, Xs+1, x, Ys-y, PictArrs[Num3]); end;{for} end; // Логическое умножение по модулю 2 изображений ( или изображения с константой) function PXor(Num1, Num2, Num3, Oper2, Xs, Ys : integer; Coeff1, Coeff2 : extended;Not_ : boolean) : boolean; var x, y : integer; t1, t2, e : cardinal; r, g, b, r1, g1, b1, r2, g2, b2 : integer; begin dec(Xs); dec(Ys); for y := 0 to Ys do for x := 0 to Xs do begin t1 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num1]); if Num2>0 then t2 := GetArrPixel(Xs+1, x, Ys-y, PictArrs[Num2]) else t2 := Oper2; r1 := Trunc(((t1 and $FF0000) shr 16) * Coeff1); g1 := Trunc(((t1 and $FF00) shr 8) * Coeff1); b1 := Trunc((t1 and $FF) * Coeff1); r2 := Trunc(((t2 and $FF0000) shr 16) * Coeff2); g2 := Trunc(((t2 and $FF00) shr 8) * Coeff2); b2 := Trunc((t2 and $FF) * Coeff2); r := r1 xor r2; g := g1 xor g2; b := b1 xor b2; e := b or (g shl 8) or (r shl 16); if Not_ then e := (not e) and $FFFFFF; SetArrPixel( e, Xs+1, x, Ys-y, PictArrs[Num3]); end;{for} end; initialization Bitmaps := TList.Create; finalization Bitmaps.Free; end. 86 СОДЕРЖАНИЕ 1 ФОРМАТ ФАЙЛА BMP ……………………………………………......... 4 1.1 Заголовок файла ……………………………………………………...... 4 1.2 Палитра ………………………………………………………………..... 6 1.3 Чтение BMP файла …………………………………………………....... 6 2 ФОРМАТ ФАЙЛА PCX ……………………………………………….... 6 2.1 Заголовок файла PCX …………………………………………...…....... 7 3 ФОРМАТ ФАЙЛА TGA …………………………………………….….... 9 3.1 Заголовок файла TGA …………………………………………….…..... 10 4 ФОРМАТ ФАЙЛА TIFF…………………………………………….…..... 11 4.1 TAGовая архитектура …………………………………………….…..... 12 4.2 Различия между TIFFом и другими форматами …………………....... 12 4.3 Преимущества формата TIFF …………………………………….…..... 13 4.4 Недостатки формата TIFF…………………………………………........ 13 4.5 Заголовок файла TIFF ………………………………………………...... 13 4.6 Directory (оглавление) ………………………………………………...... 14 4.7 Tag entry ……………………………………………………………........ 14 4.8 Совместимости ……………………………………………………......... 15 4.9 Список типов TAGов ………………………………………………....... 15 4.10 Тип данных ………………………………………………………......... 18 5 ФОРМАТ ФАЛОВ GIF ………………………………………………....... 18 5.1 Общий формат файла ………………………………………………....... 19 5.2 Идентификатор gif …………………………………………………........19 5.3 Дескриптор экрана …………………………………………………....... 20 5.4 Глобальная таблица цветов ………………………………………......... 21 5.5 Дескриптор изображения …………………………………………........ 22 5.6 Локальная таблица цветов …………………………………………....... 24 5.7 Растровые данные …………………………………………………........ 24 5.8 Терминатор gif …………………………………………………….......... 25 5.9 Расширенный блок gif …………………………………………….......... 25 87 6 ФОРМАТ ФАЛОВ PNG ……………………………………………......... 25 6.1 Общие сведения ….................................................................................... 26 6.2 Организация файла …............................................................................... 29 6.3 Детальное описание файла ….................................................................. 32 7 АЛГОРИТМ СЖАТИЯ RLE …………………………………….............. 39 8 АЛГОРИТМ СЖАТИЯ LZW ……………………………………............. 40 9 СОЗДАНИЕ НЕКОТОРЫХ ВИДЕОЭФФЕКТОВ ……………............... 47 9.1 Разложение по цветовым координатам ………………………….......... 47 9.2 Модель RGB ……………………………………………………….........50 9.3 Модель CMY ………………………………………………………......... 51 9.4 YIQ …………………………………………………………………......... 52 9.5 Модель HSV ……………………………………………………….......... 53 9.6 Модель HLS ……………………………………………………….......... 54 9.7 Использование RGB ………………………………………………......... 55 9.8 Эффект шума ……………………………………………………............ 56 9.9 Создание негатива………………………………………………............. 57 9.10 Логические операции над изображениями …………………….......... 58 9.11 Фильтрация изображений ……………………………………….......... 59 Задание к курсовой работе …………………………………………............ 60 Требования к выполнению курсовой работы ……………………….......... 64 Литература …………………………………………………………….......... 65 Приложение А -Графическая библиотека, содержащая примеры …........ 56 88 Методические указания и задания к курсовой работе по курсу “Методы и способы компьютерных информационных технологий“, (для студентовзаочников специальности 7.080403 “Программное обеспечение автоматизированных систем ”/ Составители: Наталия Евгеньевна Губенко, к.т.н., доцент Вадим Сергеевич Миргород, ассистент