2

我正在构建一个 UI 作为产品的一部分,以便轻松选择、选择和设置 Google 字体的样式。我受到可变字体的挑战,因为我找不到获取这些信息的好方法。开发者 API 通过一个大的 JSON 字符串为所有 Google 字体提供元数据。但是,它似乎不包含任何可以让开发人员辨别哪些字体是可变的数据。它们都“看起来”是标准字体。

有没有快速获取此类数据的方法?很快,我说的是类似于 Google Font 的开发人员 API 的东西,但包含各种可变字体的数据,其中包括:

  • 哪些字体是可变的?
  • 可变字体附带哪些轴?

目前,我见过的探索可变字体及其轴的唯一推荐方法是将字体加载到网页中,并在开发人员工具中使用 Firefox 的字体编辑器手动获取数据。但使用 Google 字体中当前的 112 种可变字体,收集这些信息可能需要数天时间。所以我的问题是:有没有更快的方法来获取谷歌字体中可变字体的元数据?

4

2 回答 2

1

我喜欢Stranger1586 的回答。但我确实还需要每个轴的步骤数据,以便正确构建滑块等 UI 元素。所以我决定写一个刮板从https://fonts.google.com/variablefonts刮取数据。根据 Google Font 的 GitHub 页面,该页面包含所有可变字体和所有支持轴的更新数据。

刮板创建一个 JSON 文件,其中包含每个字体系列的轴数据。我希望它可能对其他有相同需求的人有所帮助。这是代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.firefox.options import Options

from bs4 import BeautifulSoup
import json

def get_variable_fonts_data():
    print('Opening: Google Variable Fonts page...')
    options = Options()
    options.headless = True
    gecko_path = r'D:\Anaconda3\envs\py37\Lib\site-packages\helium\_impl\webdrivers\windows\geckodriver.exe'
    url = 'https://fonts.google.com/variablefonts'
    browser = webdriver.Firefox(options=options, executable_path=gecko_path)
    browser.get(url)
    timeout = 10  # seconds

    # Wait for the table element as it is not part of the page source but is generated with JavaScript
    try:
        WebDriverWait(browser, timeout).until(EC.presence_of_element_located((By.TAG_NAME, 'table')))
        print('Generating font table')
    except TimeoutException:
        print("Loading took too much time!")

    soup = BeautifulSoup(browser.page_source, 'html.parser')
    table = soup.find('table')
    table_head = table.find('thead').find('tr')
    header_values = []
    for cell in table_head.find_all('th'):
        header_values.append(cell.encode_contents().decode("utf-8").strip())
    table_body = table.find('tbody')
    variable_fonts_data = {}
    for row in table_body.find_all('tr'):
        axis_data = {}
        cells = row.find_all('td')
        font_family_name = cells[0].find('a').encode_contents().decode("utf-8").strip()
        if not (font_family_name in variable_fonts_data):
            variable_fonts_data[font_family_name] = {'Axes': {}}

        axis_data[header_values[2]] = cells[2].encode_contents().decode("utf-8").strip()  # Default
        axis_data[header_values[3]] = cells[3].encode_contents().decode("utf-8").strip()  # Min
        axis_data[header_values[4]] = cells[4].encode_contents().decode("utf-8").strip()  # Max
        axis_data[header_values[5]] = cells[5].encode_contents().decode("utf-8").strip()  # Step

        variable_fonts_data[font_family_name]['Axes'][cells[1].encode_contents().decode("utf-8").strip()] = axis_data

    return variable_fonts_data


with open('google_variable_fonts.json', 'w') as fonts_file:
    json.dump(get_variable_fonts_data(), fonts_file) 
于 2021-09-30T09:42:23.000 回答
1

我正在开发一个字体选择器插件,遇到了类似的问题,所以我开始调查谷歌字体主要分发站点,直到找到我想要的东西。Google 的字体站点执行对以下 API 端点的调用。

https://fonts.google.com/metadata/fonts

它返回以下文本文件。

)]}'{"axisRegistry": [
{
  "tag": "FILL",
  "displayName": "Fill",
  "min": 0.0,
  "defaultValue": 0.0,
  "max": 1.0,
  "precision": -2,
  "description": "The Fill axis is intended to provide a treatment of the design that fills in transparent forms with opaque ones (and sometimes interior opaque forms become transparent, to maintain contrasting shapes). Transitions often occur from the center, a side, or a corner, but can be in any direction. This can be useful in animation or interaction to convey a state transition. The numbers indicate proportion filled, from 0 (no treatment) to 1 (completely filled).",
  "fallbacks": [
    {
      "name": "Normal",
      "value": 0.0
    },
    {
      "name": "Filled",
      "value": 1.0
    }
  ]
} ...],"familyMetadataList": [{
  "family": "Alegreya",
  "displayName": null,
  "category": "Serif",
  "size": 425570,
  "subsets": [
    "menu",
    "cyrillic",
    "cyrillic-ext",
    "greek",
    "greek-ext",
    "latin",
    "latin-ext",
    "vietnamese"
  ],
  "fonts": {
    "400": {
      "thickness": 4,
      "slant": 1,
      "width": 6,
      "lineHeight": 1.361
    },
    "400i": {
      "thickness": 4,
      "slant": 4,
      "width": 6,
      "lineHeight": 1.361
    },
    "500": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "500i": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "600": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "600i": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "700": {
      "thickness": 7,
      "slant": 1,
      "width": 7,
      "lineHeight": 1.361
    },
    "700i": {
      "thickness": 6,
      "slant": 4,
      "width": 6,
      "lineHeight": 1.361
    },
    "800": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "800i": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "900": {
      "thickness": 8,
      "slant": 1,
      "width": 7,
      "lineHeight": 1.361
    },
    "900i": {
      "thickness": 8,
      "slant": 4,
      "width": 6,
      "lineHeight": 1.361
    }
  },
  "axes": [
    {
      "tag": "wght",
      "min": 400.0,
      "max": 900.0,
      "defaultValue": 400.0
    }
  ],
  "unsupportedAxes": [],
  "designers": [
    "Juan Pablo del Peral",
    "Huerta Tipográfica"
  ],
  "lastModified": "2021-02-11",
  "dateAdded": "2011-12-19",
  "popularity": 159,
  "trending": 828,
  "defaultSort": 164,
  "androidFragment": null,
  "isNoto": false
}...],...}

请注意,虽然上面看起来像一个 JSON 文件,但它将被视为文本文件,因此您必须)]}'从文本文件的顶部删除这部分,然后才能将其解析为 JSON 文件。唯一重要的顶级属性(就您的用例而言)是“familyMetadataList”属性,顾名思义,它包括所有字体元数据,其中包括任何给定字体具有的轴。您将不得不在“familyMetadataList”道具上循环并查看字体的轴成员是否有一个不为空的数组,从那里我们可以推断它是一个可变字体。你可以做一些简单的事情来确定哪种字体是可变的。

const variableFonts=[];
const googleFontJSON = {
 "familyMetadataList": [
 {
  "family": "Alegreya",
  "displayName": null,
  "category": "Serif",
  "size": 425570,
  "subsets": [
    "menu",
    "cyrillic",
    "cyrillic-ext",
    "greek",
    "greek-ext",
    "latin",
    "latin-ext",
    "vietnamese"
  ],
  "fonts": {
    "400": {
      "thickness": 4,
      "slant": 1,
      "width": 6,
      "lineHeight": 1.361
    },
    "400i": {
      "thickness": 4,
      "slant": 4,
      "width": 6,
      "lineHeight": 1.361
    },
    "500": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "500i": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "600": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "600i": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "700": {
      "thickness": 7,
      "slant": 1,
      "width": 7,
      "lineHeight": 1.361
    },
    "700i": {
      "thickness": 6,
      "slant": 4,
      "width": 6,
      "lineHeight": 1.361
    },
    "800": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "800i": {
      "thickness": null,
      "slant": null,
      "width": null,
      "lineHeight": 1.361
    },
    "900": {
      "thickness": 8,
      "slant": 1,
      "width": 7,
      "lineHeight": 1.361
    },
    "900i": {
      "thickness": 8,
      "slant": 4,
      "width": 6,
      "lineHeight": 1.361
    }
  },
  "axes": [
    {
      "tag": "wght",
      "min": 400.0,
      "max": 900.0,
      "defaultValue": 400.0
    }
  ],
  "unsupportedAxes": [],
  "designers": [
    "Juan Pablo del Peral",
    "Huerta Tipográfica"
  ],
  "lastModified": "2021-02-11",
  "dateAdded": "2011-12-19",
  "popularity": 159,
  "trending": 828,
  "defaultSort": 164,
  "androidFragment": null,
  "isNoto": false
},
    {
      "family": "Alegreya SC",
      "displayName": null,
      "category": "Serif",
      "size": 381295,
      "subsets": [
        "menu",
        "cyrillic",
        "cyrillic-ext",
        "greek",
        "greek-ext",
        "latin",
        "latin-ext",
        "vietnamese"
      ],
      "fonts": {
        "400": {
          "thickness": 4,
          "slant": 1,
          "width": 7,
          "lineHeight": 1.361
        },
        "400i": {
          "thickness": 4,
          "slant": 4,
          "width": 7,
          "lineHeight": 1.361
        },
        "500": {
          "thickness": null,
          "slant": null,
          "width": null,
          "lineHeight": 1.361
        },
        "500i": {
          "thickness": null,
          "slant": null,
          "width": null,
          "lineHeight": 1.361
        },
        "700": {
          "thickness": 6,
          "slant": 1,
          "width": 7,
          "lineHeight": 1.361
        },
        "700i": {
          "thickness": 6,
          "slant": 3,
          "width": 7,
          "lineHeight": 1.361
        },
        "800": {
          "thickness": null,
          "slant": null,
          "width": null,
          "lineHeight": 1.361
        },
        "800i": {
          "thickness": null,
          "slant": null,
          "width": null,
          "lineHeight": 1.361
        },
        "900": {
          "thickness": 8,
          "slant": 1,
          "width": 7,
          "lineHeight": 1.361
        },
        "900i": {
          "thickness": 8,
          "slant": 3,
          "width": 7,
          "lineHeight": 1.361
        }
      },
      "axes": [],
      "unsupportedAxes": [],
      "designers": [
        "Juan Pablo del Peral",
        "Huerta Tipográfica"
      ],
      "lastModified": "2021-03-24",
      "dateAdded": "2011-12-19",
      "popularity": 436,
      "trending": 249,
      "defaultSort": 443,
      "androidFragment": null,
      "isNoto": false
    }
]}; // The array of font meta data
googleFontJSON.familyMetadataList.forEach(font => {     
  if (font.axes.length) {
    font.isVariable=true;
  } else {
    font.isVariable=false;
  }
});
console.log(googleFontJSON);

你如何分析数据当然完全是你自己的特权。史蒂文先生,祝你的项目好运。您还可以通过在https://fonts.google.com/metadata/fonts找到的轴注册表道具找到有关任何给定变量字体轴步骤的更多信息。只需检查精度道具。例如,步长为 0.1 的轴(如“opsz”和“wdth”)的精度设置为 -1,步长为 0.01 的轴(如“CASL”和“MONO”)的精度设置为 -2。

  "axisRegistry": [
    {
      "tag": "opsz",
      "displayName": "Optical size",
      "min": 6.0,
      "defaultValue": 14.0,
      "max": 144.0,
      "precision": -1, //<=== Here
      "description": "Adapt the ...",
      "fallbacks": [
        {
          "name": "6pt",
          "value": 6.0
        },
        {
          "name": "7pt",
          "value": 7.0
        }...
      ]
    },...

于 2021-09-07T03:47:51.017 回答