Skip to content

Instantly share code, notes, and snippets.

@juanluisrto
Last active October 19, 2023 10:39
Show Gist options
  • Save juanluisrto/21ee923abdcacb998acaf2133b23bfd5 to your computer and use it in GitHub Desktop.
Save juanluisrto/21ee923abdcacb998acaf2133b23bfd5 to your computer and use it in GitHub Desktop.
import numpy as np, pandas as pd
import freetype
from shapely.geometry import *
from shapely import affinity as aff
from cartoframes.viz import Layer
face = freetype.Face("Vera.ttf") # path to your font
face.set_char_size(3000, hres = 100)
# These parameters are ok for Vera, but should be adjusted for each font.
char_width = 1500
space_between_chars_width = int(char_width*1/3)
get_width, get_height = (lambda b : b[2] - b[0], lambda b : b[3] - b[1])
def char_to_geometry(char, acc_offset):
face.load_char(char)
outline = face.glyph.outline
X,Y = np.array(outline.points).T
X = X - X.min() + acc_offset
points = [(x,y) for x,y in zip(X,Y)]
lines = []
start = 0
for end in outline.contours: # we travel each contour and generate a LineString
points_in_line = points[start:end + 1] + [points[start]]
l = LineString(points_in_line)
lines.append(l)
start = end + 1
bbox = [X.min(), Y.min(), X.max(), Y.max()] # we compute the bounding box
return lines, bbox
def text_as_geometry(text, coords, scale_factor = 5, rotate_angle = 0):
n = len(text)
char_geometries = []
lat, lon = coords
acc_offset = 0
for char in text:
try:
m, bbox = char_to_geometry(char, acc_offset)
offset = get_width(bbox)
acc_offset += offset + space_between_chars_width
char_geometries.extend(m)
except:
acc_offset += char_width
ml = MultiLineString(char_geometries)
Bbox = ml.bounds
w = get_width(Bbox)
h = get_height(Bbox)
f = max(w,h)
ml = aff.translate(ml, -Bbox[2] + w/2, -Bbox[3] + h/2)
ml = aff.scale(ml, scale_factor/(f*100), scale_factor/(f*100), origin = (lon, lat))
ml = aff.rotate(ml, rotate_angle)
return ml
word = "What's Up!"
lat, lon = 37.771757, -99.618516
geom = text_as_geometry(word, (lat, lon), scale_factor = 650, rotate_angle = 5)
df = pd.DataFrame([ {"geom" : geom}])
Layer(df, geom_col = "geom")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment