Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,7 +10,7 @@ import tempfile
|
|
| 10 |
import os
|
| 11 |
import glob
|
| 12 |
from fontmake.font_project import FontProject
|
| 13 |
-
from defcon import Font, Glyph
|
| 14 |
from fontTools.pens.svgPathPen import SVGPathPen
|
| 15 |
from svgpathtools import parse_path, Path, Line, CubicBezier, QuadraticBezier, Arc
|
| 16 |
from svgpathtools.path import Path as SvgPath
|
|
@@ -89,9 +89,7 @@ def build_ufo_from_glyphs(glyphs):
|
|
| 89 |
font = Font()
|
| 90 |
font.info.familyName = "TipTopType"
|
| 91 |
font.info.styleName = "Regular"
|
| 92 |
-
# Définir les unités par em (standard pour les polices)
|
| 93 |
font.info.unitsPerEm = 1000
|
| 94 |
-
# Définir d'autres propriétés de la police
|
| 95 |
font.info.ascender = 800
|
| 96 |
font.info.descender = -200
|
| 97 |
font.info.capHeight = 700
|
|
@@ -105,91 +103,54 @@ def build_ufo_from_glyphs(glyphs):
|
|
| 105 |
glyph.unicode = ord(letter)
|
| 106 |
pen = glyph.getPen()
|
| 107 |
try:
|
| 108 |
-
# Analyser le chemin SVG
|
| 109 |
path = parse_path(path_data)
|
| 110 |
-
|
| 111 |
-
normalized_path = SvgPath()
|
| 112 |
for segment in path:
|
| 113 |
if segment.length() == 0:
|
| 114 |
continue
|
| 115 |
-
|
| 116 |
-
if not normalized_path or not normalized_path[-1].end == segment.start:
|
| 117 |
-
normalized_path.append(Line(start=segment.start, end=segment.start))
|
| 118 |
-
# Ajouter le segment au chemin normalisé
|
| 119 |
-
if isinstance(segment, Line):
|
| 120 |
-
normalized_path.append(Line(start=normalized_path[-1].end, end=segment.end))
|
| 121 |
-
elif isinstance(segment, CubicBezier):
|
| 122 |
-
normalized_path.append(CubicBezier(
|
| 123 |
-
start=normalized_path[-1].end,
|
| 124 |
-
control1=segment.control1,
|
| 125 |
-
control2=segment.control2,
|
| 126 |
-
end=segment.end
|
| 127 |
-
))
|
| 128 |
-
elif isinstance(segment, QuadraticBezier):
|
| 129 |
-
# Convertir la courbe quadratique en courbe cubique
|
| 130 |
-
start = normalized_path[-1].end
|
| 131 |
-
end = segment.end
|
| 132 |
-
control = segment.control
|
| 133 |
-
# Approximation simple: diviser la courbe quadratique en deux segments cubiques
|
| 134 |
-
control1 = start + (control - start) * 2/3
|
| 135 |
-
control2 = end + (control - end) * 2/3
|
| 136 |
-
normalized_path.append(CubicBezier(
|
| 137 |
-
start=start,
|
| 138 |
-
control1=control1,
|
| 139 |
-
control2=control2,
|
| 140 |
-
end=end
|
| 141 |
-
))
|
| 142 |
-
elif isinstance(segment, Arc):
|
| 143 |
-
# Convertir l'arc en une série de courbes cubiques
|
| 144 |
-
# Pour simplifier, nous allons approximer l'arc avec une ligne droite
|
| 145 |
-
normalized_path.append(Line(start=normalized_path[-1].end, end=segment.end))
|
| 146 |
-
# Dessiner le chemin normalisé dans le glyphe
|
| 147 |
if normalized_path:
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
if bounds and (bounds.width > 0) and (bounds.height > 0):
|
| 151 |
-
# Définir la largeur du glyphe (par exemple, 80% de 1000 unités)
|
| 152 |
glyph_width = 800
|
| 153 |
-
glyph_height = 1000
|
| 154 |
-
# Calculer le facteur d'échelle pour que le glyphe tienne dans la hauteur
|
| 155 |
scale_factor = glyph_height * 0.8 / bounds.height
|
| 156 |
-
# Calculer le décalage pour centrer le glyphe horizontalement
|
| 157 |
offset_x = (glyph_width - bounds.width * scale_factor) / 2
|
| 158 |
-
offset_y = -bounds.bottom * scale_factor
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
pen.
|
| 180 |
-
# Fermer le chemin si nécessaire
|
| 181 |
-
if normalized_path.isclosed():
|
| 182 |
-
pen.closePath()
|
| 183 |
-
# Définir la largeur du glyphe
|
| 184 |
glyph.width = glyph_width
|
| 185 |
print(f"Glyph {letter} created with SVG path.")
|
| 186 |
except Exception as e:
|
| 187 |
print(f"Error injecting SVG for {letter}: {e}")
|
| 188 |
-
|
| 189 |
-
pen.
|
| 190 |
-
pen.lineTo((900,
|
| 191 |
-
pen.lineTo((
|
| 192 |
-
pen.lineTo((100, 1000))
|
| 193 |
pen.closePath()
|
| 194 |
glyph.width = 1000
|
| 195 |
font.insertGlyph(glyph)
|
|
@@ -206,26 +167,20 @@ def save_otf_font(glyphs, font_name="TipTopType-Regular.otf"):
|
|
| 206 |
font = build_ufo_from_glyphs(glyphs)
|
| 207 |
font.save(ufo_path)
|
| 208 |
print(f"UFO file saved at: {ufo_path}")
|
| 209 |
-
|
| 210 |
output_dir = os.path.join(tmpdir, "out")
|
| 211 |
os.makedirs(output_dir, exist_ok=True)
|
| 212 |
-
|
| 213 |
project = FontProject()
|
| 214 |
project.run_from_ufos([ufo_path], output=["otf"], output_dir=output_dir)
|
| 215 |
print("Fontmake ran successfully.")
|
| 216 |
-
|
| 217 |
otf_files = glob.glob(os.path.join(output_dir, "**/*.otf"), recursive=True)
|
| 218 |
if not otf_files:
|
| 219 |
print("No OTF files generated by fontmake.")
|
| 220 |
return None
|
| 221 |
-
|
| 222 |
generated_path = otf_files[0]
|
| 223 |
print(f"OTF file generated at: {generated_path}")
|
| 224 |
-
|
| 225 |
final_path = os.path.join(tempfile.gettempdir(), font_name)
|
| 226 |
os.replace(generated_path, final_path)
|
| 227 |
print(f"OTF file moved to: {final_path}")
|
| 228 |
-
|
| 229 |
return final_path
|
| 230 |
except Exception as e:
|
| 231 |
print(f"Error in save_otf_font: {e}")
|
|
|
|
| 10 |
import os
|
| 11 |
import glob
|
| 12 |
from fontmake.font_project import FontProject
|
| 13 |
+
from defcon import Font, Glyph, Point
|
| 14 |
from fontTools.pens.svgPathPen import SVGPathPen
|
| 15 |
from svgpathtools import parse_path, Path, Line, CubicBezier, QuadraticBezier, Arc
|
| 16 |
from svgpathtools.path import Path as SvgPath
|
|
|
|
| 89 |
font = Font()
|
| 90 |
font.info.familyName = "TipTopType"
|
| 91 |
font.info.styleName = "Regular"
|
|
|
|
| 92 |
font.info.unitsPerEm = 1000
|
|
|
|
| 93 |
font.info.ascender = 800
|
| 94 |
font.info.descender = -200
|
| 95 |
font.info.capHeight = 700
|
|
|
|
| 103 |
glyph.unicode = ord(letter)
|
| 104 |
pen = glyph.getPen()
|
| 105 |
try:
|
|
|
|
| 106 |
path = parse_path(path_data)
|
| 107 |
+
normalized_path = []
|
|
|
|
| 108 |
for segment in path:
|
| 109 |
if segment.length() == 0:
|
| 110 |
continue
|
| 111 |
+
normalized_path.append(segment)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
if normalized_path:
|
| 113 |
+
bounds = None
|
| 114 |
+
for segment in normalized_path:
|
| 115 |
+
if bounds is None:
|
| 116 |
+
bounds = segment.bbox()
|
| 117 |
+
else:
|
| 118 |
+
bounds |= segment.bbox()
|
| 119 |
if bounds and (bounds.width > 0) and (bounds.height > 0):
|
|
|
|
| 120 |
glyph_width = 800
|
| 121 |
+
glyph_height = 1000
|
|
|
|
| 122 |
scale_factor = glyph_height * 0.8 / bounds.height
|
|
|
|
| 123 |
offset_x = (glyph_width - bounds.width * scale_factor) / 2
|
| 124 |
+
offset_y = -bounds.bottom * scale_factor
|
| 125 |
+
def transform_point(point):
|
| 126 |
+
x = point.real
|
| 127 |
+
y = point.imag
|
| 128 |
+
new_x = x * scale_factor + offset_x
|
| 129 |
+
new_y = y * scale_factor + offset_y
|
| 130 |
+
return Point((new_x, -new_y))
|
| 131 |
+
if normalized_path:
|
| 132 |
+
start_segment = normalized_path[0]
|
| 133 |
+
start_point = transform_point(start_segment.start)
|
| 134 |
+
pen.moveTo(start_point)
|
| 135 |
+
for segment in normalized_path:
|
| 136 |
+
if isinstance(segment, Line):
|
| 137 |
+
end_point = transform_point(segment.end)
|
| 138 |
+
pen.lineTo(end_point)
|
| 139 |
+
elif isinstance(segment, CubicBezier):
|
| 140 |
+
control1 = transform_point(segment.control1)
|
| 141 |
+
control2 = transform_point(segment.control2)
|
| 142 |
+
end_point = transform_point(segment.end)
|
| 143 |
+
pen.curveTo(control1, control2, end_point)
|
| 144 |
+
if normalized_path and normalized_path[-1].end == normalized_path[0].start:
|
| 145 |
+
pen.closePath()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
glyph.width = glyph_width
|
| 147 |
print(f"Glyph {letter} created with SVG path.")
|
| 148 |
except Exception as e:
|
| 149 |
print(f"Error injecting SVG for {letter}: {e}")
|
| 150 |
+
pen.moveTo(Point((100, 0)))
|
| 151 |
+
pen.lineTo(Point((900, 0)))
|
| 152 |
+
pen.lineTo(Point((900, 1000)))
|
| 153 |
+
pen.lineTo(Point((100, 1000)))
|
|
|
|
| 154 |
pen.closePath()
|
| 155 |
glyph.width = 1000
|
| 156 |
font.insertGlyph(glyph)
|
|
|
|
| 167 |
font = build_ufo_from_glyphs(glyphs)
|
| 168 |
font.save(ufo_path)
|
| 169 |
print(f"UFO file saved at: {ufo_path}")
|
|
|
|
| 170 |
output_dir = os.path.join(tmpdir, "out")
|
| 171 |
os.makedirs(output_dir, exist_ok=True)
|
|
|
|
| 172 |
project = FontProject()
|
| 173 |
project.run_from_ufos([ufo_path], output=["otf"], output_dir=output_dir)
|
| 174 |
print("Fontmake ran successfully.")
|
|
|
|
| 175 |
otf_files = glob.glob(os.path.join(output_dir, "**/*.otf"), recursive=True)
|
| 176 |
if not otf_files:
|
| 177 |
print("No OTF files generated by fontmake.")
|
| 178 |
return None
|
|
|
|
| 179 |
generated_path = otf_files[0]
|
| 180 |
print(f"OTF file generated at: {generated_path}")
|
|
|
|
| 181 |
final_path = os.path.join(tempfile.gettempdir(), font_name)
|
| 182 |
os.replace(generated_path, final_path)
|
| 183 |
print(f"OTF file moved to: {final_path}")
|
|
|
|
| 184 |
return final_path
|
| 185 |
except Exception as e:
|
| 186 |
print(f"Error in save_otf_font: {e}")
|