summaryrefslogtreecommitdiff
path: root/fonts/gentium-tug/source/type1/kerncorrection.py
diff options
context:
space:
mode:
Diffstat (limited to 'fonts/gentium-tug/source/type1/kerncorrection.py')
-rwxr-xr-xfonts/gentium-tug/source/type1/kerncorrection.py493
1 files changed, 365 insertions, 128 deletions
diff --git a/fonts/gentium-tug/source/type1/kerncorrection.py b/fonts/gentium-tug/source/type1/kerncorrection.py
index 323a065fa2..f264cd5b5c 100755
--- a/fonts/gentium-tug/source/type1/kerncorrection.py
+++ b/fonts/gentium-tug/source/type1/kerncorrection.py
@@ -1,32 +1,99 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
# This file is part of the Gentium package for TeX.
# It is licensed under the Expat License, see doc//README for details.
# Used uni0162 for Tcedilla and uni021A for Tcommaaccent
+
+# ERROR (non-critical)
+# --------------------
+# Found where the duplicate kerning pairs are written.
+# Example of such duplicate kerning pair is 'A cacute.sc'
+# It is generated is initialcap() for the first time and in
+# accentedinitialcapsmallcap() for the second time.
+#
+# FIXED
+#
+# The previous error was fixed, althought in a dirty way. Instead of
+# writing directly to a file, the lines with extra kerning are added
+# to 'Counter' object from 'collections'. This automatically eliminates
+# duplicates, but keep track of them (they have count of 2).
+#
+# It was tested that just the duplicates are removed and nothing is lost.
+# When the duplicates were removed from the file generated by the old
+# script, the result is exactly the same as the file generated by this new
+# version of the script.
+#
+# This file will be cleaned up later (or completely rewritten). I know
+# this script is very dirty and it might be easier to rewrite it completely.
+
+
+# TODO: use variable for the small caps extension '.sc'
+
+# TODO: refactor the script; maybe remove classes
+
+
+# TODO: Decide if should be used purely class-based kerning.
+
+# TODO: It might be good idea to split this script into two scripts (Latin and
+# Cyrillic). It would be better to do different kerning for roman and
+# italic styles (at least for the small Cyrillic letters; especially
+# de, el, ge). It would be even better to do manual kerning, but it would take
+# much time. But I could do support for files with manual kerning. These
+# files would be used if they were present. This would be similar to the
+# files that are used for manual kerning for letters dcaron and lcaron.
+# There shoud be probably three such files for each font (Latin, Greek,
+# Cyrillic).
+
+# The script currently combines class-based kerning and deriving kerning from list
+# of kerns. Changing it to completely class-based kerning would create more kerning
+# pairs than now. The current (mixed) sollution makes it possible to make exceptions
+# to class-based kerning.
+
+# TODO: It might be good idea to find out which kerning pairs can really occur for
+# e.g. encoding T1. Pure class-based kernig would give too many kerning pairs.
+# This is probably no problem for TeX, but it means too many kerning pairs
+# that would never be needed (and it would be more work to look at the changes
+# from the original fonts). The solution would be to look for languages that
+# are supported by T1 and take only those pairs where both the letter are in
+# the same language. Even this would be a superset of what is really possible.
+# For example Czech has letters dcaron and ecaron, but the pair
+# dcaron + ecaron can never occur.
+#
+# These pairs might be useful also for other fonts for TeX.
+
+
import os, sys, re
+import collections
+
+SMALL_CAPS_CORRECTION = 0.94 # width of small caps / width of capital letters; tested for
+ # letters A, L, T, V, W and Y, all had nearly the same ratio
+
+input_file_name = sys.argv[1]
+output_file_name = sys.argv[2]
+
class KernReader:
def __init__(self, filename):
- self.filename = filename
+ with open(filename, "r") as afm_file:
+ self.kern_lines = [line for line in afm_file if line.startswith('KPX ')]
+
def getkerns(self, regex):
- a = []
- f = open(self.filename, "r")
- while True:
- s = f.readline()
- if s == "": break # end of file
- if re.match(regex, s):
- a.append(s)
- f.close()
- return a
+ """ return lines with kerning, format of *.afm
+
+ TODO: Check that there is only one matching line.
+ """
+ return [line for line in self.kern_lines if re.match(regex, line)]
class KernWriter:
# TODO: improve methods for quotes; probably merge them; also accented small caps; look
# also at other types of quotes, such as Polish and French; start with improving
- # aacute.SC + quotedblleft and adieresis.SC + quotedblleft
+ # aacute.sc + quotedblleft and adieresis.sc + quotedblleft
# TODO: several methods could be merged (simpler code, but worse result to report to Victor)
- kernpairscapital = [
+ kern_pairs_capital = [
+ # BE CAREFULL: It is used also for small caps and may cause problems
+ # when moving to class kerning
["V A", "V Aacute", "V Abreve", "V Acircumflex", "V Adieresis", "V AE", "V Agrave", "V Amacron", "V Aogonek", "V Aring", "V Atilde"],
["A Y", "A Yacute", "A Ydieresis", "Aacute Y", "Abreve Y", "Acircumflex Y", "Adieresis Y", "Agrave Y", "Amacron Y", "Aogonek Y", "Aring Y", "Atilde Y", "Aacute Yacute"],
["L V", "Lcommaaccent V", "Lslash V"],
@@ -70,54 +137,34 @@ class KernWriter:
# problematic kern follows (the kern value of DV was positive in GentiumPlus Regular)
["D V", "Dcaron V", "Dcroat V"]
]
- kernpairsinitialcap = [
- ["V a", "V aacute", "V abreve", "V acircumflex", "V adieresis", "V ae", "V agrave", "V amacron", "V aogonek", "V aring", "V atilde"],
- ["V e", "V eacute", "V ecaron", "V ecircumflex", "V edieresis", "V edotaccent", "V egrave", "V emacron", "V eogonek"],
- ["V o", "V oacute", "V ocircumflex", "V odieresis", "V oe", "V ograve", "V ohungarumlaut", "V omacron", "V oslash", "V otilde"],
+
+ kern_pairs_initial_cap = [
["Y a", "Y aacute", "Y abreve", "Y acircumflex", "Y adieresis", "Y ae", "Y agrave", "Y amacron", "Y aogonek", "Y aring", "Y atilde", "Yacute a", "Ydieresis a", "Yacute aacute"],
["Y e", "Y eacute", "Y ecaron", "Y ecircumflex", "Y edieresis", "Y edotaccent", "Y egrave", "Y emacron", "Y eogonek", "Yacute e", "Ydieresis e", "Yacute eacute", "Yacute ecaron"],
["Y o", "Y oacute", "Y ocircumflex", "Y odieresis", "Y oe", "Y ograve", "Y ohungarumlaut", "Y omacron", "Y oslash", "Y otilde", "Yacute o", "Ydieresis o", "Yacute oacute"],
# not used the combination "Y u" that is only in GentiumPlus regular
- ["A v", "Aacute v", "Abreve v", "Acircumflex v", "Adieresis v", "Agrave v", "Amacron v", "Aogonek v", "Aring v", "Atilde v"],
- ["A w", "Aacute w", "Abreve w", "Acircumflex w", "Adieresis w", "Agrave w", "Amacron w", "Aogonek w", "Aring w", "Atilde w"],
["A y", "A yacute", "A ydieresis", "Aacute y", "Abreve y", "Acircumflex y", "Adieresis y", "Agrave y", "Amacron y", "Aogonek y", "Aring y", "Atilde y", "Aacute yacute"],
- ["F a", "F aacute", "F abreve", "F acircumflex", "F adieresis", "F ae", "F agrave", "F amacron", "F aogonek", "F aring", "F atilde"],
- ["F e", "F eacute", "F ecaron", "F ecircumflex", "F edieresis", "F edotaccent", "F egrave", "F emacron", "F eogonek"],
- ["F o", "F oacute", "F ocircumflex", "F odieresis", "F oe", "F ograve", "F ohungarumlaut", "F omacron", "F oslash", "F otilde"],
["T a", "T aacute", "T abreve", "T acircumflex", "T adieresis", "T ae", "T agrave", "T amacron", "T aogonek", "T aring", "T atilde", "Tcaron a", "uni0162 a", "uni021A a", "Tcaron aacute"],
["T e", "T eacute", "T ecaron", "T ecircumflex", "T edieresis", "T edotaccent", "T egrave", "T emacron", "T eogonek", "Tcaron e", "uni0162 e", "uni021A e"],
["T o", "T oacute", "T ocircumflex", "T odieresis", "T oe", "T ograve", "T ohungarumlaut", "T omacron", "T oslash", "T otilde", "Tcaron o", "uni0162 o", "uni021A o", "Tcaron oacute"],
- ["W a", "W aacute", "W abreve", "W acircumflex", "W adieresis", "W ae", "W agrave", "W amacron", "W aogonek", "W aring", "W atilde"],
- ["W e", "W eacute", "W ecaron", "W ecircumflex", "W edieresis", "W edotaccent", "W egrave", "W emacron", "W eogonek"],
- ["W o", "W oacute", "W ocircumflex", "W odieresis", "W oe", "W ograve", "W ohungarumlaut", "W omacron", "W oslash", "W otilde"]
]
- kernpairssmall = [
- ["v e", "v eacute", "v ecaron", "v ecircumflex", "v edieresis", "v edotaccent", "v egrave", "v emacron", "v eogonek"],
+
+ kern_pairs_small = [
["k e", "k eacute", "k ecaron", "k ecircumflex", "k edieresis", "k edotaccent", "k egrave", "k emacron", "k eogonek", "kcommaaccent e"],
- ["o v", "oacute v", "ocircumflex v", "odieresis v", "ograve v", "oslash v", "otilde v"],
- ["o x", "oacute x", "ocircumflex x", "odieresis x", "ograve x", "oslash x", "otilde x"],
- ["v a", "v aacute", "v abreve", "v acircumflex", "v adieresis", "v ae", "v agrave", "v amacron", "v aogonek", "v aring", "v atilde"],
- ["v o", "v oacute", "v ocircumflex", "v odieresis", "v oe", "v ograve", "v ohungarumlaut", "v omacron", "v oslash", "v otilde"],
["r a", "r aacute", "r abreve", "r acircumflex", "r adieresis", "r ae", "r agrave", "r amacron", "r aogonek", "r aring", "r atilde", "racute a", "rcaron a", "rcommaaccent a", "rcaron aacute"],
["r e", "r eacute", "r ecaron", "r edieresis", "r edotaccent", "r egrave", "r emacron", "r eogonek", "racute e", "rcaron e", "rcommaaccent e", "rcaron eacute"],
["r c", "r cacute", "r ccaron", "r ccedilla", "r cdotaccent", "racute c", "rcaron c", "rcommaaccent c", "rcaron ccaron"],
- ["r q", "racute q", "rcaron q", "rcommaaccent q"],
["y e", "y eacute", "y ecaron", "y ecircumflex", "y edieresis", "y edotaccent", "y egrave", "y emacron", "y eogonek", "yacute e", "ydieresis e", "yacute eacute"],
["y o", "y oacute", "y ocircumflex", "y odieresis", "y oe", "y ograve", "y ohungarumlaut", "y omacron", "y oslash", "y otilde", "yacute o", "ydieresis o", "yacute oacute"],
- ["a v", "aacute v", "abreve v", "acircumflex v", "adieresis v", "agrave v", "amacron v", "aogonek v", "aring v", "atilde v"],
- ["a w", "aacute w", "abreve w", "acircumflex w", "adieresis w", "agrave w", "amacron w", "aogonek w", "aring w", "atilde w"],
- ["c h", "cacute h", "ccaron h", "ccedilla h", "cdotaccent h"],
- ["c k", "cacute k", "ccaron k", "ccedilla k", "cdotaccent k"],
- ["e x", "eacute x", "ecaron x", "ecircumflex x", "edieresis x", "edotaccent x", "egrave x", "emacron x", "eogonek x"],
- ["o w", "oacute w", "ocircumflex w", "odieresis w", "ograve w", "oslash w", "otilde w"],
["r o", "r oacute", "r ocircumflex", "r odieresis", "r oe", "r ograve", "r ohungarumlaut", "r omacron", "r oslash", "r otilde", "racute o", "rcaron o", "rcommaaccent o", "rcaron oacute"],
- ["x e", "x eacute", "x ecaron", "x ecircumflex", "x edieresis", "x edotaccent", "x egrave", "x emacron", "x eogonek"],
["y a", "y aacute", "y abreve", "y acircumflex", "y adieresis", "y ae", "y agrave", "y amacron", "y aogonek", "y aring", "y atilde", "yacute a", "ydieresis a", "yacute aacute"],
["r d", "r dcaron", "r dcroat", "racute d", "rcaron d", "rcommaaccent d", "rcaron dcaron"]
]
- kernpairsquotes = [
+
+ kern_pairs_quotes = [
+ # TODO pairs that have collisions can be removed in "make_derived_latin_kerns" create list for it!
# this is far from complete
- # TODO: use this list also for accented small caps (using kernfactor)
+ # TODO: use this list also for accented small caps (using SMALL_CAPS_CORRECTION)
["A quotedblright", "A quotedblleft", "Aacute quotedblleft", "Adieresis quotedblleft"],
["L quotedblright", "L quotedblleft"], # Lcaron and Lacute left out (collision)
["A quoteright", "A quoteleft", "Aacute quoteleft", "Adieresis quoteleft"],
@@ -127,75 +174,221 @@ class KernWriter:
["A quotedblright", "quotedblbase V", "quotedblbase W", "quotedblbase Y", "quotedblbase Yacute", "quotedblbase T", "quotedblbase Tcaron"],
["A quoteright", "quotesinglbase V", "quotesinglbase W", "quotesinglbase Y", "quotesinglbase Yacute", "quotesinglbase T", "quotesinglbase Tcaron"]
]
- rightpunctuationsmall = [
- ["r comma", "racute comma", "rcaron comma", "rcommaaccent comma"],
- ["y comma", "yacute comma", "ydieresis comma"],
- ["r period", "racute period", "rcaron period", "rcommaaccent period"],
- ["y period", "yacute period", "ydieresis period"]
+
+ # TODO: It is possible to create several kerning classes for one letter. For example 'A' can be used
+ # for letter A with all possible accents and 'A_unaccented' can be used for just the letter 'A',
+ # 'A_subset' can be used for just some accented variants of 'A'. The base kern is now removed,
+ # therefore there shouldn't be problems with non-existing letters like 'A_unaccented' (but check
+ # that it is true).
+ #
+ # This would enable to move more kerns to kerning classes.
+ #
+ # Deriving all kerns from e.g. 'a e' would give too many kerns. It might help to check
+ # which combinations can really exist in some language, but it would require some research
+ # and a lot of work.
+ latin_class_kerns = [
+ # sort lines before commit!
+ "A v",
+ "A w",
+ "F a",
+ "F e",
+ "F o",
+ "V a",
+ "V e",
+ "V o",
+ "W a",
+ "W e",
+ "W o",
+ "a v",
+ "a w",
+ "c h",
+ "c k",
+ "e x",
+ "o v",
+ "o w",
+ "o x",
+ "r comma",
+ "r period",
+ "r q",
+ "v a",
+ "v e",
+ "v o",
+ "x e",
+ "y comma",
+ "y period",
# nothing to be derived from "f quoteright" and "f quotedblright"
]
+
+ # similar Latin letters that come first in the kerning pair
+ latin_left_classes = {
+ # sort lines before commit!
+ "A": ["A", "Aacute", "Abreve", "Acircumflex", "Adieresis", "Agrave", "Amacron", "Aogonek", "Aring", "Atilde"],
+ "F": ["F"],
+ "V": ["V"],
+ "W": ["W"],
+ "a": ["a", "aacute", "abreve", "acircumflex", "adieresis", "agrave", "amacron", "aogonek", "aring", "atilde"],
+ "c": ["c", "cacute", "ccaron", "ccedilla", "cdotaccent"],
+ "e": ["e", "eacute", "ecaron", "ecircumflex", "edieresis", "edotaccent", "egrave", "emacron", "eogonek"],
+ "o": ["o", "oacute", "ocircumflex", "odieresis", "ograve", "oslash", "otilde"],
+ "r": ["r", "racute", "rcaron", "rcommaaccent"],
+ "v": ["v"],
+ "x": ["x"],
+ "y": ["y", "yacute", "ydieresis"],
+ }
+
+ # similar Latin letters that come second in the kerning pair
+ latin_right_classes = {
+ # sort lines before commit!
+ "a": ["a", "aacute", "abreve", "acircumflex", "adieresis", "ae", "agrave", "amacron", "aogonek", "aring", "atilde"],
+ "comma": ["comma"],
+ "e": ["e", "eacute", "ecaron", "ecircumflex", "edieresis", "edotaccent", "egrave", "emacron", "eogonek"],
+ "h": ["h"],
+ "k": ["k"],
+ "o": ["o", "oacute", "ocircumflex", "odieresis", "oe", "ograve", "ohungarumlaut", "omacron", "oslash", "otilde"],
+ "period": ["period"],
+ "q": ["q"],
+ "v": ["v"],
+ "w": ["w"],
+ "x": ["x"],
+ }
+
+
+ # first pair has Latin letters, the second pair has Cyrillic letters; probably not very obvious
+ # there is no kern for 'X O' in the fonts
+ kern_pairs_cyrillic = [
+ # sort lines before commit!
+ ["A C", "А С"],
+ ["A O", "А О"],
+ ["A T", "А Т"],
+ ["A V", "А Ч"], # make it better
+ ["A Y", "А Ү"],
+ ["A y", "А у"],
+ ["C A", "С А"],
+ ["O A", "О А"],
+ ["O X", "О Х"],
+ ["O Y", "О Ү"],
+ ["P A", "Р А"],
+ ["T A", "Г А"],
+ ["T A", "Г Д"], # make it better
+ ["T A", "Г Л"], # make it better
+ ["T A", "Т А"],
+ ["T A", "Т Д"], # make it better
+ ["T A", "Т Л"], # make it better
+ ["T a", "Г а"],
+ ["T a", "Т а"],
+ ["T e", "Г е"],
+ ["T e", "Т е"],
+ ["T o", "Г о"],
+ ["T o", "Т о"],
+ ["Y A", "У А"], # make it better
+ ["Y A", "Ү А"],
+ ["Y O", "Ү О"],
+ ["Y a", "Ү а"],
+ ["Y e", "Ү е"],
+ ["Y o", "У Д"], # make it better
+ ["Y o", "У Л"], # make it better
+ ["Y o", "Ү о"],
+ ["e x", "е х"],
+ ["o x", "о х"],
+ ["x e", "х е"],
+ ["x o", "х о"],
+ ["y o", "у д"], # make it better
+ ["y o", "у л"], # make it better
+ ]
+
+ # similar Cyrillic letters that come first in the kerning pair
+ cyrillic_left_classes = {
+ # sort lines before commit!
+ "А": ["А"],
+ "Г": ["Г", "Ӷ"],
+ "О": ["О"],
+ "Р": ["Р", "Ҏ"],
+ "С": ["С", "Ҫ"],
+ "Т": ["Т", "Ҭ"],
+ "У" : ["У"],
+ "е": ["е", "ё"],
+ "о": ["о"],
+ "у" : ["у"],
+ "х": ["х", "ҳ", "ӽ"],
+ "Ү": ["Ү"], # not Russian
+ }
+
+ # similar Cyrillic letters that come second in the kerning pair
+ cyrillic_right_classes = {
+ # sort lines before commit!
+ "А": ["А"],
+ "Д" : ["Д"],
+ "Л" : ["Л", "Љ", "Ӆ", "Ԓ"],
+ "О": ["О"],
+ "С": ["С", "Ҫ"],
+ "Т": ["Т", "Ҭ"],
+ "Х": ["Х", "Ҳ", "Ӽ"],
+ "Ч" : ["Ч", "Ҷ", "Ҹ", "Ӌ"],
+ "а": ["а", "ӕ"],
+ "д" : ["д"],
+ "е": ["е", "ё"],
+ "л" : ["л", "љ", "ӆ", "ԓ"],
+ "о": ["о"],
+ "у": ["у", "ў"],
+ "х": ["х", "ҳ", "ӽ"],
+ "Ү": ["Ү"], # not Russian
+ }
+
def __init__(self, filename):
- self.f = open(filename, "a") # append
- def writetofile(self, s):
- # This method writes one extra kerning pair to the output file.
+ self.filename = filename # the name of the file with extra kerning pairs
+ self.kern_lines = collections.Counter() # contains lines with extra kerning pairs
+
+ def add_to_kern_lines(self, s):
+ # This method adds one extra kerning pair to kern_lines.
# It also makes correction for small cap Tcommaaccent and Tcedilla.
- # Tcedilla is uni0162 and the small cap is uni0163.SC, not
- # uni0162.SC. Tcommaaccent is uni021A and the small cap is uni021B.SC,
- # not uni021a.SC (look also at the small "a"; there is problem not only
+ # Tcedilla is uni0162 and the small cap is uni0163.sc, not
+ # uni0162.sc. Tcommaaccent is uni021A and the small cap is uni021B.sc,
+ # not uni021a.sc (look also at the small "a"; there is problem not only
# in the unicode value, but also in the case, because method lower() is
# used).
- self.f.write(s.replace("uni021a.SC", "uni021B.SC").replace("uni0162.SC", "uni0163.SC"))
- def smallcaps(self, fromreader, kernfactor):
+ extra_line = s.replace("uni021a.sc", "uni021B.sc").replace("uni0162.sc", "uni0163.sc")
+ self.kern_lines.update([extra_line]) # must use '[]', otherwise iterates over letters
+
+ def write_kern_lines_to_file(self):
+ with open(self.filename, "a") as extra_kern_file: # append to file!
+ for line in self.kern_lines:
+ extra_kern_file.write(line)
+
+
+ def small_caps(self, fromreader):
a = fromreader.getkerns("KPX [A-Z] [A-Z]")
for s in a:
parts = s.split()
- self.writetofile("KPX " + parts[1].lower() + ".SC " + parts[2].lower() +
- ".SC " + str(int(round(kernfactor * float(parts[3])))) +
+ # Write two small caps
+ self.add_to_kern_lines("KPX " + parts[1].lower() + ".sc " + parts[2].lower() +
+ ".sc " + str(int(round(SMALL_CAPS_CORRECTION * float(parts[3])))) +
'\n')
- def initialcap(self, fromreader, kernfactor):
- a = fromreader.getkerns("KPX [A-Z] [A-Z]")
- for s in a:
- parts = s.split()
- self.writetofile("KPX " + parts[1] + " " + parts[2].lower() + ".SC " +
- str(int(round(kernfactor * float(parts[3])))) + '\n')
- def rightpunctuation(self, fromreader, kernfactor):
+ # Write capital letter + small cap
+ self.add_to_kern_lines("KPX " + parts[1] + " " + parts[2].lower() + ".sc " +
+ str(int(round(SMALL_CAPS_CORRECTION * float(parts[3])))) + '\n')
+
+ def right_punctuation(self, fromreader):
# small cap and punctuation
- a = fromreader.getkerns("KPX [A-Z] period")
+ a = fromreader.getkerns("KPX [A-Z] period")
a.extend(fromreader.getkerns("KPX [A-Z] comma"))
a.extend(fromreader.getkerns("KPX [A-Z] quotedblright"))
a.extend(fromreader.getkerns("KPX [A-Z] quoteright"))
for s in a:
parts = s.split()
- self.writetofile("KPX " + parts[1].lower() + ".SC " + parts[2] + " " +
- str(int(round(kernfactor * float(parts[3])))) + '\n')
- def leftpunctuation(self, fromreader, kernfactor):
+ self.add_to_kern_lines("KPX " + parts[1].lower() + ".sc " + parts[2] + " " +
+ str(int(round(SMALL_CAPS_CORRECTION * float(parts[3])))) + '\n')
+
+ def left_punctuation(self, fromreader):
# punctuation and small cap
- a = fromreader.getkerns("KPX quotedblleft [A-Z]")
+ a = fromreader.getkerns("KPX quotedblleft [A-Z]")
a.extend(fromreader.getkerns("KPX quoteleft [A-Z]"))
for s in a:
parts = s.split()
- self.writetofile("KPX " + parts[1] + " " + parts[2].lower() + ".SC " +
- str(int(round(kernfactor * float(parts[3])))) + '\n')
- def accentedcapitalletters(self, fromreader):
- for x in self.kernpairscapital:
- basekern = x[0]
- derivedkerns = x[1:]
- a = fromreader.getkerns("KPX " + basekern + " ")
- kernline = a[0]
- for b in derivedkerns:
- newkernline = kernline.replace(basekern, b)
- self.writetofile(newkernline)
- def accentedsmallletters(self, fromreader):
- for x in self.kernpairssmall:
- basekern = x[0]
- derivedkerns = x[1:]
- a = fromreader.getkerns("KPX " + basekern + " ")
- kernline = a[0]
- for b in derivedkerns:
- newkernline = kernline.replace(basekern, b)
- self.writetofile(newkernline)
- def accentedsmallcaps(self, fromreader, kernfactor):
- for x in self.kernpairscapital:
+ self.add_to_kern_lines("KPX " + parts[1] + " " + parts[2].lower() + ".sc " +
+ str(int(round(SMALL_CAPS_CORRECTION * float(parts[3])))) + '\n')
+
+ def accented_capital_letters(self, fromreader):
+ for x in self.kern_pairs_capital:
basekern = x[0]
derivedkerns = x[1:]
a = fromreader.getkerns("KPX " + basekern + " ")
@@ -203,72 +396,116 @@ class KernWriter:
for b in derivedkerns:
newkernline = kernline.replace(basekern, b)
parts = newkernline.split()
- self.writetofile("KPX " + parts[1].lower() + ".SC " + parts[2].lower() +
- ".SC " + str(int(round(kernfactor * float(parts[3])))) +
+ # Write two capital letters
+ self.add_to_kern_lines(newkernline)
+ # Write two small caps
+ self.add_to_kern_lines("KPX " + parts[1].lower() + ".sc " + parts[2].lower() +
+ ".sc " + str(int(round(SMALL_CAPS_CORRECTION * float(parts[3])))) +
'\n')
- def accentedinitialcap(self, fromreader):
- for x in self.kernpairsinitialcap:
+ # Write capital letter + small cap
+ self.add_to_kern_lines("KPX " + parts[1] + " " + parts[2].lower() + ".sc " +
+ str(int(round(SMALL_CAPS_CORRECTION * float(parts[3])))) + '\n')
+
+ def accented_small_letters(self, fromreader):
+ for x in self.kern_pairs_small:
basekern = x[0]
derivedkerns = x[1:]
a = fromreader.getkerns("KPX " + basekern + " ")
kernline = a[0]
for b in derivedkerns:
newkernline = kernline.replace(basekern, b)
- self.writetofile(newkernline)
- def accentedinitialcapsmallcap(self, fromreader, kernfactor):
- for x in self.kernpairscapital:
+ self.add_to_kern_lines(newkernline)
+
+ def accented_initial_cap(self, fromreader):
+ for x in self.kern_pairs_initial_cap:
basekern = x[0]
derivedkerns = x[1:]
a = fromreader.getkerns("KPX " + basekern + " ")
kernline = a[0]
for b in derivedkerns:
newkernline = kernline.replace(basekern, b)
- parts = newkernline.split()
- self.writetofile("KPX " + parts[1] + " " + parts[2].lower() + ".SC " +
- str(int(round(kernfactor * float(parts[3])))) + '\n')
- def accentedrightpunctuation(self, fromreader):
- for x in self.rightpunctuationsmall:
- basekern = x[0]
- derivedkerns = x[1:]
+ self.add_to_kern_lines(newkernline)
+
+ def make_derived_latin_kerns(self, latin_kern):
+ left_base_letter, right_base_letter = latin_kern.split()
+
+ derived_kerns = [ left + " " + right
+ for left in self.latin_left_classes[left_base_letter]
+ for right in self.latin_right_classes[right_base_letter] ]
+
+ return derived_kerns[1:] # remove the base kern that is already in the font
+
+ def make_latin_class_kerns(self, fromreader):
+ for basekern in self.latin_class_kerns:
+ derivedkerns = self.make_derived_latin_kerns(basekern)
a = fromreader.getkerns("KPX " + basekern + " ")
kernline = a[0]
+
for b in derivedkerns:
newkernline = kernline.replace(basekern, b)
- self.writetofile(newkernline)
- def accentedleftpunctuation(self, fromreader):
+ self.add_to_kern_lines(newkernline)
+
+ def accented_left_punctuation(self, fromreader):
# nothing to be done
pass
- def czechquotes(self, fromreader):
- for x in self.kernpairsquotes:
+
+ def czech_quotes(self, fromreader):
+ for x in self.kern_pairs_quotes:
basekern = x[0]
derivedkerns = x[1:]
a = fromreader.getkerns("KPX " + basekern + " ")
kernline = a[0]
for b in derivedkerns:
newkernline = kernline.replace(basekern, b)
- self.writetofile(newkernline)
- def close(self):
- self.f.close()
+ self.add_to_kern_lines(newkernline)
+
+ def char_to_uni(self, c):
+ """ Convert character to 'uniXXXX' string """
+ return "uni{0:04X}".format(ord(c))
+
+ # TODO: Test the kern_pairs_cyrillic array. First pair must be Latin letters,
+ # all the remaining pairs must be Cyrillic letters.
+
+ def make_derived_cyrillic_kerns(self, cyrillic_kern):
+ """ make kerns from the base cyrillic kern and kern classes """
+ left_base_letter = cyrillic_kern[0]
+ right_base_letter = cyrillic_kern[-1]
+ return [ left + " " + right
+ for left in self.cyrillic_left_classes[left_base_letter]
+ for right in self.cyrillic_right_classes[right_base_letter] ]
-kernfactor = 0.94 # width of small caps / width of capital letters; tested for
- # letters A, L, T, V, W and Y, all had nearly the same ratio
+ def cyrillic_kerns(self, fromreader):
+ for x in self.kern_pairs_cyrillic:
+ basekern = x[0]
+ derivedkerns = self.make_derived_cyrillic_kerns(x[1])
+ base_kern_line = fromreader.getkerns("KPX " + basekern + " ")
+
+ # skip the Cyrillic kerns if the corresponding Latin kern is not found
+ if not base_kern_line:
+ continue
+
+ kernline = base_kern_line[0]
+ for b in derivedkerns:
+ first_char, second_char = b.split()
+ new_kern = self.char_to_uni(first_char) + ' ' + self.char_to_uni(second_char)
+ newkernline = kernline.replace(basekern, new_kern)
+ self.add_to_kern_lines(newkernline)
-fin = KernReader(sys.argv[1])
+fin = KernReader(input_file_name)
-fout = KernWriter(sys.argv[2])
+# output_generator is not a file ane more! Rename!
+output_generator = KernWriter(output_file_name)
# letters without accents
-fout.smallcaps(fin, kernfactor)
-fout.initialcap(fin, kernfactor)
-fout.rightpunctuation(fin, kernfactor)
-fout.leftpunctuation(fin, kernfactor)
+output_generator.small_caps(fin)
+output_generator.right_punctuation(fin)
+output_generator.left_punctuation(fin)
# letters with accents
-fout.accentedcapitalletters(fin)
-fout.accentedsmallletters(fin)
-fout.accentedsmallcaps(fin, kernfactor)
-fout.accentedinitialcap(fin)
-fout.accentedinitialcapsmallcap(fin, kernfactor)
-fout.accentedrightpunctuation(fin)
-fout.accentedleftpunctuation(fin)
-fout.czechquotes(fin)
-fout.close()
+output_generator.accented_capital_letters(fin)
+output_generator.accented_small_letters(fin)
+output_generator.accented_initial_cap(fin)
+output_generator.make_latin_class_kerns(fin)
+output_generator.accented_left_punctuation(fin)
+output_generator.czech_quotes(fin)
+output_generator.cyrillic_kerns(fin)
+output_generator.write_kern_lines_to_file()