将文本创建为位图的工具(消除锯齿文本、自定义间距、透明背景)

Posted

技术标签:

【中文标题】将文本创建为位图的工具(消除锯齿文本、自定义间距、透明背景)【英文标题】:Tools for creating text as bitmaps (anti-aliased text, custom spacing, transparent background) 【发布时间】:2010-10-02 16:24:02 【问题描述】:

我需要批量创建带有文本的图像。要求:

    任意大小的位图 PNG 格式 透明背景 黑色文本消除了透明度的锯齿 可调整字符间距 可调整的文本位置(文本开始的 x 和 y 坐标) TrueType 和/或 Type1 支持 Unix 命令行工具或 Python 库

到目前为止,我已经评估了以下内容:

Python Imaging Library:失败 5。 ImageMagick(“标题”选项):很难弄清楚 6。 PyCairo:失败 5。 SVG + ImageMagick convert:最有前途,虽然需要多种工具

PIL 的问题在于,例如Verdana 的默认间距太稀疏了。我需要文本更紧凑一些,但在 PIL 中无法调整。

在 ImageMagick 中,我还没有找到一种简单的方法来指定图像中文本的开始位置(我使用的是 -size WIDTHxHEIGHT 和标题:'TEXT')。添加透明边框会将文本从它所锚定的角落移开,但是

图像大小需要相应调整,因为边框会增加范围 无法独立调整水平和垂直偏移

我是否错过了一些明显的替代方案或未能从上述提到的功能中找到必要的功能?

【问题讨论】:

您能详细说明一下规格吗?主要是 5 和 6,因为这似乎是您的替代品所缺乏的地方。 @PEZ 好的,我扩展了问题。 【参考方案1】:

(5) 确实看起来很棘手,没有在字符串中插入虚拟窄空格(这会破坏字距调整)或使用更高级别的东西,如 SVG 或 html/CSS 渲染器。

但是,如果您不介意弄脏自己的手,那么破解 PIL 的 freetype 渲染器来添加水平空间看起来很容易。见_imagingft.c;在 font_getsize 和 font_render 中的以下代码之后:

if (kerning && last_index && index) 
    FT_Vector delta;
    FT_Get_Kerning(self->face, last_index, index, ft_kerning_default,
                   &delta);
    x += delta.x >> 6;

添加:

if (last_index && index) 
    x += tracking;

首先尝试使用纯整数进行跟踪(根据'>>6'判断可能相当大);编译并查看它是否有效。下一步是将跟踪值从 Python 获取到 C 函数中,为此您必须将 font_render 中的 ParseTuple 调用更改为:

long tracking;
if (!PyArg_ParseTuple(args, "Ol|il:render", &string, &id, &mask, &tracking))
    return NULL;

在 font_getsize 中:

long tracking;
if (!PyArg_ParseTuple(args, "O|l:getsize", &string, &tracking))
    return NULL;

然后看你想要什么Python接口。这是通过界面的每个级别添加额外的“跟踪”参数的一个微不足道但非常乏味的案例,例如:

def truetype(filename, size, index=0, encoding="", tracking= 0): # added optional tracking
    "Load a truetype font file."
    try:
        return FreeTypeFont(filename, size, index, encoding, tracking) # added tracking
    ...

class FreeTypeFont:
    "FreeType font wrapper (requires _imagingft service)"

    def __init__(self, file, size, index=0, encoding="", tracking= 0): # added tracking
        import _imagingft
        self.font = _imagingft.getfont(file, size, index, encoding)
        self.tracking= tracking # add this line

    ...

    def getmask2(self, text, mode="", fill=Image.core.fill):
        size, offset = self.font.getsize(text, self.tracking) # use tracking
        im = fill("L", size, 0)
        self.font.render(text, im.id, mode=="1", self.tracking) # use tracking
        return im, offset

我还没有测试过这些!如果可行,可能值得作为补丁提交。

【讨论】:

整洁!为了改进您的想法,不仅可以更改绝对单位的间距,还可以更改相对于符号的正常字距调整的间距。 同意!我什至没有查看这里的单位到底是什么,但是在外部 API 级别正确执行,相对于字体大小的单位可能是最好的。【参考方案2】:

这是 SVG + ImageMagick 解决方案:

基于此模板以编程方式创建 SVG 文档,将“TEXT HERE”替换为所需的文本内容:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE svg PUBLIC
      "-//W3C//DTD SVG 1.0//EN"
      "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0"  >
  <text style="font-size: 22px; font-weight:bold; font-family: Verdana-Bold;
               letter-spacing: -1.3%;">
    <tspan x="10" y="39">TEXT HERE</tspan>
  </text>
</svg>

使用 ImageMagick 的 convert 将文档转换为背景透明的 PNG:

$ convert -background none input.svg output.png

【讨论】:

【参考方案3】:

一眼看去,Pango 支持letter spacing。 Pango 具有 Python 绑定并与 Cairo 集成。

【讨论】:

实际上我想我正在查看 PyCairo 中与 Pango 相关的功能的文档,但显然我错过了字母间距。谢谢!

以上是关于将文本创建为位图的工具(消除锯齿文本、自定义间距、透明背景)的主要内容,如果未能解决你的问题,请参考以下文章

透明位图上的抗锯齿文本

PS里图片的锯齿效果怎么做?

自定义导航栏中后退图标和文本的间距和格式

Android 自定义TextView 实现文本间距

RemoteViews (Widget) 使用 Bitmap 时文本模糊

如何在 php 中使用自定义文本创建图像?