【问题标题】:Is there a "fast" way to get info about variable Google Fonts?是否有一种“快速”的方式来获取有关可变 Google 字体的信息?
【发布时间】:2021-10-31 04:06:34
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: axes google-font-api google-fonts variable-fonts


    【解决方案1】:

    我正在开发一个字体选择器插件,但遇到了类似的问题,所以我开始调查谷歌字体主 distribution site,直到找到我想要的东西。 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 的轴注册表道具找到的 JSON 文件获取有关任何给定变量字体轴步骤的更多信息。 只需检查精度道具。 例如,步长为 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
            }...
          ]
        },...

    【讨论】:

    【解决方案2】:

    我喜欢answer from 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) 
    

    【讨论】:

    • 将刮板与@Stranger1586 的答案相结合,可为您提供所需的一切。刮板为您提供每个轴上的数据,包括步数,并且从 fonts.google.com/metadata/fonts 端点中的“axisRegistry”,您可以获得每个轴的显示名称。
    • I really also need data on the steps... 我不知道你为什么想要这些步骤。请注意,可变字体允许在每个轴上连续变化(16 个小数位的模粒度)。罐头可以将轴调制成离散的步骤,但通常不会这样做。
    • @Peter Constable。正如我所写:因为我正在构建 UI 元素(例如滑块)来控制字体轴。他们不同,你知道的。有些使用小数,有些使用整数,它们有不同的端点,有些甚至有负值。如果没有此类数据,您将如何构建功能滑块来控制轴?
    • 我不熟悉 Google 的 API 或元数据文件有什么,但可以告诉你字体本身有什么。字体的“fvar”表定义了轴及其最小、默认、最大点(均表示为 16.16 浮点数)。它还有一个命名实例数组;例如,[wght:600, wdth:75] = "Condensed Semibold"。现在,对您来说一个关键问题是您是否希望 UI 显示命名实例或沿每个轴的步骤。命名实例将暗示沿每个轴的点,但仅在所有轴的组合中。如果您想要每个轴独立的步骤,'STAT' 表(如果正确创建)有。
    猜你喜欢
    • 1970-01-01
    • 2012-02-15
    • 2017-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多