views:

301

answers:

3

I use the following two methods to to generate text preview image for a .ttf font file

PIL method:

def make_preview(text, fontfile, imagefile, fontsize=30):
    try:
        font = ImageFont.truetype(fontfile, fontsize)
        text_width, text_height = font.getsize(text)
        img = Image.new('RGBA', (text_width, text_height))
        draw = ImageDraw.Draw(img)
        draw.text((0, 0), text, font=font, fill=(0, 0, 0))
        return True
    except:
        return False

ImageMagick method:

def make_preview(text, fontfile, imagefile, fontsize=30):
    p = subprocess.Popen(['convert', '-font', fontfile, '-background',
            'transparent', '-gravity', 'center', '-pointsize', str(fontsize),
            '-trim', '+repage', 'label:%s' % text, image_file])
    return p==0

Both methods create correct preview images most of time but in some rare cases (<2%), the font.getsize(text) just cannot get the correct text size which result in text overflowed provided canvas. ImageMagick has same problem.

Sample fonts and previews:

HANFORD.TTF

NEWTOW.TTF

MILF.TTF

SWANSE.TTF

I have looked into ImageMagick's documentations and found the explanation of this problem at http://www.imagemagick.org/Usage/text/#overflow.

Is it possible to detect such text overflows and draw text to fit the canvas as we expected?

+2  A: 

I had a similar issue once in PHP and ImageMagick.

In the end, I solved this by drawing the text on a very large canvas, and then trimming it using the trim/auto-crop functions that shave extra space off the image.

If I understand your preview function right, it is actually already doing exactly that: It should be enough to just remove the width and height settings.

Pekka
@Pekka, your method may works with IM but it will create big overhead, not only trimming but also resizing trimmed image to fit into specified canvas dimension. This doesn't work with PIL. It always draws upper half of above fonts even i create a larger canvas.
jack
Try putting the "label" command *before* the trim and repage commands, that should work. The overhead, I can't help.
Pekka
+1  A: 

In this case, just specify ImageMagick to use a larger canvas size with a fixed font size and it will draw text at specified point size while keeping its integrity.

def make_preview(text, fontfile, imagefile, fontsize=30):
    p = subprocess.call(['convert', '-font', fontfile, '-background', 
        'transparent', '-gravity', 'center', '-size', '1500x300',
        '-pointsize', str(fontsize),  '-trim', '+repage', 'label:%s' % text, image_file]) 
    return p==0 

If you need to fit text into specified canvas rather than using a fixed point size, you may need to resize the output image after it's created.

PIL doesn't do this very well drawing exotic fonts, no matter what point size you specify to load a font, it always overflows text outside output image.

henry
+1  A: 

alt text

Not a programming solution, but when I regenerate your problem, its only happens on your fonts (other fonts like Arial is no problem at all), so I have fixed your font files (by changing ascent/decent metrics). you can download here,

And sorry about Hanford Script Font, its not perfect as you see, height seems ok, but left side is not get drawed, its out of my understanding.

UPDATE: Regarding Hanford Font, Here is a work around, pass extra space in text like " Handford Script", and then crop the extra space in image like img=img.crop(img.getbbox())

alt text

UPDATE2:I had to pass color=(255,255,255) in Image.New to get Black Text on White background

img = Image.new('RGBA', (text_width, text_height),color=(255,255,255))

alt text

S.Mark
how to modify ascent/decent metric for a specified font? Is manual re-calucation needed on a per font basis?
jack
I used fontforge to edit those fonts, jack.
S.Mark
Due to copyright issues, i think it's better to leave the font as it is and draw text on a larger canvas and then crop it. but your method worked for personal use. Thanks for your advice.
jack
Pretty correct, but how come you put them to public downloadable first? I will remove download link on my post soon.
S.Mark