drawbot icon indicating copy to clipboard operation
drawbot copied to clipboard

Kerning pairs missing with FormattedString, works with app but not with module

Open joachimvu opened this issue 5 years ago • 14 comments

The Issue

The output of passing some text to a FormattedString is missing some kerning pairs when I use the module version of Drawbot, but works properly when using the same script with the app.

The script

I'm working on a cli tool to generate various documents using the drawBot module. A part of it is reading from a text file and outputting a pdf, appending the content of the file to a FormattedString.

The input text file is mixing regular text and slashed glyph names, in a way that it's also usable as a sample strings file inside Glyphs (its generated from another script, parses the kerning groups in a Glyphs file to make the needed strings and uses slashed glyph names for the two glyphs of a pair to support alternates and other unencoded glyphs): non/o/o non ono/o/o ono\nnon/o/a non ono/o/a ono\nnon/a/o non ono/a/o ono\nnon/o/b non ono/o/b ono\nnon/c/o non ono/c/o ono\nnon/e/o non ono/e/o ono\nnon/o/f non ono/o/f ono\nnon/f/o non ono/f/o ono\nnon/o/g non ono/o/g ono\nnon/g/o non ono/g/o ono\nnon/o/i non ono/o/i ono\nnon/i/o non ono/i/o ono\nnon/o/j non ono/o/j ono\nnon/j/o non ono/j/o ono\nnon/k/o non ono/k/o ono\nnon/o/l non ono/o/l ono\nnon/l/o non ono/l/o ono\nnon/q/o non ono/q/o ono\nnon/r/o non ono/r/o ono\nnon/o/s non ono/o/s ono\nnon/s/o non ono/s/o ono\nnon/o/t non ono/o/t ono\nnon/t/o non ono/t/o ono\nnon/o/u non ono/o/u ono\nnon/u/o non ono/u/o ono\nnon/o/v non ono/o/v ono\nnon/v/o non ono/v/o ono\nnon/o/w non ono/o/w ono\nnon/w/o non ono/w/o ono\nnon/o/x non ono/o/x ono\nnon/x/o non ono/x/o ono\nnon/o/y non ono/o/y ono\nnon/y/o non ono/y/o ono\nnon/o/z non ono/o/z ono\nnon/z/o non ono/z/o ono\n

Here's the script that's responsible for outputting the pdf, rewritten so it can be launched on its own, both from and outside the Drawbot app:

from drawBot import *
import os
import re

text = "path/to/text/file.txt"
fontPath = "path/to/font.otf"
fontSize = 16

width = 842
height = 1190
margin = 20

newDrawing()
font = installFont(fontPath)
content = FormattedString()
content.font(font)
content.fontSize(fontSize)
content.openTypeFeatures(calt=True, kern=True)
x, y, w, h = margin, margin, width - margin * 2, height - margin * 2

with open(text, "r") as reader:
    for p in reader.readlines():
        split_p = p.split("\\n")
        for line in split_p:
            if line:
                line = line.strip('\n')
                slashed_glyphnames = re.findall(
                    r"(.*?)((?:\/\w+)(?:\.\w*)*)([\w ]*)", line
                )
                if slashed_glyphnames:
                    for match in slashed_glyphnames:
                        for group in match:
                            if group and group[0] == "/":
                                glyphname = group[1:].strip()
                                content.appendGlyph(glyphname)
                            elif group != " ":
                                content.append(group.strip())
                    content.append("\n")
                else:
                    content.append(line)
                    content.append("\n")

while len(content) > 0:
    newPage(width, height)

    colSize = w / 3
    for c in range(3):
        content = textBox(
            content, (x + (colSize * c), y, colSize, h), align="left"
        )
        
saveImage("~/Desktop/test.pdf")
uninstallFont(font)
endDrawing()

Results

The output of that script is that the generated pdf when using the module version of Drawbot is missing some kerning. Using the exact same script from inside the app produced a correct result:

module: Capture d’écran 2020-11-07 à 20 07 40

app: Capture d’écran 2020-11-07 à 20 10 05

I originally thought it could be a cache issue, but I tested generating a font multiple times with drawing changes and they appeared in the output pdf every time.

Also to note: depending on the length of the text file, its not always the same pairs that go missing with the module version of the script. Using as input just the small chunk of text presented at the beginning of this post, the output will be just fine. It seems that problems occur past a certain length, but I havent been able to figure out exactly what is triggering the errors. For reference, here is the text file used to make the pdf from the two screenshots above.

kern.txt

joachimvu avatar Nov 07 '20 19:11 joachimvu

Your kern.txt file doesn't match the screenshots, though.

A few things:

  • Does it make a difference whether the font is installed "normally" vs using installFont()?
  • Can you make a simpler test that does not read from an external file, and does not do /glyphname parsing? Some hard coded glyph names should be enough.
  • Can you reproduce it with a system font?
  • Can you reproduce it with an open source font so we can look at the exact same thing?

justvanrossum avatar Nov 08 '20 16:11 justvanrossum

Hi Just, thank you for your answer.

The screenshots are from line 28 of the kern.txt (in the UC/UC section)

• The following tests are made with an installed version of IBMPlexSans-Bold, and AvenirNext-Heavy for the system font. • A simpler script now includes the kern strings as one big string, without slashed glyph names. It's rather long because, according to my previous tests, size seem to have something to do with the issue. I've kept the same content that I know will show the problems.

The exact same issues are reproducible with these new tests:

Heres IBM Plex Sans, module: Capture d’écran 2020-11-08 à 18 16 22

IBM Plex Sans, app: Capture d’écran 2020-11-08 à 18 16 46

Avenir Next Heavy, module: Capture d’écran 2020-11-08 à 18 19 12

Avenir Next Heavy, app: Capture d’écran 2020-11-08 à 18 19 48

The script used for these tests:

from drawBot import *

text = """lc/lc
nonnnnonononnono\nnonnononononoono\nnononnononoonono\nnonnanonononaono\nnonannononoanono\nnonnbnonononbono\nnoncnnononocnono\nnonennononoenono\nnonnfnonononfono\nnonfnnononofnono\nnonngnononongono\nnongnnononognono\nnonninonononiono\nnoninnononoinono\nnonnjnonononjono\nnonjnnononojnono\nnonknnononoknono\nnonnlnonononlono\nnonlnnononolnono\nnonqnnononoqnono\nnonrnnononornono\nnonnsnonononsono\nnonsnnononosnono\nnonntnononontono\nnontnnononotnono\nnonnunonononuono\nnonunnononounono\nnonnvnonononvono\nnonvnnononovnono\nnonnwnonononwono\nnonwnnononownono\nnonnxnonononxono\nnonxnnononoxnono\nnonnynonononyono\nnonynnononoynono\nnonnznonononzono\nnonznnononoznono\n
nonoonononoooono\nnonoanononooaono\nnonaonononoaoono\nnonobnononoobono\nnonconononocoono\nnoneonononoeoono\nnonofnononoofono\nnonfonononofoono\nnonognononoogono\nnongonononogoono\nnonoinononooiono\nnonionononoioono\nnonojnononoojono\nnonjonononojoono\nnonkonononokoono\nnonolnononoolono\nnonlonononoloono\nnonqonononoqoono\nnonronononoroono\nnonosnononoosono\nnonsonononosoono\nnonotnononootono\nnontonononotoono\nnonounononoouono\nnonuonononouoono\nnonovnononoovono\nnonvonononovoono\nnonownononoowono\nnonwonononowoono\nnonoxnononooxono\nnonxonononoxoono\nnonoynononooyono\nnonyonononoyoono\nnonoznononoozono\nnonzonononozoono\n
nonaanononoaaono\nnonabnononoabono\nnoncanononocaono\nnoneanononoeaono\nnonafnononoafono\nnonfanononofaono\nnonagnononoagono\nnonganononogaono\nnonainononoaiono\nnonianononoiaono\nnonajnononoajono\nnonjanononojaono\nnonkanononokaono\nnonalnononoalono\nnonlanononolaono\nnonqanononoqaono\nnonranononoraono\nnonasnononoasono\nnonsanononosaono\nnonatnononoatono\nnontanononotaono\nnonaunononoauono\nnonuanononouaono\nnonavnononoavono\nnonvanononovaono\nnonawnononoawono\nnonwanononowaono\nnonaxnononoaxono\nnonxanononoxaono\nnonaynononoayono\nnonyanononoyaono\nnonaznononoazono\nnonzanononozaono\n
noncbnononocbono\nnonebnononoebono\nnonfbnononofbono\nnongbnononogbono\nnonibnononoibono\nnonjbnononojbono\nnonkbnononokbono\nnonlbnononolbono\nnonqbnononoqbono\nnonrbnononorbono\nnonsbnononosbono\nnontbnononotbono\nnonubnononoubono\nnonvbnononovbono\nnonwbnononowbono\nnonxbnononoxbono\nnonybnononoybono\nnonzbnononozbono\n
noncfnononocfono\nnoncgnononocgono\nnoncinononociono\nnoncjnononocjono\nnonclnononoclono\nnoncsnononocsono\nnonctnononoctono\nnoncunononocuono\nnoncvnononocvono\nnoncwnononocwono\nnoncxnononocxono\nnoncynononocyono\nnoncznononoczono\n
nonefnononoefono\nnonegnononoegono\nnoneinononoeiono\nnonejnononoejono\nnonelnononoelono\nnonesnononoesono\nnonetnononoetono\nnoneunononoeuono\nnonevnononoevono\nnonewnononoewono\nnonexnononoexono\nnoneynononoeyono\nnoneznononoezono\n
nonffnononoffono\nnonfgnononofgono\nnongfnononogfono\nnonfinononofiono\nnonifnononoifono\nnonfjnononofjono\nnonjfnononojfono\nnonkfnononokfono\nnonflnononoflono\nnonlfnononolfono\nnonqfnononoqfono\nnonrfnononorfono\nnonfsnononofsono\nnonsfnononosfono\nnonftnononoftono\nnontfnononotfono\nnonfunononofuono\nnonufnononoufono\nnonfvnononofvono\nnonvfnononovfono\nnonfwnononofwono\nnonwfnononowfono\nnonfxnononofxono\nnonxfnononoxfono\nnonfynononofyono\nnonyfnononoyfono\nnonfznononofzono\nnonzfnononozfono\n
nonggnononoggono\nnonginononogiono\nnonignononoigono\nnongjnononogjono\nnonjgnononojgono\nnonkgnononokgono\nnonglnononoglono\nnonlgnononolgono\nnonqgnononoqgono\nnonrgnononorgono\nnongsnononogsono\nnonsgnononosgono\nnongtnononogtono\nnontgnononotgono\nnongunononoguono\nnonugnononougono\nnongvnononogvono\nnonvgnononovgono\nnongwnononogwono\nnonwgnononowgono\nnongxnononogxono\nnonxgnononoxgono\nnongynononogyono\nnonygnononoygono\nnongznononogzono\nnonzgnononozgono\n
noniinononoiiono\nnonijnononoijono\nnonjinononojiono\nnonkinononokiono\nnonilnononoilono\nnonlinononoliono\nnonqinononoqiono\nnonrinononoriono\nnonisnononoisono\nnonsinononosiono\nnonitnononoitono\nnontinononotiono\nnoniunononoiuono\nnonuinononouiono\nnonivnononoivono\nnonvinononoviono\nnoniwnononoiwono\nnonwinononowiono\nnonixnononoixono\nnonxinononoxiono\nnoniynononoiyono\nnonyinononoyiono\nnoniznononoizono\nnonzinononoziono\n
nonjjnononojjono\nnonkjnononokjono\nnonjlnononojlono\nnonljnononoljono\nnonqjnononoqjono\nnonrjnononorjono\nnonjsnononojsono\nnonsjnononosjono\nnonjtnononojtono\nnontjnononotjono\nnonjunononojuono\nnonujnononoujono\nnonjvnononojvono\nnonvjnononovjono\nnonjwnononojwono\nnonwjnononowjono\nnonjxnononojxono\nnonxjnononoxjono\nnonjynononojyono\nnonyjnononoyjono\nnonjznononojzono\nnonzjnononozjono\n
nonklnononoklono\nnonksnononoksono\nnonktnononoktono\nnonkunononokuono\nnonkvnononokvono\nnonkwnononokwono\nnonkxnononokxono\nnonkynononokyono\nnonkznononokzono\n
nonllnononollono\nnonqlnononoqlono\nnonrlnononorlono\nnonlsnononolsono\nnonslnononoslono\nnonltnononoltono\nnontlnononotlono\nnonlunononoluono\nnonulnononoulono\nnonlvnononolvono\nnonvlnononovlono\nnonlwnononolwono\nnonwlnononowlono\nnonlxnononolxono\nnonxlnononoxlono\nnonlynononolyono\nnonylnononoylono\nnonlznononolzono\nnonzlnononozlono\n
nonqsnononoqsono\nnonqtnononoqtono\nnonqunononoquono\nnonqvnononoqvono\nnonqwnononoqwono\nnonqxnononoqxono\nnonqynononoqyono\nnonqznononoqzono\n
nonrsnononorsono\nnonrtnononortono\nnonrunononoruono\nnonrvnononorvono\nnonrwnononorwono\nnonrxnononorxono\nnonrynononoryono\nnonrznononorzono\n
nonssnononossono\nnonstnononostono\nnontsnononotsono\nnonsunononosuono\nnonusnononousono\nnonsvnononosvono\nnonvsnononovsono\nnonswnononoswono\nnonwsnononowsono\nnonsxnononosxono\nnonxsnononoxsono\nnonsynononosyono\nnonysnononoysono\nnonsznononoszono\nnonzsnononozsono\n
nonttnononottono\nnontunononotuono\nnonutnononoutono\nnontvnononotvono\nnonvtnononovtono\nnontwnononotwono\nnonwtnononowtono\nnontxnononotxono\nnonxtnononoxtono\nnontynononotyono\nnonytnononoytono\nnontznononotzono\nnonztnononoztono\n
nonuunononouuono\nnonuvnononouvono\nnonvunononovuono\nnonuwnononouwono\nnonwunononowuono\nnonuxnononouxono\nnonxunononoxuono\nnonuynononouyono\nnonyunononoyuono\nnonuznononouzono\nnonzunononozuono\n
nonvvnononovvono\nnonvwnononovwono\nnonwvnononowvono\nnonvxnononovxono\nnonxvnononoxvono\nnonvynononovyono\nnonyvnononoyvono\nnonvznononovzono\nnonzvnononozvono\n
nonwwnononowwono\nnonwxnononowxono\nnonxwnononoxwono\nnonwynononowyono\nnonywnononoywono\nnonwznononowzono\nnonzwnononozwono\n
nonxxnononoxxono\nnonxynononoxyono\nnonyxnononoyxono\nnonxznononoxzono\nnonzxnononozxono\n
nonyynononoyyono\nnonyznononoyzono\nnonzynononozyono\n
nonzznononozzono\n

UC/UC
HOHHHHOHOHOHHOHO\nHOHHOHOHOHOHOOHO\nHOHOHHOHOHOOHOHO\nHOHHAHOHOHOHAOHO\nHOHAHHOHOHOAHOHO\nHOHBHHOHOHOBHOHO\nHOHCHHOHOHOCHOHO\nHOHEHHOHOHOEHOHO\nHOHFHHOHOHOFHOHO\nHOHGHHOHOHOGHOHO\nHOHHJHOHOHOHJOHO\nHOHJHHOHOHOJHOHO\nHOHKHHOHOHOKHOHO\nHOHLHHOHOHOLHOHO\nHOHHMHOHOHOHMOHO\nHOHMHHOHOHOMHOHO\nHOHHNHOHOHOHNOHO\nHOHNHHOHOHONHOHO\nHOHPHHOHOHOPHOHO\nHOHRHHOHOHORHOHO\nHOHHSHOHOHOHSOHO\nHOHSHHOHOHOSHOHO\nHOHHTHOHOHOHTOHO\nHOHTHHOHOHOTHOHO\nHOHHUHOHOHOHUOHO\nHOHUHHOHOHOUHOHO\nHOHHVHOHOHOHVOHO\nHOHVHHOHOHOVHOHO\nHOHHWHOHOHOHWOHO\nHOHWHHOHOHOWHOHO\nHOHHXHOHOHOHXOHO\nHOHXHHOHOHOXHOHO\nHOHHYHOHOHOHYOHO\nHOHYHHOHOHOYHOHO\nHOHHZHOHOHOHZOHO\nHOHZHHOHOHOZHOHO\n
HOHOOHOHOHOOOOHO\nHOHOAHOHOHOOAOHO\nHOHAOHOHOHOAOOHO\nHOHBOHOHOHOBOOHO\nHOHCOHOHOHOCOOHO\nHOHEOHOHOHOEOOHO\nHOHFOHOHOHOFOOHO\nHOHGOHOHOHOGOOHO\nHOHOJHOHOHOOJOHO\nHOHJOHOHOHOJOOHO\nHOHKOHOHOHOKOOHO\nHOHLOHOHOHOLOOHO\nHOHOMHOHOHOOMOHO\nHOHMOHOHOHOMOOHO\nHOHONHOHOHOONOHO\nHOHNOHOHOHONOOHO\nHOHPOHOHOHOPOOHO\nHOHROHOHOHOROOHO\nHOHOSHOHOHOOSOHO\nHOHSOHOHOHOSOOHO\nHOHOTHOHOHOOTOHO\nHOHTOHOHOHOTOOHO\nHOHOUHOHOHOOUOHO\nHOHUOHOHOHOUOOHO\nHOHOVHOHOHOOVOHO\nHOHVOHOHOHOVOOHO\nHOHOWHOHOHOOWOHO\nHOHWOHOHOHOWOOHO\nHOHOXHOHOHOOXOHO\nHOHXOHOHOHOXOOHO\nHOHOYHOHOHOOYOHO\nHOHYOHOHOHOYOOHO\nHOHOZHOHOHOOZOHO\nHOHZOHOHOHOZOOHO\n
HOHAAHOHOHOAAOHO\nHOHBAHOHOHOBAOHO\nHOHCAHOHOHOCAOHO\nHOHEAHOHOHOEAOHO\nHOHFAHOHOHOFAOHO\nHOHGAHOHOHOGAOHO\nHOHAJHOHOHOAJOHO\nHOHJAHOHOHOJAOHO\nHOHKAHOHOHOKAOHO\nHOHLAHOHOHOLAOHO\nHOHAMHOHOHOAMOHO\nHOHMAHOHOHOMAOHO\nHOHANHOHOHOANOHO\nHOHNAHOHOHONAOHO\nHOHPAHOHOHOPAOHO\nHOHRAHOHOHORAOHO\nHOHASHOHOHOASOHO\nHOHSAHOHOHOSAOHO\nHOHATHOHOHOATOHO\nHOHTAHOHOHOTAOHO\nHOHAUHOHOHOAUOHO\nHOHUAHOHOHOUAOHO\nHOHAVHOHOHOAVOHO\nHOHVAHOHOHOVAOHO\nHOHAWHOHOHOAWOHO\nHOHWAHOHOHOWAOHO\nHOHAXHOHOHOAXOHO\nHOHXAHOHOHOXAOHO\nHOHAYHOHOHOAYOHO\nHOHYAHOHOHOYAOHO\nHOHAZHOHOHOAZOHO\nHOHZAHOHOHOZAOHO\n
HOHBJHOHOHOBJOHO\nHOHBMHOHOHOBMOHO\nHOHBNHOHOHOBNOHO\nHOHBSHOHOHOBSOHO\nHOHBTHOHOHOBTOHO\nHOHBUHOHOHOBUOHO\nHOHBVHOHOHOBVOHO\nHOHBWHOHOHOBWOHO\nHOHBXHOHOHOBXOHO\nHOHBYHOHOHOBYOHO\nHOHBZHOHOHOBZOHO\n
HOHCJHOHOHOCJOHO\nHOHCMHOHOHOCMOHO\nHOHCNHOHOHOCNOHO\nHOHCSHOHOHOCSOHO\nHOHCTHOHOHOCTOHO\nHOHCUHOHOHOCUOHO\nHOHCVHOHOHOCVOHO\nHOHCWHOHOHOCWOHO\nHOHCXHOHOHOCXOHO\nHOHCYHOHOHOCYOHO\nHOHCZHOHOHOCZOHO\n
HOHEJHOHOHOEJOHO\nHOHEMHOHOHOEMOHO\nHOHENHOHOHOENOHO\nHOHESHOHOHOESOHO\nHOHETHOHOHOETOHO\nHOHEUHOHOHOEUOHO\nHOHEVHOHOHOEVOHO\nHOHEWHOHOHOEWOHO\nHOHEXHOHOHOEXOHO\nHOHEYHOHOHOEYOHO\nHOHEZHOHOHOEZOHO\n
HOHFJHOHOHOFJOHO\nHOHFMHOHOHOFMOHO\nHOHFNHOHOHOFNOHO\nHOHFSHOHOHOFSOHO\nHOHFTHOHOHOFTOHO\nHOHFUHOHOHOFUOHO\nHOHFVHOHOHOFVOHO\nHOHFWHOHOHOFWOHO\nHOHFXHOHOHOFXOHO\nHOHFYHOHOHOFYOHO\nHOHFZHOHOHOFZOHO\n
HOHGJHOHOHOGJOHO\nHOHGMHOHOHOGMOHO\nHOHGNHOHOHOGNOHO\nHOHGSHOHOHOGSOHO\nHOHGTHOHOHOGTOHO\nHOHGUHOHOHOGUOHO\nHOHGVHOHOHOGVOHO\nHOHGWHOHOHOGWOHO\nHOHGXHOHOHOGXOHO\nHOHGYHOHOHOGYOHO\nHOHGZHOHOHOGZOHO\n
HOHJJHOHOHOJJOHO\nHOHKJHOHOHOKJOHO\nHOHLJHOHOHOLJOHO\nHOHJMHOHOHOJMOHO\nHOHMJHOHOHOMJOHO\nHOHJNHOHOHOJNOHO\nHOHNJHOHOHONJOHO\nHOHPJHOHOHOPJOHO\nHOHRJHOHOHORJOHO\nHOHJSHOHOHOJSOHO\nHOHSJHOHOHOSJOHO\nHOHJTHOHOHOJTOHO\nHOHTJHOHOHOTJOHO\nHOHJUHOHOHOJUOHO\nHOHUJHOHOHOUJOHO\nHOHJVHOHOHOJVOHO\nHOHVJHOHOHOVJOHO\nHOHJWHOHOHOJWOHO\nHOHWJHOHOHOWJOHO\nHOHJXHOHOHOJXOHO\nHOHXJHOHOHOXJOHO\nHOHJYHOHOHOJYOHO\nHOHYJHOHOHOYJOHO\nHOHJZHOHOHOJZOHO\nHOHZJHOHOHOZJOHO\n
HOHKMHOHOHOKMOHO\nHOHKNHOHOHOKNOHO\nHOHKSHOHOHOKSOHO\nHOHKTHOHOHOKTOHO\nHOHKUHOHOHOKUOHO\nHOHKVHOHOHOKVOHO\nHOHKWHOHOHOKWOHO\nHOHKXHOHOHOKXOHO\nHOHKYHOHOHOKYOHO\nHOHKZHOHOHOKZOHO\n
HOHLMHOHOHOLMOHO\nHOHLNHOHOHOLNOHO\nHOHLSHOHOHOLSOHO\nHOHLTHOHOHOLTOHO\nHOHLUHOHOHOLUOHO\nHOHLVHOHOHOLVOHO\nHOHLWHOHOHOLWOHO\nHOHLXHOHOHOLXOHO\nHOHLYHOHOHOLYOHO\nHOHLZHOHOHOLZOHO\n
HOHMMHOHOHOMMOHO\nHOHMNHOHOHOMNOHO\nHOHNMHOHOHONMOHO\nHOHPMHOHOHOPMOHO\nHOHRMHOHOHORMOHO\nHOHMSHOHOHOMSOHO\nHOHSMHOHOHOSMOHO\nHOHMTHOHOHOMTOHO\nHOHTMHOHOHOTMOHO\nHOHMUHOHOHOMUOHO\nHOHUMHOHOHOUMOHO\nHOHMVHOHOHOMVOHO\nHOHVMHOHOHOVMOHO\nHOHMWHOHOHOMWOHO\nHOHWMHOHOHOWMOHO\nHOHMXHOHOHOMXOHO\nHOHXMHOHOHOXMOHO\nHOHMYHOHOHOMYOHO\nHOHYMHOHOHOYMOHO\nHOHMZHOHOHOMZOHO\nHOHZMHOHOHOZMOHO\n
HOHNNHOHOHONNOHO\nHOHPNHOHOHOPNOHO\nHOHRNHOHOHORNOHO\nHOHNSHOHOHONSOHO\nHOHSNHOHOHOSNOHO\nHOHNTHOHOHONTOHO\nHOHTNHOHOHOTNOHO\nHOHNUHOHOHONUOHO\nHOHUNHOHOHOUNOHO\nHOHNVHOHOHONVOHO\nHOHVNHOHOHOVNOHO\nHOHNWHOHOHONWOHO\nHOHWNHOHOHOWNOHO\nHOHNXHOHOHONXOHO\nHOHXNHOHOHOXNOHO\nHOHNYHOHOHONYOHO\nHOHYNHOHOHOYNOHO\nHOHNZHOHOHONZOHO\nHOHZNHOHOHOZNOHO\n
HOHPSHOHOHOPSOHO\nHOHPTHOHOHOPTOHO\nHOHPUHOHOHOPUOHO\nHOHPVHOHOHOPVOHO\nHOHPWHOHOHOPWOHO\nHOHPXHOHOHOPXOHO\nHOHPYHOHOHOPYOHO\nHOHPZHOHOHOPZOHO\n
HOHRSHOHOHORSOHO\nHOHRTHOHOHORTOHO\nHOHRUHOHOHORUOHO\nHOHRVHOHOHORVOHO\nHOHRWHOHOHORWOHO\nHOHRXHOHOHORXOHO\nHOHRYHOHOHORYOHO\nHOHRZHOHOHORZOHO\n
HOHSSHOHOHOSSOHO\nHOHSTHOHOHOSTOHO\nHOHTSHOHOHOTSOHO\nHOHSUHOHOHOSUOHO\nHOHUSHOHOHOUSOHO\nHOHSVHOHOHOSVOHO\nHOHVSHOHOHOVSOHO\nHOHSWHOHOHOSWOHO\nHOHWSHOHOHOWSOHO\nHOHSXHOHOHOSXOHO\nHOHXSHOHOHOXSOHO\nHOHSYHOHOHOSYOHO\nHOHYSHOHOHOYSOHO\nHOHSZHOHOHOSZOHO\nHOHZSHOHOHOZSOHO\n
HOHTTHOHOHOTTOHO\nHOHTUHOHOHOTUOHO\nHOHUTHOHOHOUTOHO\nHOHTVHOHOHOTVOHO\nHOHVTHOHOHOVTOHO\nHOHTWHOHOHOTWOHO\nHOHWTHOHOHOWTOHO\nHOHTXHOHOHOTXOHO\nHOHXTHOHOHOXTOHO\nHOHTYHOHOHOTYOHO\nHOHYTHOHOHOYTOHO\nHOHTZHOHOHOTZOHO\nHOHZTHOHOHOZTOHO\n
HOHUUHOHOHOUUOHO\nHOHUVHOHOHOUVOHO\nHOHVUHOHOHOVUOHO\nHOHUWHOHOHOUWOHO\nHOHWUHOHOHOWUOHO\nHOHUXHOHOHOUXOHO\nHOHXUHOHOHOXUOHO\nHOHUYHOHOHOUYOHO\nHOHYUHOHOHOYUOHO\nHOHUZHOHOHOUZOHO\nHOHZUHOHOHOZUOHO\n
HOHVVHOHOHOVVOHO\nHOHVWHOHOHOVWOHO\nHOHWVHOHOHOWVOHO\nHOHVXHOHOHOVXOHO\nHOHXVHOHOHOXVOHO\nHOHVYHOHOHOVYOHO\nHOHYVHOHOHOYVOHO\nHOHVZHOHOHOVZOHO\nHOHZVHOHOHOZVOHO\n
HOHWWHOHOHOWWOHO\nHOHWXHOHOHOWXOHO\nHOHXWHOHOHOXWOHO\nHOHWYHOHOHOWYOHO\nHOHYWHOHOHOYWOHO\nHOHWZHOHOHOWZOHO\nHOHZWHOHOHOZWOHO\n
HOHXXHOHOHOXXOHO\nHOHXYHOHOHOXYOHO\nHOHYXHOHOHOYXOHO\nHOHXZHOHOHOXZOHO\nHOHZXHOHOHOZXOHO\n
HOHYYHOHOHOYYOHO\nHOHYZHOHOHOYZOHO\nHOHZYHOHOHOZYOHO\n
HOHZZHOHOHOZZOHO\n

UC/lc
nonHnnononoHnono\nnonnHnonononHono\nnonHonononoHoono\nnonoHnononooHono\nnonHanononoHaono\nnonaHnononoaHono\nnonHbnononoHbono\nnoncHnononocHono\nnoneHnononoeHono\nnonHfnononoHfono\nnonfHnononofHono\nnonHgnononoHgono\nnongHnononogHono\nnonHinononoHiono\nnoniHnononoiHono\nnonHjnononoHjono\nnonjHnononojHono\nnonkHnononokHono\nnonHlnononoHlono\nnonlHnononolHono\nnonqHnononoqHono\nnonrHnononorHono\nnonHsnononoHsono\nnonsHnononosHono\nnonHtnononoHtono\nnontHnononotHono\nnonHunononoHuono\nnonuHnononouHono\nnonHvnononoHvono\nnonvHnononovHono\nnonHwnononoHwono\nnonwHnononowHono\nnonHxnononoHxono\nnonxHnononoxHono\nnonHynononoHyono\nnonyHnononoyHono\nnonHznononoHzono\nnonzHnononozHono\n
nonOnnononoOnono\nnonnOnonononOono\nnonOonononoOoono\nnonoOnononooOono\nnonOanononoOaono\nnonaOnononoaOono\nnonObnononoObono\nnoncOnononocOono\nnoneOnononoeOono\nnonOfnononoOfono\nnonfOnononofOono\nnonOgnononoOgono\nnongOnononogOono\nnonOinononoOiono\nnoniOnononoiOono\nnonOjnononoOjono\nnonjOnononojOono\nnonkOnononokOono\nnonOlnononoOlono\nnonlOnononolOono\nnonqOnononoqOono\nnonrOnononorOono\nnonOsnononoOsono\nnonsOnononosOono\nnonOtnononoOtono\nnontOnononotOono\nnonOunononoOuono\nnonuOnononouOono\nnonOvnononoOvono\nnonvOnononovOono\nnonOwnononoOwono\nnonwOnononowOono\nnonOxnononoOxono\nnonxOnononoxOono\nnonOynononoOyono\nnonyOnononoyOono\nnonOznononoOzono\nnonzOnononozOono\n
nonAnnononoAnono\nnonnAnonononAono\nnonAonononoAoono\nnonoAnononooAono\nnonAanononoAaono\nnonaAnononoaAono\nnonAbnononoAbono\nnoncAnononocAono\nnoneAnononoeAono\nnonAfnononoAfono\nnonfAnononofAono\nnonAgnononoAgono\nnongAnononogAono\nnonAinononoAiono\nnoniAnononoiAono\nnonAjnononoAjono\nnonjAnononojAono\nnonkAnononokAono\nnonAlnononoAlono\nnonlAnononolAono\nnonqAnononoqAono\nnonrAnononorAono\nnonAsnononoAsono\nnonsAnononosAono\nnonAtnononoAtono\nnontAnononotAono\nnonAunononoAuono\nnonuAnononouAono\nnonAvnononoAvono\nnonvAnononovAono\nnonAwnononoAwono\nnonwAnononowAono\nnonAxnononoAxono\nnonxAnononoxAono\nnonAynononoAyono\nnonyAnononoyAono\nnonAznononoAzono\nnonzAnononozAono\n
nonBnnononoBnono\nnonBonononoBoono\nnonBanononoBaono\nnonBbnononoBbono\nnonBfnononoBfono\nnonBgnononoBgono\nnonBinononoBiono\nnonBjnononoBjono\nnonBlnononoBlono\nnonBsnononoBsono\nnonBtnononoBtono\nnonBunononoBuono\nnonBvnononoBvono\nnonBwnononoBwono\nnonBxnononoBxono\nnonBynononoByono\nnonBznononoBzono\n
nonCnnononoCnono\nnonConononoCoono\nnonCanononoCaono\nnonCbnononoCbono\nnonCfnononoCfono\nnonCgnononoCgono\nnonCinononoCiono\nnonCjnononoCjono\nnonClnononoClono\nnonCsnononoCsono\nnonCtnononoCtono\nnonCunononoCuono\nnonCvnononoCvono\nnonCwnononoCwono\nnonCxnononoCxono\nnonCynononoCyono\nnonCznononoCzono\n
nonEnnononoEnono\nnonEonononoEoono\nnonEanononoEaono\nnonEbnononoEbono\nnonEfnononoEfono\nnonEgnononoEgono\nnonEinononoEiono\nnonEjnononoEjono\nnonElnononoElono\nnonEsnononoEsono\nnonEtnononoEtono\nnonEunononoEuono\nnonEvnononoEvono\nnonEwnononoEwono\nnonExnononoExono\nnonEynononoEyono\nnonEznononoEzono\n
nonFnnononoFnono\nnonFonononoFoono\nnonFanononoFaono\nnonFbnononoFbono\nnonFfnononoFfono\nnonFgnononoFgono\nnonFinononoFiono\nnonFjnononoFjono\nnonFlnononoFlono\nnonFsnononoFsono\nnonFtnononoFtono\nnonFunononoFuono\nnonFvnononoFvono\nnonFwnononoFwono\nnonFxnononoFxono\nnonFynononoFyono\nnonFznononoFzono\n
nonGnnononoGnono\nnonGonononoGoono\nnonGanononoGaono\nnonGbnononoGbono\nnonGfnononoGfono\nnonGgnononoGgono\nnonGinononoGiono\nnonGjnononoGjono\nnonGlnononoGlono\nnonGsnononoGsono\nnonGtnononoGtono\nnonGunononoGuono\nnonGvnononoGvono\nnonGwnononoGwono\nnonGxnononoGxono\nnonGynononoGyono\nnonGznononoGzono\n
nonJnnononoJnono\nnonnJnonononJono\nnonJonononoJoono\nnonoJnononooJono\nnonJanononoJaono\nnonaJnononoaJono\nnonJbnononoJbono\nnoncJnononocJono\nnoneJnononoeJono\nnonJfnononoJfono\nnonfJnononofJono\nnonJgnononoJgono\nnongJnononogJono\nnonJinononoJiono\nnoniJnononoiJono\nnonJjnononoJjono\nnonjJnononojJono\nnonkJnononokJono\nnonJlnononoJlono\nnonlJnononolJono\nnonqJnononoqJono\nnonrJnononorJono\nnonJsnononoJsono\nnonsJnononosJono\nnonJtnononoJtono\nnontJnononotJono\nnonJunononoJuono\nnonuJnononouJono\nnonJvnononoJvono\nnonvJnononovJono\nnonJwnononoJwono\nnonwJnononowJono\nnonJxnononoJxono\nnonxJnononoxJono\nnonJynononoJyono\nnonyJnononoyJono\nnonJznononoJzono\nnonzJnononozJono\n
nonKnnononoKnono\nnonKonononoKoono\nnonKanononoKaono\nnonKbnononoKbono\nnonKfnononoKfono\nnonKgnononoKgono\nnonKinononoKiono\nnonKjnononoKjono\nnonKlnononoKlono\nnonKsnononoKsono\nnonKtnononoKtono\nnonKunononoKuono\nnonKvnononoKvono\nnonKwnononoKwono\nnonKxnononoKxono\nnonKynononoKyono\nnonKznononoKzono\n
nonLnnononoLnono\nnonLonononoLoono\nnonLanononoLaono\nnonLbnononoLbono\nnonLfnononoLfono\nnonLgnononoLgono\nnonLinononoLiono\nnonLjnononoLjono\nnonLlnononoLlono\nnonLsnononoLsono\nnonLtnononoLtono\nnonLunononoLuono\nnonLvnononoLvono\nnonLwnononoLwono\nnonLxnononoLxono\nnonLynononoLyono\nnonLznononoLzono\n
nonMnnononoMnono\nnonnMnonononMono\nnonMonononoMoono\nnonoMnononooMono\nnonManononoMaono\nnonaMnononoaMono\nnonMbnononoMbono\nnoncMnononocMono\nnoneMnononoeMono\nnonMfnononoMfono\nnonfMnononofMono\nnonMgnononoMgono\nnongMnononogMono\nnonMinononoMiono\nnoniMnononoiMono\nnonMjnononoMjono\nnonjMnononojMono\nnonkMnononokMono\nnonMlnononoMlono\nnonlMnononolMono\nnonqMnononoqMono\nnonrMnononorMono\nnonMsnononoMsono\nnonsMnononosMono\nnonMtnononoMtono\nnontMnononotMono\nnonMunononoMuono\nnonuMnononouMono\nnonMvnononoMvono\nnonvMnononovMono\nnonMwnononoMwono\nnonwMnononowMono\nnonMxnononoMxono\nnonxMnononoxMono\nnonMynononoMyono\nnonyMnononoyMono\nnonMznononoMzono\nnonzMnononozMono\n
nonNnnononoNnono\nnonnNnonononNono\nnonNonononoNoono\nnonoNnononooNono\nnonNanononoNaono\nnonaNnononoaNono\nnonNbnononoNbono\nnoncNnononocNono\nnoneNnononoeNono\nnonNfnononoNfono\nnonfNnononofNono\nnonNgnononoNgono\nnongNnononogNono\nnonNinononoNiono\nnoniNnononoiNono\nnonNjnononoNjono\nnonjNnononojNono\nnonkNnononokNono\nnonNlnononoNlono\nnonlNnononolNono\nnonqNnononoqNono\nnonrNnononorNono\nnonNsnononoNsono\nnonsNnononosNono\nnonNtnononoNtono\nnontNnononotNono\nnonNunononoNuono\nnonuNnononouNono\nnonNvnononoNvono\nnonvNnononovNono\nnonNwnononoNwono\nnonwNnononowNono\nnonNxnononoNxono\nnonxNnononoxNono\nnonNynononoNyono\nnonyNnononoyNono\nnonNznononoNzono\nnonzNnononozNono\n
nonPnnononoPnono\nnonPonononoPoono\nnonPanononoPaono\nnonPbnononoPbono\nnonPfnononoPfono\nnonPgnononoPgono\nnonPinononoPiono\nnonPjnononoPjono\nnonPlnononoPlono\nnonPsnononoPsono\nnonPtnononoPtono\nnonPunononoPuono\nnonPvnononoPvono\nnonPwnononoPwono\nnonPxnononoPxono\nnonPynononoPyono\nnonPznononoPzono\n
nonRnnononoRnono\nnonRonononoRoono\nnonRanononoRaono\nnonRbnononoRbono\nnonRfnononoRfono\nnonRgnononoRgono\nnonRinononoRiono\nnonRjnononoRjono\nnonRlnononoRlono\nnonRsnononoRsono\nnonRtnononoRtono\nnonRunononoRuono\nnonRvnononoRvono\nnonRwnononoRwono\nnonRxnononoRxono\nnonRynononoRyono\nnonRznononoRzono\n
nonSnnononoSnono\nnonnSnonononSono\nnonSonononoSoono\nnonoSnononooSono\nnonSanononoSaono\nnonaSnononoaSono\nnonSbnononoSbono\nnoncSnononocSono\nnoneSnononoeSono\nnonSfnononoSfono\nnonfSnononofSono\nnonSgnononoSgono\nnongSnononogSono\nnonSinononoSiono\nnoniSnononoiSono\nnonSjnononoSjono\nnonjSnononojSono\nnonkSnononokSono\nnonSlnononoSlono\nnonlSnononolSono\nnonqSnononoqSono\nnonrSnononorSono\nnonSsnononoSsono\nnonsSnononosSono\nnonStnononoStono\nnontSnononotSono\nnonSunononoSuono\nnonuSnononouSono\nnonSvnononoSvono\nnonvSnononovSono\nnonSwnononoSwono\nnonwSnononowSono\nnonSxnononoSxono\nnonxSnononoxSono\nnonSynononoSyono\nnonySnononoySono\nnonSznononoSzono\nnonzSnononozSono\n
nonTnnononoTnono\nnonnTnonononTono\nnonTonononoToono\nnonoTnononooTono\nnonTanononoTaono\nnonaTnononoaTono\nnonTbnononoTbono\nnoncTnononocTono\nnoneTnononoeTono\nnonTfnononoTfono\nnonfTnononofTono\nnonTgnononoTgono\nnongTnononogTono\nnonTinononoTiono\nnoniTnononoiTono\nnonTjnononoTjono\nnonjTnononojTono\nnonkTnononokTono\nnonTlnononoTlono\nnonlTnononolTono\nnonqTnononoqTono\nnonrTnononorTono\nnonTsnononoTsono\nnonsTnononosTono\nnonTtnononoTtono\nnontTnononotTono\nnonTunononoTuono\nnonuTnononouTono\nnonTvnononoTvono\nnonvTnononovTono\nnonTwnononoTwono\nnonwTnononowTono\nnonTxnononoTxono\nnonxTnononoxTono\nnonTynononoTyono\nnonyTnononoyTono\nnonTznononoTzono\nnonzTnononozTono\n
nonUnnononoUnono\nnonnUnonononUono\nnonUonononoUoono\nnonoUnononooUono\nnonUanononoUaono\nnonaUnononoaUono\nnonUbnononoUbono\nnoncUnononocUono\nnoneUnononoeUono\nnonUfnononoUfono\nnonfUnononofUono\nnonUgnononoUgono\nnongUnononogUono\nnonUinononoUiono\nnoniUnononoiUono\nnonUjnononoUjono\nnonjUnononojUono\nnonkUnononokUono\nnonUlnononoUlono\nnonlUnononolUono\nnonqUnononoqUono\nnonrUnononorUono\nnonUsnononoUsono\nnonsUnononosUono\nnonUtnononoUtono\nnontUnononotUono\nnonUunononoUuono\nnonuUnononouUono\nnonUvnononoUvono\nnonvUnononovUono\nnonUwnononoUwono\nnonwUnononowUono\nnonUxnononoUxono\nnonxUnononoxUono\nnonUynononoUyono\nnonyUnononoyUono\nnonUznononoUzono\nnonzUnononozUono\n
nonVnnononoVnono\nnonnVnonononVono\nnonVonononoVoono\nnonoVnononooVono\nnonVanononoVaono\nnonaVnononoaVono\nnonVbnononoVbono\nnoncVnononocVono\nnoneVnononoeVono\nnonVfnononoVfono\nnonfVnononofVono\nnonVgnononoVgono\nnongVnononogVono\nnonVinononoViono\nnoniVnononoiVono\nnonVjnononoVjono\nnonjVnononojVono\nnonkVnononokVono\nnonVlnononoVlono\nnonlVnononolVono\nnonqVnononoqVono\nnonrVnononorVono\nnonVsnononoVsono\nnonsVnononosVono\nnonVtnononoVtono\nnontVnononotVono\nnonVunononoVuono\nnonuVnononouVono\nnonVvnononoVvono\nnonvVnononovVono\nnonVwnononoVwono\nnonwVnononowVono\nnonVxnononoVxono\nnonxVnononoxVono\nnonVynononoVyono\nnonyVnononoyVono\nnonVznononoVzono\nnonzVnononozVono\n
nonWnnononoWnono\nnonnWnonononWono\nnonWonononoWoono\nnonoWnononooWono\nnonWanononoWaono\nnonaWnononoaWono\nnonWbnononoWbono\nnoncWnononocWono\nnoneWnononoeWono\nnonWfnononoWfono\nnonfWnononofWono\nnonWgnononoWgono\nnongWnononogWono\nnonWinononoWiono\nnoniWnononoiWono\nnonWjnononoWjono\nnonjWnononojWono\nnonkWnononokWono\nnonWlnononoWlono\nnonlWnononolWono\nnonqWnononoqWono\nnonrWnononorWono\nnonWsnononoWsono\nnonsWnononosWono\nnonWtnononoWtono\nnontWnononotWono\nnonWunononoWuono\nnonuWnononouWono\nnonWvnononoWvono\nnonvWnononovWono\nnonWwnononoWwono\nnonwWnononowWono\nnonWxnononoWxono\nnonxWnononoxWono\nnonWynononoWyono\nnonyWnononoyWono\nnonWznononoWzono\nnonzWnononozWono\n
nonXnnononoXnono\nnonnXnonononXono\nnonXonononoXoono\nnonoXnononooXono\nnonXanononoXaono\nnonaXnononoaXono\nnonXbnononoXbono\nnoncXnononocXono\nnoneXnononoeXono\nnonXfnononoXfono\nnonfXnononofXono\nnonXgnononoXgono\nnongXnononogXono\nnonXinononoXiono\nnoniXnononoiXono\nnonXjnononoXjono\nnonjXnononojXono\nnonkXnononokXono\nnonXlnononoXlono\nnonlXnononolXono\nnonqXnononoqXono\nnonrXnononorXono\nnonXsnononoXsono\nnonsXnononosXono\nnonXtnononoXtono\nnontXnononotXono\nnonXunononoXuono\nnonuXnononouXono\nnonXvnononoXvono\nnonvXnononovXono\nnonXwnononoXwono\nnonwXnononowXono\nnonXxnononoXxono\nnonxXnononoxXono\nnonXynononoXyono\nnonyXnononoyXono\nnonXznononoXzono\nnonzXnononozXono\n
nonYnnononoYnono\nnonnYnonononYono\nnonYonononoYoono\nnonoYnononooYono\nnonYanononoYaono\nnonaYnononoaYono\nnonYbnononoYbono\nnoncYnononocYono\nnoneYnononoeYono\nnonYfnononoYfono\nnonfYnononofYono\nnonYgnononoYgono\nnongYnononogYono\nnonYinononoYiono\nnoniYnononoiYono\nnonYjnononoYjono\nnonjYnononojYono\nnonkYnononokYono\nnonYlnononoYlono\nnonlYnononolYono\nnonqYnononoqYono\nnonrYnononorYono\nnonYsnononoYsono\nnonsYnononosYono\nnonYtnononoYtono\nnontYnononotYono\nnonYunononoYuono\nnonuYnononouYono\nnonYvnononoYvono\nnonvYnononovYono\nnonYwnononoYwono\nnonwYnononowYono\nnonYxnononoYxono\nnonxYnononoxYono\nnonYynononoYyono\nnonyYnononoyYono\nnonYznononoYzono\nnonzYnononozYono\n
nonZnnononoZnono\nnonnZnonononZono\nnonZonononoZoono\nnonoZnononooZono\nnonZanononoZaono\nnonaZnononoaZono\nnonZbnononoZbono\nnoncZnononocZono\nnoneZnononoeZono\nnonZfnononoZfono\nnonfZnononofZono\nnonZgnononoZgono\nnongZnononogZono\nnonZinononoZiono\nnoniZnononoiZono\nnonZjnononoZjono\nnonjZnononojZono\nnonkZnononokZono\nnonZlnononoZlono\nnonlZnononolZono\nnonqZnononoqZono\nnonrZnononorZono\nnonZsnononoZsono\nnonsZnononosZono\nnonZtnononoZtono\nnontZnononotZono\nnonZunononoZuono\nnonuZnononouZono\nnonZvnononoZvono\nnonvZnononovZono\nnonZwnononoZwono\nnonwZnononowZono\nnonZxnononoZxono\nnonxZnononoxZono\nnonZynononoZyono\nnonyZnononoyZono\nnonZznononoZzono\nnonzZnononozZono\n
"""

fontSize = 16

width = 842
height = 1190
margin = 20

newDrawing()
content = FormattedString()
content.font("AvenirNext-Heavy")
content.fontSize(fontSize)
x, y, w, h = margin, margin, width - margin * 2, height - margin * 2

for line in text.splitlines():
    content.append(f"{line}\n")

while len(content) > 0:
    newPage(width, height)

    colSize = w / 3
    for c in range(3):
        content = textBox(content, (x + (colSize * c), y, colSize, h), align="left")

saveImage("~/Desktop/test.pdf")
endDrawing()

joachimvu avatar Nov 08 '20 17:11 joachimvu

With Avenir (the latest script) I can't reproduce it (the kerning on page 4 looks ok to me).

Which version of Python macOS are you using?

justvanrossum avatar Nov 08 '20 18:11 justvanrossum

I'm on Catalina 10.15.6 (19G73) and using Python 3.6.12 (I manage my python versions with Pyenv) from a virtual environment, but tried with 3.8.4 with the same results.

joachimvu avatar Nov 08 '20 19:11 joachimvu

I tested with a python3 version installed from python.org and I don't have the issue either (tested with and without a virtual env). So it has something to do with python versions installed with Pyenv?

joachimvu avatar Nov 09 '20 11:11 joachimvu

So it has something to do with python versions installed with Pyenv?

Check whether perhaps you used a 32-bit version of Python before?

Did you use the latest PyObjC in all cases?

justvanrossum avatar Nov 09 '20 11:11 justvanrossum

I'm using 64-bit versions of Python and started from fresh environments every time, so I get whatever version of PyObjC pip installs when running pip install git+https://github.com/typemytype/drawbot. That would be 6.2.2!

joachimvu avatar Nov 09 '20 12:11 joachimvu

I cannot reproduce this kerning issue. Not with your example nor with single line of text

from drawBot import *

fontName = "Avenir-Black"

sampleText = "ATAV"

newDrawing()
newPage(1000, 1000)
font(fontName, 200)
print(fontFilePath())
text(sampleText, (100, 100))

t = FormattedString()
t.font(fontName, 200)
t.append(sampleText)

print(t.fontFilePath())

text(t, (100, 400))

import AppKit
# check if we are inside or outside 
appName = AppKit.NSBundle.mainBundle().objectForInfoDictionaryKey_("CFBundleDisplayName")
print(appName)
if appName == "DrawBot":
    fileName = "kerningIndrawbot.png"
else:
    fileName = "kerningAsAModule.png"

saveImage(fileName)
endDrawing()

typemytype avatar Nov 09 '20 12:11 typemytype

@typemytype, yes the issue is unlikely to arise with such a short string. Even with the small chunk from my first post I don't have the issue, which is why it took a while to spot that there was something going on because I didn't use very long input texts while developing.

I tried uninstalling and reinstalling Pyenv and python versions I used with it, still get the same results. It shows in execution time too:

  • the script run with Pyenv python takes 1m for a given input, has missing kerning in output.
  • the same script run from the same version of python but installed from python.org takes 7m to process, has correct output.

joachimvu avatar Nov 14 '20 12:11 joachimvu

I don't know what pyenv really does, but it seems the running time has more to do with how you set up your environment then with the kerning test script.

Please show the follow sys fields in both versions, perhaps we can find a difference:

import sys
print(sys.version)
print(sys.maxunicode)
print(sys.executable)

justvanrossum avatar Nov 14 '20 14:11 justvanrossum

Hi @justvanrossum, Here's my output for both python versions I'm using in this test.

>>> import sys
>>> print(sys.version)
3.7.9 (v3.7.9:13c94747c7, Aug 15 2020, 01:31:08)
[Clang 6.0 (clang-600.0.57)]
>>> print(sys.maxunicode)
1114111
>>> print(sys.executable)
/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

>>> import sys
>>> print(sys.version)
3.7.9 (default, Nov 14 2020, 13:13:35)
[Clang 12.0.0 (clang-1200.0.32.2)]
>>> print(sys.maxunicode)
1114111
>>> print(sys.executable)
/Users/joachimvu/.pyenv/versions/3.7.9/bin/python

joachimvu avatar Nov 15 '20 13:11 joachimvu

Ok, so that didn't help finding anything :(

Do you know where pyenv gets its Python from? Could it be homebrew or Anaconda?

Can you show the output of ls -l /Users/joachimvu/.pyenv/versions/3.7.9/bin/ ? That may give a clue.

On the one hand, I'd like to help you, on the other, we may have to say "Please use Python from python.org, as we can't guarantee the results of other builds."

It may be a bug in macOS, that only gets triggered in certain environments.

Probably unrelated, but since I don't have any other ideas at the moment: we have the issue that the Python versions that GitHub Actions provide are not suitable to build an application bundle, because it's not a framework build, which makes it incompatible with py2app, that builds the app. So can we run our tests CI with the Python provided by GH Actions, but we need to download the python.org Python to build the app. So I wonder if what you're seeing could also be related to this kind of build difference.

Can you say a bit more why you're using pyenv? I use venv virtual environments together with Python from python.org. Switching may be a bit less convenient, but I feel I have full control over which Python I'm using. I don't understand how pyenv dictates the Python build.

justvanrossum avatar Nov 15 '20 14:11 justvanrossum

Here's the content of my bin folder:

lrwxr-xr-x  1 joachimvu  staff        8 14 nov 13:14 2to3 -> 2to3-3.7
-rwxr-xr-x  1 joachimvu  staff      129 14 nov 13:14 2to3-3.7
lrwxr-xr-x  1 joachimvu  staff       16 14 nov 13:14 easy_install -> easy_install-3.7
-rwxr-xr-x  1 joachimvu  staff      266 14 nov 13:14 easy_install-3.7
lrwxr-xr-x  1 joachimvu  staff        7 14 nov 13:14 idle -> idle3.7
lrwxr-xr-x  1 joachimvu  staff        7 14 nov 13:14 idle3 -> idle3.7
-rwxr-xr-x  1 joachimvu  staff      127 14 nov 13:14 idle3.7
lrwxr-xr-x  1 joachimvu  staff        6 14 nov 13:14 pip -> pip3.7
-rwxr-xr-x  1 joachimvu  staff      257 14 nov 13:14 pip3
-rwxr-xr-x  1 joachimvu  staff      257 14 nov 13:14 pip3.7
lrwxr-xr-x  1 joachimvu  staff        8 14 nov 13:14 pydoc -> pydoc3.7
lrwxr-xr-x  1 joachimvu  staff        8 14 nov 13:14 pydoc3 -> pydoc3.7
-rwxr-xr-x  1 joachimvu  staff      112 14 nov 13:14 pydoc3.7
lrwxr-xr-x  1 joachimvu  staff        9 14 nov 13:14 python -> python3.7
lrwxr-xr-x  1 joachimvu  staff       16 14 nov 13:14 python-config -> python3.7-config
lrwxr-xr-x  1 joachimvu  staff        9 14 nov 13:14 python3 -> python3.7
lrwxr-xr-x  1 joachimvu  staff       16 14 nov 13:14 python3-config -> python3.7-config
-rwxr-xr-x  2 joachimvu  staff  3292600 14 nov 13:14 python3.7
lrwxr-xr-x  1 joachimvu  staff       17 14 nov 13:14 python3.7-config -> python3.7m-config
-rwxr-xr-x  1 joachimvu  staff    65409 14 nov 13:14 python3.7-gdb.py
-rwxr-xr-x  2 joachimvu  staff  3292600 14 nov 13:14 python3.7m
-rwxr-xr-x  1 joachimvu  staff     1963 14 nov 13:14 python3.7m-config
lrwxr-xr-x  1 joachimvu  staff       10 14 nov 13:14 pyvenv -> pyvenv-3.7
-rwxr-xr-x  1 joachimvu  staff      469 14 nov 13:14 pyvenv-3.7

I believe Pyenv get its Python versions from Homebrew.

I mostly use Pyenv out of convenience. It makes it easy to manage and install various Python versions from a single command pyenv install X.X.X and to choose an interpreter at will either globally or locally. I can then tie a version, or a virtual env to a project (with the pyenv-virtualenv plugin) to activate it when I cd into it.

Although I'd prefer to manage my python versions from a unique tool, its admittedly not the end of the world if I have to use a separate python install for my DrawBot stuff. Now I'm mostly curious to find out what would cause such a weird bug :)

joachimvu avatar Nov 16 '20 17:11 joachimvu

Hi all, I just encountered this issue today, also while working on a script to generate kerning proofs. Kerning just seemed to be getting disabled when my string got above a certain length, but only when running the script from the command line and not the app. After playing around a bit I circled in on a limit of 10240, which suspiciously seems to be some sort of hard limit enforced by something. I haven't been able to figure out what is causing this, but maybe you have some ideas?

Below: PDF generated from the command line (left side not enforcing a string length limit, right side enforcing a string length limit of 10240 image

Below: PDF generated from the DrawBot app (left side not enforcing a string length limit, right side enforcing a string length limit of 10240 image

Here's the code I used to generate the tests.

from drawBot import *

newDrawing()
size(1000, 1000)
txt = "HLTHATAHAYAH".ljust(100000, "H")
fontSize(48)
font("Helvetica")
overflow = textBox(txt, (20, 20, 460, 960))
overflow = textBox(txt[0:10240], (520, 20, 460, 960))
endDrawing()
saveImage("bug-test.pdf")

robertjanes avatar Feb 21 '24 20:02 robertjanes