Incorrect vertical alignment of character when using fontmode = '1' #2293

Open
jkrebs opened this Issue Dec 19, 2016 · 11 comments

Projects

None yet

4 participants

@jkrebs
jkrebs commented Dec 19, 2016

What did you do?

I installed Pillow 3.4.2 for local development (Python 2.7.12 on Ubuntu 16.04). My deployment target is Google App Engine which unfortunately still uses PIL 1.1.7.

There appears to be a backwards incompatibility (regression?) with the vertical alignment of the zero (0) character between these libraries and versions. Pillow does not align the character correctly.

I noticed it in one particular font (Verdana 13pt) when using ImageDraw.fontmode = '1' to disable anti-aliasing. The same issue does not occur with the default fontmode value.

I have tested this across 3 different official versions of the font from various downloads on Microsoft's website and Windows. These are freely available core fonts.

What actually happened?

Please compare the alignment of the zero (0) character in the aliased lines of the following images. It is very slight but it is unfortunately a big problem in my use-case.

PIL 1.1.7

pil_1_1_7

Pillow 3.4.2

pillow_3_4_2

Script

from PIL import Image, ImageDraw, ImageFont

import os.path
import string

path = os.path.dirname(os.path.abspath(__file__))

text = (string.digits
        + string.ascii_lowercase
        + string.ascii_uppercase
        + string.punctuation)

font_names = ['verdanab_a.ttf', 'verdanab_b.ttf', 'verdanab_c.ttf']

image = Image.new('RGB', (1250, 250))

draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, image.size[0], image.size[1]), fill=(255, 255, 255))

current_y = 10

for n, font_name in enumerate(font_names):
    font = ImageFont.truetype(os.path.join(path, font_name), 13)

    draw_alias = ImageDraw.Draw(image)
    draw_alias.fontmode = '1'
    draw_alias.text(
        (10, current_y),
        '%s (alias): %s' % (font_name, text),
        (0, 0, 0),
        font=font)

    current_y += 25

    draw = ImageDraw.Draw(image)
    draw.text(
        (10, current_y),
        '%s (anti-alias): %s' % (font_name, text),
        (0, 0, 0),
        font=font)

    current_y += 50

image.save(os.path.join(path, 'output.png'), 'PNG')

Fonts

fonts.zip

@aclark4life
Member

@jkrebs So it's better in PIL 1.1.7?

@aclark4life aclark4life added the Bug label Jan 8, 2017
@aclark4life aclark4life added this to the Future milestone Jan 8, 2017
@jkrebs
jkrebs commented Jan 8, 2017

@aclark4life Yes, PIL 1.1.7 aligns the zero character correctly.

@aclark4life
Member
aclark4life commented Jan 8, 2017 edited

@jkrebs Thanks, added Regression label

@wiredfool
Member

Are you building the recent Pillow, or are you installing from a wheel?

@jkrebs
jkrebs commented Jan 8, 2017

I installed Pillow 3.4.2 via pip install on Ubuntu 16.04.

As part of the setup, I installed external libraries using apt-get install libxml2-dev libxslt1-dev libz-dev python-dev libjpeg-dev zlib1g-dev libfreetype6 libfreetype6-dev

@wiredfool
Member

I strongly suspect that this is a difference in rendering in freetype.

Pip will preferrentially install from binary wheels, and all the binary wheels that we have package their own dependencies. So that is one version of freetype.

PIL doesn't have binaries, so it's building using the freetype on your machine.

I've tested this with MASTER and Pillow 1.2 (which is the earliest that builds for me, and it's basically PIL at that point), and not seeing any difference in the rendering. Specifically, both of them have an elevated 0.

This is from Pillow 1.2:
output

@hugovk
Member
hugovk commented Jan 8, 2017

@jkrebs What version of FreeType is on Google App Engine?

I can reproduce the problem with Pillow 4.0.0 / Python 2.7 and:

$ freetype-config --ftversion
2.7.0
@jkrebs
jkrebs commented Jan 8, 2017

@hugovk Is there a way to determine the version of FreeType being used by PIL or Pillow from within Python? Google App Engine is kind of a black box.

My test was carried out using PIL 1.1.7 and Pillow 3.4.2 within the same machine, both compiled from source by pip, as far as I know. Could they still be using different FreeType versions?

@hugovk
Member
hugovk commented Jan 8, 2017 edited

Is there a way to determine the version of FreeType being used by PIL or Pillow from within Python? Google App Engine is kind of a black box.

I don't know.

My test was carried out using PIL 1.1.7 and Pillow 3.4.2 within the same machine, both compiled from source by pip, as far as I know. Could they still be using different FreeType versions?

They could. It's likely when you pip installed Pillow 3.4.2 it used a binary wheel, packaging its own version of FreeType (probably FreeType 2.7 or thereabouts). I'd guess PIL was built from source and used whatever FreeType is on GAE, which could well be as ancient as PIL 1.1.7 (maybe 2.4.4 from 2010?).

@jkrebs
jkrebs commented Jan 8, 2017

I'd guess PIL was built from source and used whatever FreeType is on GAE, which could well be as ancient as PIL 1.1.7 (maybe 2.4.4 from 2010?).

I compiled PIL 1.1.7 from source (http://effbot.org/downloads/Imaging-1.1.7.tar.gz). Pip would only compile when the FreeType libraries were already installed on the system, so presumably it did not use a binary wheel. The result of freetype-config --ftversion is 2.6.1.

So we know that the test case was passing as of FreeType 2.6.1 via PIL 1.1.7.

Is there a way that I can install Pillow 3.4.2 and force it to use the system FreeType 2.6.1 as a test?

@wiredfool
Member

You can clone this git repo, then run python setup.py install and it will build against system packages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment