GraphicsMagick TTF字体性能
GraphicsMagick TTF Font Performance
我在C++库中使用GraphicsMagick来创建光栅化输出,该输出主要由文本组成。
我正在做这样的事情:
void gfx_writer::add_text(Magick::Image& img) const
{
using namespace Magick;
const unsigned x = // just a position;
const unsigned y_title = // just a position;
const unsigned y_heading = // just a position;
const unsigned y_value = // just a position;
img.strokeColor("transparent");
img.fillColor("black");
img.font(font_title_);
img.fontPointsize(font_size_title_);
img.draw(DrawableText{static_cast<double>(x), static_cast<double>(y_title), "a text"});
img.font(font_heading_);
img.fontPointsize(font_size_heading_);
img.draw(DrawableText{static_cast<double>(x), static_cast<double>(y_heading), "another text"});
img.font(font_value_);
img.fontPointsize(font_size_value_);
img.draw(DrawableText{static_cast<double>(x), static_cast<double>(y_value), "third text"});
}
而font_title_
、font_heading_
和font_value_
是到TTF文件的路径。
这已经不止一次了,我的表现相当糟糕。当我看到使用Sysinternals Process Monitor会发生什么时,我会看到TTF文件被反复读取。所以我的问题是:
- 每次调用
img.font(...)
时都会读取TTF文件,我的观察结果正确吗 - 有没有一种方法可以使用GraphicsMagick缓存字体,或者提供TTF文件的路径之外的其他内容
- 我还缺什么吗
注意:此答案使用ImageMagick的Magick++
库,并且GraphicsMagick可能存在较小的可移植性问题,但底层解决方案是相同的
我的观察结果正确吗,每次调用img.font(…)时都会读取TTF文件?
是的,每次都会重新加载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
这样做不止一次,我的表现相当糟糕。
值得退一步,问问:"如何重构我的解决方案,只在最后一刻绘制?"。
相关文章:
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中测量postscript字体宽度
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 大小相等但成员数量不同的结构之间的性能差异
- 为什么constexpr的性能比正常表达式差
- 在类中使用随机生成器时出现性能问题
- 如何在Directwrite中获得给定字体的可用OpenType功能
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 海湾合作委员会 ARM 性能下降
- GCC 和 Clang 代码性能的巨大差异
- 在容量内调整矢量大小时的性能影响
- 了解算法的性能差异(如果以不同的编程语言实现)
- 未达到的情况会影响开关外壳性能
- QStringList vs list<shared_ptr<QString>> 性能比较C++
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- 哪种方法更好,性能明智
- C++ 特征库:引用的性能开销<>
- 与多个 for 循环与单个 for 循环 wrt 相关的性能从多映射获取数据
- GraphicsMagick TTF字体性能