== XPM: растровое изображение своими руками == Возьмём какую-нибудь тему из школьной информатики. Например, изучение растровой графики. О чём по этой теме стоит разговаривать? * О матричном представлении изображения, в том числе — о том, что одной только матрицы недостаточно: размеры, способ кодирования цвета, другая дополнительная информация * О кодировании цветов и цветовых пространствах (как минимум — RGB, CMYK и HLS/HLV) * Об упаковке изображения и об упаковке «с потерями» * О проблемах геометрических преобразований === Ставить точки руками или обрабатывать области магией? === Среди этих тем некоторые — явно выше того, что можно в школе объяснить до конца (та же упаковка с потерями, например). Некоторые темы можно осветить только поверхностно. Можно запустить любой приличный редактор растровой графики и показать диалог выбора цвета в различных цветовых пространствах — какой при изменении параметров получается в результате цвет. Однако объяснять, почему цветовые пространства именно такие, придётся всё равно «на пальцах» (колбочки, палочки, складывание цветов, вычитание, а на освещённости/светлоте начинается уже математика). {{attachment:colorpick.jpg}} Диалог выбора цвета в редакторе [[https://www.gimp.org/|GIMP]]. Довольно поучительно начать изменять один параметр из пространства HSV и пронаблюдать, как движется «прицел» и вращается маркер цвета. Геометрические преобразования стоит исследовать уже после близкого знакомства с предыдущими темами. А вот теме «матричное представление изображения», как это ни странно, не хватает ''программной'' наглядности. С одной стороны, имеется растровый редактор, в котором всё вполне наглядно, своими руками делается. А с другой стороны, со стороны программиста — разнообразные прекрасные библиотеки для работы с разнообразными прекрасными растровыми форматами. И вот эта пропасть слабо преодолима. Потому что библиотеки, в конечном счёте, описывают совсем не то, что человек делает в простейшем растровом редакторе, а если описывают, то в очень общем, действительно сложном изводе. Для короткого, но познавательного изучения растровых форматов на занятиях по ''программированию'' большинство библиотек непригодны — получится изучение самих библиотек. === Просто строки === Чего не хватает — это наглядного представления изображения в виде двумерного массива байтов и сопутствующей информации. Например, в «[[LecturesVMSH/FunctionGraphic|проекте рисования графика]]» мы использовал для этой цели… двумерный массив байтов! Более точно — массив строк, каждый символ которых соответствует отдельной точке «экрана». Обновление такого «экрана» — просто вывод всех строк на текстовый терминал. Довольно интересный компромисс в этом плане — формат [[RW:X_Pixmap|X Pixmap]]. Вот, например, [[attachment:rbomb.xpm|маленькая картинка]] в формате xpm: {{attachment:rbomb.png}} А вот ''тот же самый файл'' непосредственно: {{{#!highlight c static char * rbomb_xpm[] = { /* width height ncolors chars_per_pixel */ "32 32 5 1", /* colors */ " c None s Transparent", "o c gray50 s Cord", "O c black", "$ c red", "% c #D0D0A0 s Gold", /* pixels */ " ", " ", " ", " ", " ", " ", " ", " ", " oOoOo ", " O Oo ", " o O ", " O o ", " OOOOO O ", " OOOOO o ", " OOOOOOO O ", " oOOOOOOOOOo o $ $", " oOOOOOOOOOOOo O $ $ ", " oOOOOOOOOOOOOOo o $ ", " OOOOOOOO%ooOOOO O $ $ ", " oOOOOOOOOO%ooOOOo o $ $ ", " OOOOOOOOOOOOOOOOO OoO $ $ $", " OOOOOOOOOOO%ooOOO $$ ", " OOOOOOOOOOO%ooOOO $ $ ", " OOOOOOOOOOO%ooOOO $ $ ", " OOOOOOOOOOOOOOOOO $ ", " oOOOOOOOOOOOOOOOo $ $ $", " OOOOOOOOOOOOOOO ", " oOOOOOOOOOOOOOo $ ", " oOOOOOOOOOOOo ", " oOOOOOOOOOo ", " oOOOOOo ", " "}; }}} То есть сам формат — '''строго текстовый'''. Зная структуру XPM-файла, его несложно создать, и ещё проще — редактировать в произвольном текстовом редакторе. Вот так, например, выглядит «подсветка синтаксиса», когда редактируешь XPM-файл с помощью редактора [[http://www.vim.org/download.php|gvim]]: {{attachment:gvimxpm.jpg}} Нетрудно заметить, что XPM-файл — это просто массив строк, записанный ''на языке программирования Си''. Первая строка массива содержит (в строковом виде) метаинформацию: ширину и высоту картинки в точках растра, количество цветов в палитре и «количество символов на цвет». Вот этот последний параметр особенно забавен: дело в том, что последние строки XPM-файла представляют собственно изображение, причём одна точка растра соответствует фиксированному числу символов (удобнее всего, когда одному). При этом сами символы задаются ''произвольно'' в палитре, начинающейся со второй строки массива. В частности, в примере чёрному цвету соответствует символ 'O', а красному — '$'. Цвета в палитре можно задавать в пространстве RBG (24 бита на точку), как это сделано для золотистого цвета, а можно по именам. Имена цветов X.Org (графической подсистеме, используемой в большинстве дистрибутивов Linux) заданы примерно в том же формате в файле [[/XColors|/usr/share/X11/rgb.txt]]. Среди них встречаются весьма поэтично названные, например !LavenderBlush или !PeachPuff. Ещё одна особенность XPM — «значимые» имена цветов (задаются в форме «s '''имя'''»); в примере значимые имена даны всем цветам, кроме красного и чёрного. Соответствующая библиотека (`libxpm`) позволяет программам работать с этими значащими именами вместо непосредственно символов, так что нет необходимости пользоваться ровно теми символами, которые заданы в палитре. Например, при разработке графического интерфейса можно выделить цвет фона, цвет печати, цвета обычной, затенённой и высветленной областей границы и т. п. «Кнопочка» будет нарисована независимо от того, какая в действительности задана палитра. Но и без библиотеки такие имена полезны — они указывают на назначение цвета. При описании цвета можно ещё задавать, как отображать точки этого цвета в монохромном и чёрно-белом пространстве (когда-то давно это было насущной необходимостью, т. к. далеко не все графические устройства были цветными). Одно из имён цвета — «`None`» — особенное. Это не значащее имя, а именно задание цвета (значащее имя для цвета None в примере — `Transparent`). При обработке изображения точки цвета `None` считаются прозрачными, выводятся и обрабатываются соответственно. Дальнейшее обсуждение формата выходит за рамки интересного, можно поизучать [[https://www.opennet.ru/docs/formats/xpm.pdf|соответствующую документацию]]. === Программа на Си === Рассмотрим [[attachment:xpmex.c|простую учебную программу]] на языке Си. В программе * XPM-файл с картинкой просто включается в исходный текст (он же тоже написан на Си!), * затем создаётся доступная на запись копия (заметим, что исходный код имеет тип `const char **`), * в этой копии модифицируется содержимое растровой матрицы, * результат записывается в новый XPM-файл (формат XPM при этом соблюдается вручную, это несложно :) ) {{{#!highlight c #include #include #include #include "face.xpm" int main(int argc, char *argv[]) { int Width, Height, PSize, BPP; int size; int beg, end, y, x, len; char **newface; FILE *fout; /* Извлекаем размеры картинки и палитры */ /* ВНИМАНИЕ! Для простоты считаем, что BPP=1 */ sscanf(face[0], "%d %d %d %d", &Width, &Height, &PSize, &BPP); /* Область картинки */ beg = PSize+1; end = PSize+Height+1; /* Копия картинки, доступная для модификации */ newface = calloc(end, sizeof(char *)); for(y=size=0; y