1import defcon 2from babelfont.font import Font 3from babelfont.layer import Layer 4from babelfont.lib import Lib 5from babelfont.glyph import Glyph 6from babelfont.point import Point 7from babelfont.features import Features 8from babelfont.contour import Contour 9from babelfont.component import Component 10from babelfont.anchor import Anchor 11from copy import copy 12 13 14def can_load(filename): 15 return filename.endswith(".ufo") 16 17def can_save(filename): 18 return filename.endswith(".ufo") 19 20 21def load(filename, **kwargs): 22 dcfont = defcon.Font(filename) 23 return _load_dcfont(dcfont) 24 25def save(font, filename): 26 dcfont = _save_dcfont(font) 27 dcfont.save(filename) 28 29# defcon -> babelfont 30 31 32def _load_dcfont(dcf): 33 bbf = Font(dcf) 34 35 # XXX Create: features 36 for k,v in dcf.info.getDataForSerialization().items(): 37 bbf.info._setAttr(k, copy(v)) 38 for k,v in dcf.lib.items(): 39 bbf.lib._setItem(k, copy(v)) 40 for dclayer in dcf.layers: 41 bblayer = _load_dclayer(dclayer) 42 bblayer.font = bbf 43 bbf._layers.append(bblayer) 44 bbf._layerOrder.append(bblayer.name) 45 for name, contents in dcf.groups.items(): 46 bbf.groups[name] = contents 47 bbf.lib.glyphOrder = list(dcf.layers[None].keys()) 48 _copy_kerning(dcf.kerning, bbf.kerning) 49 if dcf.features and dcf.features.text: 50 bbf.features.text = dcf.features.text 51 return bbf 52 53 54def _load_dclayer(dclayer): # -> Layer 55 bblayer = Layer() 56 for k,v in dclayer.lib.items(): 57 bblayer.lib._setItem(k, copy(v)) 58 if dclayer.color: 59 bblayer.color = tuple(v for v in dclayer.color) 60 bblayer.name = dclayer.name 61 for k in dclayer.keys(): 62 bblayer._glyphs[k] = _load_dcglyph(dclayer[k], bblayer) 63 return bblayer 64 65def _load_dcglyph(dcglyph, layer): 66 glyph = Glyph() 67 glyph._layer = layer 68 glyph._lib = Lib() 69 glyph._lib.glyph = glyph 70 for k,v in dcglyph.lib.items(): 71 glyph._lib._setItem(k, copy(v)) 72 glyph._name = dcglyph.name 73 glyph._unicodes = copy(dcglyph.unicodes) 74 glyph._width = dcglyph.width 75 glyph._height = dcglyph.height 76 # components, anchors, guidelines, image 77 glyph._components = [_load_dccomponent(c, glyph) for c in dcglyph.components] 78 glyph._contours = [_load_dccontour(p, glyph) for p in dcglyph] 79 glyph._anchors = [_load_dcanchor(a, glyph) for a in dcglyph.anchors] 80 return glyph 81 82 83def _load_dccontour(dccontour, glyph): 84 contour = Contour() 85 contour._glyph = glyph 86 contour._points = [_load_dcpoint(p, contour) for p in dccontour] 87 contour.clockwise = dccontour.clockwise 88 return contour 89 90 91def _load_dccomponent(dccomponent, glyph): 92 component = Component() 93 component._glyph = glyph 94 component._baseGlyph = dccomponent.baseGlyph 95 component.transformation = dccomponent.transformation 96 # XXX 97 return component 98 99 100def _load_dcanchor(dcanchor, glyph): 101 anchor = Anchor() 102 anchor._glyph = glyph 103 anchor.name = dcanchor.name 104 anchor.color = dcanchor.color 105 anchor.x = dcanchor.x 106 anchor.y = dcanchor.y 107 return anchor 108 109 110def _load_dcpoint(dcpoint, contour): 111 point = Point() 112 point._contour = contour 113 point._x = dcpoint.x 114 point._y = dcpoint.y 115 if not dcpoint.segmentType: 116 point.type = "offcurve" 117 else: 118 point.type = dcpoint.segmentType 119 point.smooth = dcpoint.smooth 120 return point 121 122def _copy_kerning(inkerning, outkerning): 123 for pair, value in inkerning.items(): 124 outkerning[pair] = value 125 126# # babelfont -> defcon 127 128 129def _save_point(point): 130 if point.type == "offcurve": 131 dctype = None 132 else: 133 dctype = point.type 134 return defcon.Point ((point.x, point.y), dctype, point.smooth) 135 136 137def _save_contour(contour): 138 path = defcon.Contour() 139 for p in contour._points: 140 path.appendPoint(_save_point(p)) 141 path.clockwise = contour.clockwise 142 return path 143 144 145def _save_component(component): 146 c = defcon.Component(None) 147 c.baseGlyph = component.baseGlyph 148 c.transformation = component.transformation 149 # XXX 150 return c 151 152def _save_anchor(anchor): 153 dcanchor = defcon.Anchor() 154 dcanchor.color = anchor.color 155 dcanchor.name = anchor.name 156 dcanchor.x = anchor.x 157 dcanchor.y = anchor.y 158 return dcanchor 159 160def _save_glyph(glyph): 161 dcglyph = defcon.Glyph() 162 dcglyph.unicodes = copy(glyph._unicodes) 163 for c in glyph.contours: 164 dccontour = _save_contour(c) 165 dcglyph.appendContour(dccontour) 166 # Anchors 167 for a in glyph.anchors: 168 dcglyph.appendAnchor(_save_anchor(a)) 169 170 for k,v in glyph.lib._dict.items(): 171 if k == "glyph": 172 continue 173 dcglyph.lib[k] = copy(v) 174 dcglyph.rightMargin = glyph.rightMargin 175 dcglyph.leftMargin = glyph.leftMargin 176 dcglyph.width = glyph.width 177 dcglyph.name = glyph.name 178 return dcglyph 179 180def _save_layer(layer, dclayer): 181 for g in layer: 182 dclayer.insertGlyph(_save_glyph(g)) 183 # Handle components after all glyphs are in 184 for glyph in layer: 185 dcglyph = dclayer[glyph.name] 186 for c in glyph.components: 187 dcglyph.appendComponent(_save_component(c)) 188 189 dclayer.color = layer.color 190 191def _save_dcfont(font): 192 dcf = defcon.Font() 193 for k,v in font.lib._dict.items(): 194 dcf.lib[k] = copy(v) 195 dcf.info.setDataFromSerialization(font.info._dict) 196 if len(font.layers) == 1: 197 # Just put it in public.default 198 _save_layer(font.defaultLayer, dcf.layers.defaultLayer) 199 else: 200 for l in dcf.layers.layerOrder: 201 del(dcf.layers[l]) 202 203 for l in font.layers: 204 newLayer = dcf.newLayer(l.name) 205 _save_layer(l, newLayer) 206 for name, contents in font.groups.items(): 207 dcf.groups[name] = contents 208 _copy_kerning(font.kerning, dcf.kerning) 209 if font.features and font.features.text: 210 dcf.features.text = font.features.text 211 return dcf 212 213# # Random stuff 214 215# def _glyphs_date_to_ufo(d): 216# return d.strftime('%Y/%m/%d %H:%M:%S') 217 218# def _ufo_date_to_glyphs(d): 219# return datetime.strptime(d, '%Y/%m/%d %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S +0000') 220