В одной из статей мы упоминали, что нам не удалось найти примеры изображений в одном из описанных в блоге форматов. Тогда, проблема с отсутствием демонстрационных файлов решилась с помощью сторонних утилит и последующей конвертацией в нужный формат. Однако, очень неудобно иметь зависимость от стороннего инструмента и потому мы решили написать простой рецепт осуществления этой задачи силами 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