В одной из статей мы упоминали, что нам не удалось найти примеры изображений в одном из описанных в блоге форматов. Тогда, проблема с отсутствием демонстрационных файлов решилась с помощью сторонних утилит и последующей конвертацией в нужный формат. Однако, очень неудобно иметь зависимость от стороннего инструмента и потому мы решили написать простой рецепт осуществления этой задачи силами D.
Для конвертации файла с изображением в формате PNG в любой из файлов Portable Any Map используется dlib, а также две наших библиотеки (обе теперь есть в dub): ppmformats и farbfelded. Заготовка кода конвертации при этом будет выглядеть так:
#!/usr/bin/env dub /+ dub.sdl: name "png2ff" dependency "dlib" version="~>0.20.0" dependency "farbfelded" version="~>0.0.1" dependency "ppmformats" version="~>0.0.3" +/ import dlib.image; import farbfelded; import ppmformats; auto toFarbfeld(SuperImage simg) { FarbfeldImage ff = new FarbfeldImage(simg.width, simg.height); foreach (i; 0..simg.width) { foreach (j; 0..simg.height) { auto color = simg[i, j]; ff[i, j] = new RGBAColor( cast(int) (65535 * color.r), cast(int) (65535 * color.g), cast(int) (65535 * color.b), cast(int) (65535 * color.a) ); } } return ff; } auto toPNM(SuperImage simg, string pmFormat = "P6") { auto pmf = image(simg.width, simg.height, pmFormat); foreach (i; 0..simg.width) { foreach (j; 0..simg.height) { auto color = simg[i, j]; pmf[i, j] = new RGBColor( cast(int) (255 * color.r), cast(int) (255 * color.g), cast(int) (255 * color.b) ); } } return pmf; } void main(string[] args) { import std.stdio; import std.string; import std.traits; auto p = load(`/home/aquareji/Templates/Lenna0.png`); string[] fmts = cast(string[]) [EnumMembers!PixMapFormat]; string[] ext = ["pbm", "pgm", "ppm"]; foreach (i, e; ext) { auto I = 2 * i; SuperImage q; if (e == "pbm") { q = p.otsuBinarization; } else { q = p; } q.toPNM(fmts[I]).save(`/home/aquareji/Templates/Lenna_%s.%s`.format(fmts[I], ext[i])); q.toPNM(fmts[I+1]).save(`/home/aquareji/Templates/Lenna_%s.%s`.format(fmts[I + 1], ext[i])); } p.toFarbfeld.save(`/home/aquareji/Templates/Lenna.ff`); }
Примечание. Для тех кто забыл напоминаем, Portable AnyMap имеет 6 различных вариантов формата для изображений, которые отличаются друг от друга видом представляемой информации и “магическим числом” — сигнатурой. Сигнатура служит еще и именем формата, которое позволяет уточнить тип файла. К примеру, можно сказать, что есть формат изображения P6, подразумевая при этом файл вида Portable Any Map с сигнатурой P6, т.е. обычный бинарный вариант PPM.
Данный код реализует две функции конвертации изображения с типом SuperImage
(это тип изображения, который использует dlib) в нужные виды изображения:
toFarbfeld
– конвертация в формат Farbfeld с генерацией результата с типомFarbfeldImage
;toPNM
– конвертация в формат PNM (Portable aNy Map) с последующей генерацией одного из типовPxImage
, где x – число от 1 до 6, соответствующее номеру в сигнатуре формата.
Эти функции используются в приведенном примере-заготовке, который реализует простейший скрипт-конвертор. В скрипте прописаны нужны зависимости для dub и вручную прописаны пути для демонстрационного изображения Lenna в формате PNG. Сам скрипт при этом выполняет конвертацию изображения Лены во все известные библиотеке ppmformats форматы от P1 до P6, после чего производит конвертацию в формат Farbfeld. Кроме того, скрипт работает не только с PNG, но и другими форматами, которые поддерживает dlib, а это означает, что показанный нами код может быть использован как основа для других типов конверсии, а также как код для универсального конвертера.
Исходный файл и результат работы скрипта можно увидеть тут: https://github.com/LightHouseSoftware/EoFF