Примечание. В этом ответе используется библиотека Magick++
ImageMagick, и могут возникнуть незначительные проблемы с переносимостью с GraphicsMagick, но базовое решение остается тем же.
Верны ли мои наблюдения, что файлы TTF читаются при каждом вызове img.font (...)?
Да, шрифт TTF перезагружается каждый раз. Один из вариантов - установить шрифты в системе и вызвать конструктор семейства шрифтов.
DrawableFont ( const std::string &family_,
StyleType style_,
const unsigned long weight_,
StretchType stretch_ );
Большинство систем имеют какую-то систему кэширования шрифтов, которая обеспечивает более быстрый доступ, но не очень заметна на современном оборудовании.
что-то еще мне не хватает?
Попробуйте создать графический контекст, и вызывайте Magick::Image.draw
только один раз. Помните, что вызовы Drawable...
являются только переносом операторов MVG, а создание std::list<Drawable>
позволяет создавать сложные векторы. Только когда метод draw
потребляет команды рисования, это когда TTF будет загружен, поэтому его ключ готовит все команды рисования заранее.
Давайте начнем с переписывания кода, который вы предоставили (и здесь я получаю определенную степень свободы).
#include <Magick++.h>
const char * font_title_ = "fonts/OpenSans-Regular.ttf";
const char * font_heading_ = "fonts/LiberationMono-Regular.ttf";
const char * font_value_ = "fonts/sansation.ttf";
double font_size_title_ = 32;
double font_size_heading_ = 24;
double font_size_value_ = 16;
void gfx_writer_add_text(Magick::Image& img)
{
using namespace Magick;
double x = 10.0;
double y_title = 10;
double y_heading = 20.0;
double y_value = 30.0;
img.strokeColor("transparent");
img.fillColor("black");
img.font(font_title_);
img.fontPointsize(font_size_title_);
img.draw(DrawableText{x, y_title, "a text"});
img.font(font_heading_);
img.fontPointsize(font_size_heading_);
img.draw(DrawableText{x, y_heading, "another text"});
img.font(font_value_);
img.fontPointsize(font_size_value_);
img.draw(DrawableText{x, y_value, "third text"});
}
int main()
{
Magick::Image img("wizard:");
gfx_writer_add_text(img);
gfx_writer_add_text(img);
gfx_writer_add_text(img);
img.write("output.png");
}
Я могу скомпилировать и протестировать время выполнения. Я получаю следующее время:
$ time ./original.o
real 0m5.061s
user 0m0.094s
sys 0m0.029s
Рефакторинг кода для использования контекста рисования, и вызывать Magick::Image.draw
только один раз.
#include <Magick++.h>
#include <list>
const char * font_title_ = "fonts/OpenSans-Regular.ttf";
const char * font_heading_ = "fonts/LiberationMono-Regular.ttf";
const char * font_value_ = "fonts/sansation.ttf";
double font_size_title_ = 32;
double font_size_heading_ = 24;
double font_size_value_ = 16;
void gfx_writer_add_text(Magick::Image& img)
{
using namespace Magick;
double x = 10.0;
double y_title = 10;
double y_heading = 20.0;
double y_value = 30.0;
std::list<Drawable> ctx;
ctx.push_back(DrawableStrokeColor("transparent"));
ctx.push_back(DrawableFillColor("black"));
/* TITLE */
ctx.push_back(DrawablePushGraphicContext());
ctx.push_back(DrawableFont(font_title_);
ctx.push_back(DrawablePointSize(font_size_title_));
ctx.push_back(DrawableText{x, y_title, "a text"});
ctx.push_back(DrawablePopGraphicContext());
/* HEADING */
ctx.push_back(DrawablePushGraphicContext());
ctx.push_back(DrawableFont(font_heading_));
ctx.push_back(DrawablePointSize(font_size_heading_));
ctx.push_back(DrawableText{x, y_heading, "another text"});
ctx.push_back(DrawablePopGraphicContext());
/* Value */
ctx.push_back(DrawablePushGraphicContext());
ctx.push_back(DrawableFont(font_value_));
ctx.push_back(DrawablePointSize(font_size_value_));
ctx.push_back(DrawableText{x, y_value, "third text"});
ctx.push_back(DrawablePopGraphicContext());
img.draw(ctx);
}
int main()
{
Magick::Image img("wizard:");
gfx_writer_add_text(img);
gfx_writer_add_text(img);
gfx_writer_add_text(img);
img.write("output2.png");
}
И время тестирования немного лучше.
$ time ./with_context.o
real 0m0.106s
user 0m0.090s
sys 0m0.012s
Это делается не раз, и у меня довольно низкая производительность.
Стоит сделать шаг назад и спросить: «Как может рефакторинг моего решения рисовать только в самый последний момент?» .