Skip to content

Commit

Permalink
Merge pull request #366 from m4rc1e/add-designer
Browse files Browse the repository at this point in the history
gftools-add-designer
  • Loading branch information
m4rc1e authored Jun 2, 2021
2 parents 1448062 + 811ff7a commit 06171ac
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 0 deletions.
19 changes: 19 additions & 0 deletions Lib/gftools/designers.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
syntax = "proto2";
// GF Designer Profile Protos

// A designer listed on the catalog:
message DesignerInfoProto {
// Designer or typefoundry name:
optional string designer = 1;

// URL for more info on this designer:
optional string link = 2;

// Photo or logo:
optional AvatarProto avatar = 3;
}

message AvatarProto {
optional string file_name = 1;
}

123 changes: 123 additions & 0 deletions Lib/gftools/designers_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

181 changes: 181 additions & 0 deletions bin/gftools-add-designer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#!/usr/bin/env python3
"""Add or update a designer entry in the Google Fonts catalog.
Designer profiles are stored in the google/fonts repo:
https://github.com/google/fonts/tree/main/catalog/designers
This script is intended to help onboarders quickly create individual designer
profiles.
Designer Profiles are visible to the public. They are included in the the about
section for each family e.g:
https://fonts.google.com/specimen/Roboto#about
In 2021, Rosalie Wagner created an online form for us to collect designer
information from the general public. The form populates the following spreadsheet,
https://docs.google.com/spreadsheets/d/1G1rkk_jJnuV7lVWkfCbqwTkSjbbWJcC1a2Xfoh-nRWM/edit#gid=1905114301
There is also an image directory where the designer's profile pics are uploaded into.
In order to use the spreadsheet command in this script, you will need to
download the folder which contains the spreadsheet and designer images.
You can then use the ``--spreadsheet`` arg.
Usage:
# Add or update a designer entry. User will need to hand complete the bio.html.
$ gftools add-designer path/to/local/clone/fonts/catalog/designers "Theo Salvadore" --img_path path/to/img.png
# Add or update a designer entry using the spreadsheet.
$ gftools add-designer path/to/local/clone/fonts/catalog/designers "Theo Salvador" --img_path path/to/img.png --spreadsheet ./GFDesigners.xlsx
"""
import argparse
from glob import glob
import os
from PIL import Image
from gftools.designers_pb2 import DesignerInfoProto
from google.protobuf import text_format
from pandas.core.base import PandasObject


def process_image(fp):
if not os.path.isfile(fp):
raise ValueError(f"{fp} is not a file")
img = Image.open(fp)
width, height = img.size
if width != height:
print("warning: img is rectangular when it should be square")
if width < 300 or height < 300:
print("warning: img is smaller than 300x300px")
return img

print("resizing image")
img.thumbnail((300, 300))
return img


def gen_info(designer, img_path=None, link=""):
# Write info.pb
info = DesignerInfoProto()
info.designer = designer
info.link = ""
if img_path:
info.avatar.file_name = img_path

text_proto = text_format.MessageToString(info, as_utf8=True, use_index_order=True)
return text_proto


def parse_urls(string):
urls = string.split()
res = []
for url in urls:
if not url.startswith("http"):
url = "https://" + url
res.append(url)
return res


def gen_hrefs(urls):
res = {}
for url in urls:
if "twitter" in url:
res[url] = "Twitter"
elif "facebook" in url:
res[url] = "Facebook"
elif "instagram" in url:
res[url] = "Instagram"
else:
# https://www.mysite.com --> mysite.com
res[url] = url.split("//")[1]
return " | ".join(f"<a href={k}>{v}</a>" for k,v in res.items())


def make_designer(
designer_directory,
name,
img_path=None,
bio=None,
urls=None,
):
designer_dir_name = name.lower().replace(" ", "").replace("-", "")
designer_dir = os.path.join(designer_directory, designer_dir_name)
if not os.path.isdir(designer_dir):
print(f"{name} isn't in catalog. Creating new dir {designer_dir}")
os.mkdir(designer_dir)

existing_imgs = glob(os.path.join(designer_dir, "*[.png|.jpg|.jpeg]"))
if not img_path and existing_imgs:
img_path = existing_imgs[0]
img_dst = os.path.join(designer_dir, f"{designer_dir_name}.png")

if img_path and img_path in existing_imgs:
print("Skipping image processing")
elif img_path:
print(f"processing image {img_path}")
# remove any existing images
if existing_imgs:
[os.remove(i) for i in existing_imgs]
image = process_image(img_path)
image.save(img_dst)

print(f"Generating info.pb file")
info_pb = gen_info(name, os.path.basename(img_dst) if os.path.isfile(img_dst) else None)
filename = os.path.join(designer_dir, "info.pb")
with open(filename, "w") as f:
f.write(info_pb)

# write/update bio.html
bio_file = os.path.join(designer_dir, "bio.html")
html_text = None
if bio:
print("Generating bio.html")
html_text = f"<p>{bio}</p>"
if urls:
hrefs = gen_hrefs(urls)
html_text += "\n" + f"<p>{hrefs}</p>"
elif os.path.isfile(bio_file):
print("Skipping. No bio text supplied but bio.html already exists")
else:
print(f"Please manually update the bio.html file")
html_text = "N/A"
if html_text:
with open(bio_file, "w") as f:
f.write(html_text)
print(f"Finished profile {designer_dir}")


def main():
parser = argparse.ArgumentParser(usage=__doc__)
parser.add_argument("designers_directory", help="path to google/fonts designer dir")
parser.add_argument("name", help="Designer name e.g 'Steve Matteson'")
parser.add_argument("--img_path", help="Optional path to profile image", default=None)
parser.add_argument(
"--spreadsheet", help="Optional path to the Google Drive spreadsheet"
)
args = parser.parse_args()

if args.spreadsheet:
import pandas as pd

df = pd.read_excel(args.spreadsheet)
entry = df.loc[df["Name"] == args.name]
if len(entry) == 0:
raise ValueError(f"Spreadsheet doesn't contain name '{args.name}'")
bio = entry["Bio"].item()
urls = entry["Link"].item()
if isinstance(urls, float): # pandas DF sets empty cells to a float
urls = None
else:
urls = parse_urls(urls)

if isinstance(bio, float):
bio = None
else:
bio = None
urls = None

make_designer(args.designers_directory, args.name, args.img_path, bio, urls)


if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ strictyaml
tabulate
unidecode
skia-pathops
pandas
xlrd
openpyxl
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,8 @@ def gftools_scripts():
'brotli',
'browserstack-local==1.2.2',
'pybrowserstack-screenshots==0.1',
'pandas',
'xlrd',
'openpyxl',
]
)

0 comments on commit 06171ac

Please sign in to comment.