动画 gif 上的 ImageMagick 文本水印

Posted

技术标签:

【中文标题】动画 gif 上的 ImageMagick 文本水印【英文标题】:ImageMagick text watermark on animated gif 【发布时间】:2018-01-09 08:52:27 【问题描述】:
//add text watermark on animated gif
std::vector<Image> imglist;
std::vector<Drawable> text_list;
text_list.push_back( DrawableText(0, 0, “I love you!"));
text_list.push_back( DrawableStrokeColor(Color("black")));
try 
    readImages(&imglist, "test.gif");
    for (uint32_t i = 0; i < imglist.size(); ++i) 
        imglist[i].font("./MILT_RG.ttf");
        imglist[i].draw(text_list);
    
    writeImages(imglist.begin(), imglist.end(), "test_render.gif");
 catch (Exception &error_) 

    cout << error_.what() << endl;

但是函数 writeImages 花费了太多时间。在我的测试示例中,一个 gif,900x600,20 帧,需要 1.5 秒。有什么办法可以加快速度吗?或者,一些更好的算法可以在 gif 上添加文本水印。谢谢。

【问题讨论】:

只是在 Eric 稍后上线之前疯狂地猜测,但您可以尝试将文本写入透明画布一次,然后在 20 帧中的每一帧上合成... 【参考方案1】:

您也许可以通过利用 STL 来简化事情

std::vector<Image> imglist;
DrawableList text_list; // <= Same as vector<Drawable>
text_list.push_back( DrawableText(0, 0, "I love you!"));
text_list.push_back( DrawableStrokeColor(Color("black")));
try 
    readImages(&imglist, "test.gif");
    for_each(imglist.begin(), imglist.end(), fontImage("./MILT_RG.ttf"));
    for_each(imglist.begin(), imglist.end(), drawImage(text_list));
    writeImages(imglist.begin(), imglist.end(), "test_render.gif");
 // ...

但随着您对速度更感兴趣,可能是时候考虑使用OpenMP 进行并行处理了。

#pragma omp parallel for
for (size_t i = 0; i < imglist.size(); ++i) 
    imglist[i].font("./MILT_RG.ttf");
    imglist[i].draw(text_list);

最后,您可以将字体移动到可绘制上下文中,并消除对同一 TTF 文件的重复读取。可能是最好的选择。

std::vector<Image> imglist;
DrawableList text_list;
text_list.push_back( DrawableFont("./MILT_RG.ttf"));
text_list.push_back( DrawableText(32, 32, "I love you!"));
text_list.push_back( DrawableStrokeColor(Color("black")));
try 
    readImages(&imglist, "test.gif");
    for_each(imglist.begin(), imglist.end(), drawImage(text_list));
    writeImages(imglist.begin(), imglist.end(), "test_render.gif");
 // ...

YMMV

编辑

正如 Mark 在 cmets 中指出的那样,在临时图像中绘制一次文本并在所有帧中合成可能会更快。

Geometry imgSize = imglist[0].size();
Image imgText(imgSize, Color("transparent"));
imgText.draw(text_list);
for_each(imglist.begin(), imglist.end(), compositeImage(imgText, 0, 0, AtopCompositeOp)); 

【讨论】:

在我的测试中,绘制文本的循环花费了100多毫秒,而writeImages操作花费了1300多毫秒。瓶颈可能是writeImages。请问您知道原因吗? @Yang 您可以尝试在tmpfs 或 RAMdrive 文件系统上写入,看看它是否是导致您的问题的慢速磁盘。另一种可能性是 IM 可能正在尝试在所有 20 帧中优化您的调色板... @emcconville 慢速磁盘不是问题,因为我尝试将图像写入 blob 并且它也很慢。您的后一种猜测可能是正确的。有没有办法验证并做一些优化?【参考方案2】:

我找到了一种可能的方法。我们可以根据@emcconville 的上述回答并行化程序。但是我们必须并行化成本操作,也就是量化。代码如下:

#pragma omp parallel for
for (size_t i = 0; i < imglist.size(); ++i) 
imglist[i].font("./MILT_RG.ttf");
imglist[i].draw(text_list);
imglist[i].quantize(false);

【讨论】:

以上是关于动画 gif 上的 ImageMagick 文本水印的主要内容,如果未能解决你的问题,请参考以下文章

Imagemagick:如何减小具有大静态区域的动画 GIF 的大小?

带有 ImageMagick 和许多图像的 GIF 动画

使用imagemagick的动画gif中的多种透明颜色?

如何使用 ImageMagick (php) 调整动画 gif 的大小?

使用PythonOpenCV,ImageMagick工具箱根据原始视频制作GIF动画

使用PythonOpenCV,ImageMagick工具箱根据原始视频制作GIF动画