XPM: растровое изображение своими руками

Возьмём какую-нибудь тему из школьной информатики. Например, изучение растровой графики.

О чём по этой теме стоит разговаривать?

Ставить точки руками или обрабатывать области магией?

Среди этих тем некоторые — явно выше того, что можно в школе объяснить до конца (та же упаковка с потерями, например). Некоторые темы можно осветить только поверхностно. Можно запустить любой приличный редактор растровой графики и показать диалог выбора цвета в различных цветовых пространствах — какой при изменении параметров получается в результате цвет. Однако объяснять, почему цветовые пространства именно такие, придётся всё равно «на пальцах» (колбочки, палочки, складывание цветов, вычитание, а на освещённости/светлоте начинается уже математика).

colorpick.jpg

Диалог выбора цвета в редакторе GIMP. Довольно поучительно начать изменять один параметр из пространства HSV и пронаблюдать, как движется «прицел» и вращается маркер цвета.

Геометрические преобразования стоит исследовать уже после близкого знакомства с предыдущими темами.

А вот теме «матричное представление изображения», как это ни странно, не хватает программной наглядности. С одной стороны, имеется растровый редактор, в котором всё вполне наглядно, своими руками делается. А с другой стороны, со стороны программиста — разнообразные прекрасные библиотеки для работы с разнообразными прекрасными растровыми форматами.

И вот эта пропасть слабо преодолима. Потому что библиотеки, в конечном счёте, описывают совсем не то, что человек делает в простейшем растровом редакторе, а если описывают, то в очень общем, действительно сложном изводе. Для короткого, но познавательного изучения растровых форматов на занятиях по программированию большинство библиотек непригодны — получится изучение самих библиотек.

Байты и договоренности

Чего не хватает — это наглядного представления изображения в виде двумерного массива байтов и сопутствующей информации. Например, в «проекте рисования графика» мы использовал для этой цели… двумерный массив байтов! Более точно — массив строк, каждый символ которых соответствует отдельной точке «экрана». Обновление такого «экрана» — просто вывод всех строк на текстовый терминал.

Довольно интересный компромисс в этом плане — формат X Pixmap.

Вот, например, маленькая картинка в формате xpm: rbomb.png А вот тот же самый файл непосредственно:

   1 static char * rbomb_xpm[] = {
   2 /* width height ncolors chars_per_pixel */
   3 "32 32 5 1",
   4 /* colors */
   5 "       c None          s Transparent",
   6 "o      c gray50        s Cord",
   7 "O      c black",
   8 "$      c red",
   9 "%      c #D0D0A0       s Gold",
  10 /* pixels */
  11 "                                ",
  12 "                                ",
  13 "                                ",
  14 "                                ",
  15 "                                ",
  16 "                                ",
  17 "                                ",
  18 "                                ",
  19 "           oOoOo                ",
  20 "          O     Oo              ",
  21 "         o        O             ",
  22 "         O        o             ",
  23 "       OOOOO       O            ",
  24 "       OOOOO       o            ",
  25 "      OOOOOOO       O           ",
  26 "    oOOOOOOOOOo     o  $       $",
  27 "   oOOOOOOOOOOOo    O      $  $ ",
  28 "  oOOOOOOOOOOOOOo    o  $       ",
  29 "  OOOOOOOO%ooOOOO    O   $  $   ",
  30 " oOOOOOOOOO%ooOOOo    o   $ $   ",
  31 " OOOOOOOOOOOOOOOOO     OoO $ $ $",
  32 " OOOOOOOOOOO%ooOOO        $$    ",
  33 " OOOOOOOOOOO%ooOOO      $   $   ",
  34 " OOOOOOOOOOO%ooOOO        $  $  ",
  35 " OOOOOOOOOOOOOOOOO     $        ",
  36 " oOOOOOOOOOOOOOOOo    $   $    $",
  37 "  OOOOOOOOOOOOOOO               ",
  38 "  oOOOOOOOOOOOOOo         $     ",
  39 "   oOOOOOOOOOOOo                ",
  40 "    oOOOOOOOOOo                 ",
  41 "      oOOOOOo                   ",
  42 "                                "};

То есть сам формат — строго текстовый. Зная структуру XPM-файла, его несложно создать, и ещё проще — редактировать в произвольном текстовом редакторе.

Нетрудно заметить, что XPM-файл — это просто массив строк, записанный на языке программирования Си. Первая строка массива содержит (в строковом виде) метаинформацию: ширину и высоту картинки в точках растра, количество цветов в палитре и «количество символов на цвет». Вот этот последний параметр особенно забавен: дело в том, что последние строки XPM-файла представляют собственно изображение, причём одна точка растра соответствует фиксированному числу символов (удобнее всего, когда одному). При этом сами символы задаются произвольно в палитре, начинающейся со второй строки массива. В частности, в примере чёрному цвету соответствует символ 'O', а красному — '$'.

Цвета в палитре можно задавать в пространстве RBG (24 бита на точку), как это сделано для золотистого цвета, а можно по именам. Имена цветов X.Org (графической подсистеме, используемой в большинстве дистрибутивов Linux) заданы примерно в том же формате в файле /usr/share/X11/rgb.txt. Среди них встречаются весьма поэтично названные, например LavenderBlush или PeachPuff.

Ещё одна особенность XPM — «значимые» имена цветов (задаются в форме «s имя»); в примере значимые имена даны всем цветам, кроме красного и чёрного. Соответствующая библиотека (libxpm) позволяет программам работать с этими значащими именами вместо непосредственно символов, так что нет необходимости пользоваться ровно теми символами, которые заданы в палитре. Например, при разработке графического интерфейса можно выделить цвет фона, цвет печати, цвета обычной, затенённой и высветленной областей границы и т. п. «Кнопочка» будет нарисована независимо от того, какая в действительности задана палитра. Но и без библиотеки такие имена полезны — они указывают на назначение цвета. При описании цвета можно ещё задавать, как отображать точки этого цвета в монохромном и чёрно-белом пространстве (когда-то давно это было насущной необходимостью, т. к. далеко не все графические устройства были цветными).

Одно из имён цвета — «None» — особенное. Это не значащее имя, а именно задание цвета (значащее имя для цвета None в примере — Transparent). При обработке изображения точки цвета None считаются прозрачными, выводятся и обрабатываются соответственно.

Дальнейшее обсуждение формата выходит за рамки интересного, можно поизучать соответствующую документацию.

TODO X Pixmap

Что в итоге

При всё своей «игрушечности» формат XPM: