Is Fontlab's Paste Special > Left / Right Kerning reliable?
Ramiro Espinoza
Posts: 839
Hi there,
Does anyone know if the command Paste Special > Left / Right Kerning in Fontlab is reliable?
Thanks in advance.
Does anyone know if the command Paste Special > Left / Right Kerning in Fontlab is reliable?
Thanks in advance.
Tagged:
0
Comments
-
Not always ;-)0
-
IIRC FontLab 5 does not paste kerning reliably. I think someone—John Hudson and Karsten Luecke?—wrote scripts to copy/paste kerning correctly. There were great Typophile threads about this…0
-
I didn't know that feature would be used! Ramiro what is the situation, maybe there would be another solution?0
-
I need to export / import only some blocks of a kerning table. That's it. Too complicated to explain why.0
-
I think the main issue is when you copy a selection of glyphs and an early glyph has a pair with a glyph that is later in the selection. When the first glyph is pasted, if a second glyph is not yet present as a key in the font, the second glyph/value is not assigned to the first. Something like that.
There are probably better ways around this using a Python script and RoboFab f.kerning objects.
Depending upon the scope and structure of the kerning to be transferred, I’ve also gone at this before via AFMs with some intermediate GREP work before appending/replacing.
0 -
I need to export / import only some blocks of a kerning table.
I wouldn't try to use the paste kerning option for that. What you want is a script that allows export of kerning for selected glyphs to a text file; the corresponding import script should have options to add to or replace existing kerning for the same glyphs in the target font source. I have scripts like this, but they're not mine to share. I suggest contacting Karsten.
0 -
Perhaps this would do - I have reworked one of my scripts, so it could suit your needs. It works by either glyph names or glyph references that form a kerning pair. You could use a dictionary or multiple lists, and it will copy kerning information from one pair to another for all MMM layers.
#FLM: Copy Kerning Pair to Pair v.1.0 # Vassil Kateliev (2016) # - Dependancies ---------------- from FL import * # - Functions ---------------- def copyKerningPair2Pair(leftSRC, rightSRC, leftDST, rightDST): # - Source Glyph if isinstance(leftSRC, basestring) and isinstance(rightSRC, basestring): leftSRC = fl.font[fl.font.FindGlyph(leftSRC)] rightSRC = fl.font[fl.font.FindGlyph(rightSRC)] #fl.font.FindGlyph(rightSRC) # - Destination Glyph if isinstance(leftDST, basestring) and isinstance(rightDST, basestring): leftDST = fl.font[fl.font.FindGlyph(leftDST)] rightDST = fl.font[fl.font.FindGlyph(rightDST)] #fl.font.FindGlyph(rightDST) if len(leftSRC.kerning): keySRC = [kpair for kpair in range(len(leftSRC.kerning)) if leftSRC.kerning[kpair].key == rightSRC.index] if keySRC: if len(leftDST.kerning): keyDST = [kpair for kpair in range(len(leftDST.kerning)) if leftDST.kerning[kpair].key == rightDST.index] if keyDST: for layer in range(leftDST.layers_number): leftDST.kerning[keyDST[0]].values[layer] = leftSRC.kerning[keySRC[0]].values[layer] print 'DONE:\tCopied kerning data from %s to %s.' %(leftSRC.name + ':' + rightSRC.name, leftDST.name + ':' + rightDST.name) else: newKernPair = KerningPair(leftSRC.kerning[keySRC[0]]) leftDST.kerning.append(newKernPair) print 'WARN:\tDestination pair %s not found! Created NEW!' %(leftDST.name + ':' + rightDST.name) else: print 'ERROR:\tSource pair %s not found!' %(leftSRC.name + ':' + rightSRC.name) else: print 'ERROR:\tSource pair %s not found!' %(leftSRC.name + ':' + rightSRC.name) # - Run --- # Example using Dictinary: copyKerning = {('a','b'):('c','d')} for key,value in copyKerning.iteritems(): copyKerningPair2Pair(key[0],key[1],value[0],value[1]) fl.UpdateFont()
0 -
Thanks a lot but I need something that works differently (and I don't work with MMs). I need something that point to specific pairs like in this piece of code:
left = ['exclamdown', 'questiondown', 'quotesingle', 'quoteleft','quoteright','quotesinglbase','hyphen', 'period', 'parenleft', 'bracketleft', 'braceleft', 'slash'] middle= ['A', 'AE', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Thorn', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] right = ['exclam', 'question', 'quotesingle', 'quoteleft', 'quoteright','hyphen', 'period', 'colon','parenright', 'bracketright', 'braceright', 'slash'] for A in left: for B in middle: print A,B for A in middle: for B in right: print A,B
Then the kerning values should be stored in a dictionary (I think) and written in a text file. Other script should be use to import these values in the receiving font. I think I can write it but at the moment I am too busy and my coding skills are more than modest and takes me quite a lot of time.0 -
So just to be clear, and I hope, that I understand you correctly: (1) You wish to copy kerning info from [left]:[middle] to [middle]:[right], or (2) you wish to store information for [left]:middle] and [middle]:[right] to a file and import it to another typeface... i presume you need the second option?0
-
No, iterations between 'left' and 'middle' and 'middle' and 'right' is my system to distinguish left and right kerning. Basically I want to copy / store the kerning values of the pairs generated by:
for A in left: for B in middle: print A,B for A in middle: for B in right: print A,B
...and then to be able to import these values to the same pairs of another font. It shouldn't be difficult.0 -
This should do the job (probably..., needs more testing). Uses pickle and dictionary.
#FLM: Export Kerning Block v.1.0 # Vassil Kateliev (2016) # - Dependancies ---------------- from FL import * import itertools, pickle # - Functions ---------------- def getKerningValue(fontSRC, leftSRC, rightSRC): # - Source Glyph leftSRC = fontSRC[fontSRC.FindGlyph(leftSRC)] rightSRC = fontSRC[fontSRC.FindGlyph(rightSRC)] if len(leftSRC.kerning): keySRC = [kpair for kpair in range(len(leftSRC.kerning)) if leftSRC.kerning[kpair].key == rightSRC.index] if len(keySRC): return int(leftSRC.kerning[keySRC[0]].value) else: return None else: return None def putKerningValue(fontDST, leftDST, rightDST, value): # - Source Glyph leftDST = fontDST[fontDST.FindGlyph(leftDST)] rightDST = fontDST[fontDST.FindGlyph(rightDST)] if len(leftDST.kerning): keyDST = [kpair for kpair in range(len(leftDST.kerning)) if leftDST.kerning[kpair].key == rightDST.index] if len(keyDST): leftDST.kerning[keyDST[0]].value = value print 'DONE:\tCopied kerning data to %s.' %(leftDST.name + ':' + leftDST.name) else: # TODO: Create new kern pair and assign value! Not implemented, beacuse of iconsistent results! print 'ERR:\tDestination Kerning pair %s not found!' %(leftDST.name + ':' + leftDST.name) else: # TODO: Create new kern pair and assign value! Not implemented, beacuse of iconsistent results! print 'ERR:\tDestination Kerning pair %s not found!' %(leftDST.name + ':' + leftDST.name) # - Run --- # -- Init fontSRC = fl.font # Source font = CurrentFont! Change to desired font! fontDST = fl.font # Destination font = CurrentFont! Change to desired font! fileName = str(fl.font.file_name.replace('.vfb', '')) + '-KerningBlock.p' # Database file left = ['exclamdown', 'questiondown', 'quotesingle', 'quoteleft','quoteright','quotesinglbase','hyphen', 'period', 'parenleft', 'bracketleft', 'braceleft', 'slash'] middle= ['A', 'AE', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Thorn', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] right = ['exclam', 'question', 'quotesingle', 'quoteleft', 'quoteright','hyphen', 'period', 'colon','parenright', 'bracketright', 'braceright', 'slash'] # -- Build left2middle = {pair : getKerningValue(fontSRC, pair[0],pair[1]) for pair in itertools.product(left, middle) if getKerningValue(fontSRC, pair[0],pair[1]) != None} middle2right = {pair : getKerningValue(fontSRC, pair[0],pair[1]) for pair in itertools.product(middle, right) if getKerningValue(fontSRC, pair[0],pair[1]) != None} # -- Export exportKerning = left2middle.copy() exportKerning.update(middle2right) pickle.dump(exportKerning, open(fileName, "wb")) # -- Import importKerning = pickle.load(open(fileName, "rb")) print importKerning for key,value in importKerning.iteritems(): putKerningValue(fontDST, key[0],key[1],value) fl.UpdateFont()
0 -
Thanks a lot! I will try to test it during the weekend.0
-
One more remark: The script is now not MMM capable and will not create new pairs, just update the existing ones. I have left place for this "future functionality", but in my experience, so far I had little (and inconsistent) success making Fontlab create new pairs and assigning values to them - most of the time it ends in a mess with duplicate pairs and etc. Perhaps Adam can clarify us the process of adding new pairs (and hopefully in MMM space)0
-
I need something able to create new pairs in the receiving fonts if necessary.
What about creating the same pairs first by assigning them any value (for example: kerning[A,B]=1) and then importing the values stored from the inputing font?
Why don't you use Robofab's objects?0 -
OK, I figured out a (very basic) way to write a txt with my targeted kerning stored.
Now I have to see how I import this information into another font.import sys sys.dont_write_bytecode = True from robofab.world import CurrentFont font = CurrentFont() kerning = font.kerning target = [] left = ['exclamdown', 'questiondown', 'quotesingle', 'quoteleft','quoteright','quotesinglbase','hyphen', 'period', 'parenleft', 'bracketleft', 'braceleft', 'slash'] middle= ['A', 'AE', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Thorn', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] right = ['exclam', 'question', 'quotesingle', 'quoteleft', 'quoteright','hyphen', 'period', 'colon','parenright', 'bracketright', 'braceright', 'slash'] for x in left: for y in middle: target.append( x+' ' + y +' '+ str(kerning[x,y]) ) for x in middle: for y in right: target.append( x+' ' + y +' '+ str(kerning[x,y]) ) import os.path path = os.path.join( os.path.split(fl.font.file_name)[0] , "Kerning.txt") f = open(path, 'w') f.write("\r".join(target)) f.close()
0 -
Ramiro Espinoza said:I need something able to create new pairs in the receiving fonts if necessary.
What about creating the same pairs first by assigning them any value (for example: kerning[A,B]=1) and then importing the values stored from the inputing font?
Why don't you use Robofab's objects?
I have revisited my work and the following code will create new pairs, if necessary - it was more simple than I imagined
Note, that this is in Python 2.7 syntax, so it needs one of the last version(s) of Fontlab (5.2). For Python 2.4 the dictionary comprehension must be converted to nested loops the way you do it.
Why do you need the kerning information saved in .txt file? Do you mean to edit it between import/export sessions? Otherwise i will suggest using pickle.dump() - it is reliable, faster and easier to use.#FLM: Export Kerning Block v.1.1 # Vassil Kateliev (2016) # - Dependancies ---------------- from FL import * import itertools, pickle # - Functions ---------------- def getKerningValue(fontSRC, leftSRC, rightSRC): # - Source Glyph leftSRC = fontSRC[fontSRC.FindGlyph(leftSRC)] rightSRC = fontSRC[fontSRC.FindGlyph(rightSRC)] if len(leftSRC.kerning): keySRC = [kpair for kpair in range(len(leftSRC.kerning)) if leftSRC.kerning[kpair].key == rightSRC.index] if len(keySRC): return int(leftSRC.kerning[keySRC[0]].value) else: return None else: return None def putKerningValue(fontDST, leftDST, rightDST, value): # - Source Glyph leftDST = fontDST[fontDST.FindGlyph(leftDST)] rightDST = fontDST[fontDST.FindGlyph(rightDST)] if len(leftDST.kerning): keyDST = [kpair for kpair in range(len(leftDST.kerning)) if leftDST.kerning[kpair].key == rightDST.index] if len(keyDST): leftDST.kerning[keyDST[0]].value = value print 'DONE:\tCopied kerning data to %s.' %(leftDST.name + ':' + leftDST.name) else: newKernPair = KerningPair(rightDST.index, value) leftDST.kerning.append(newKernPair) print 'WARN:\tDestination Kerning pair %s not found! Created NEW!' %(leftDST.name + ':' + leftDST.name) else: newKernPair = KerningPair(rightDST.index, value) leftDST.kerning.append(newKernPair) print 'WARN:\tDestination Kerning pair %s not found! Created NEW!' %(leftDST.name + ':' + leftDST.name) # - Run --- # -- Init fontSRC = fl.font # Source font = CurrentFont! Change to desired font! fontDST = fl.font # Destination font = CurrentFont! Change to desired font! fileName = str(fl.font.file_name.replace('.vfb', '')) + '-KerningBlock.p' # Database file left = ['exclamdown', 'questiondown', 'quotesingle', 'quoteleft','quoteright','quotesinglbase','hyphen', 'period', 'parenleft', 'bracketleft', 'braceleft', 'slash'] middle= ['A', 'AE', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Thorn', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] right = ['exclam', 'question', 'quotesingle', 'quoteleft', 'quoteright','hyphen', 'period', 'colon','parenright', 'bracketright', 'braceright', 'slash'] # -- Build left2middle = {pair : getKerningValue(fontSRC, pair[0],pair[1]) for pair in itertools.product(left, middle) if getKerningValue(fontSRC, pair[0],pair[1]) != None} middle2right = {pair : getKerningValue(fontSRC, pair[0],pair[1]) for pair in itertools.product(middle, right) if getKerningValue(fontSRC, pair[0],pair[1]) != None} # -- Export exportKerning = left2middle.copy() exportKerning.update(middle2right) pickle.dump(exportKerning, open(fileName, "wb")) # -- Import importKerning = pickle.load(open(fileName, "rb")) print importKerning for key,value in importKerning.iteritems(): putKerningValue(fontDST, key[0],key[1],value) fl.UpdateFont()
0
Categories
- All Categories
- 43 Introductions
- 3.7K Typeface Design
- 801 Font Technology
- 1K Technique and Theory
- 618 Type Business
- 444 Type Design Critiques
- 542 Type Design Software
- 30 Punchcutting
- 136 Lettering and Calligraphy
- 83 Technique and Theory
- 53 Lettering Critiques
- 483 Typography
- 301 History of Typography
- 114 Education
- 68 Resources
- 498 Announcements
- 79 Events
- 105 Job Postings
- 148 Type Releases
- 165 Miscellaneous News
- 269 About TypeDrawers
- 53 TypeDrawers Announcements
- 116 Suggestions and Bug Reports