I need to batch create images with text. Requirements:
So far I've evaluated the following:
The problem with PIL is that e.g. the default spacing for Verdana is way too sparse. I need the text to be a bit tighter, but there's no way to adjust it in PIL.
In ImageMagick I haven't found an easy way to specify where in the image the text begins (I'm using -size WIDTHxHEIGHT and caption:'TEXT'). Adding a transparent border will move the text away from the corner it's achored to, but
Have I missed some obvious alternatives or failed to find necessary features from the above mentioned?
(5) indeed looks tricky, short of inserting dummy narrow-spaces into the string (which will break kerning) or using something much higher-level like the SVG or HTML/CSS renderer.
However, if you don't mind getting your hands dirty, it looks quite easy to hack PIL's freetype renderer into adding horizontal space. See _imagingft.c; after the following code in both font_getsize and 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;
}
Add:
if (last_index && index) {
x += tracking;
}
Try it with a plain integer for tracking (probably quite large judging by that '>>6') first; compile and see if it works. The next step would be to get the tracking value into the C function from Python, for which you would have to change the ParseTuple call in font_render to:
long tracking;
if (!PyArg_ParseTuple(args, "Ol|il:render", &string, &id, &mask, &tracking))
return NULL;
And in font_getsize:
long tracking;
if (!PyArg_ParseTuple(args, "O|l:getsize", &string, &tracking))
return NULL;
Then look at what Python interface you want. This is a trivial but quite tedious case of adding the extra 'tracking' argument through each level of the interface, for example:
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
I haven't tested any of this! If it works, might be worth submitting as a patch.
Here's the SVG + ImageMagick solution:
Programmatically create SVG documents based on this template, replacing "TEXT HERE" with the desired text content:
<?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" width="152px" height="50px">
<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>
Convert the documents to background-transparent PNGs with ImageMagick's convert
:
$ convert -background none input.svg output.png
From a quick glance, Pango has support for letter spacing. Pango has Python bindings and is integrated with Cairo.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With