从字体的后记名称中获取字体的文件名

问题描述 投票:0回答:3

当我唯一的信息是字体的“postscript”名称时,我试图获取字体文件名。 (强调:字体名称是postscript,不是字体)。
例如,我有以下后记名称:TimesNewRomanPSMT。
保存在注册表中的真实姓名是:Times New Roman (TrueType)。
有没有办法从给定的后记名称中获取该名称?

我在这里看到了类似的帖子,但没有得到答复: C# 从 postscript 名称获取字体

我用 C++ 编写这个代码,所以我不受编码语言的限制。 目前我正在为 Windows 编写此代码,但它应该兼容,或者至少有 MacOS 的替代代码

c++ windows macos fonts postscript
3个回答
0
投票

我有 C++ 代码来从给定的字体文件检查标题中获取字体名称...但是对于我测试的某些字体来说,这失败了(据说可以工作 90%)。我认为最简单的方法是使用十六进制编辑器打开字体文件并在其中搜索字体名称。如果您担心注册表问题,可以重新注册字体名称,如下例所示:

reg 添加“HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts”/v“Arial Bold”/t REG_SZ /d arialbd.ttf


0
投票

我也有类似的问题,但是是针对 Photoshop 的。所以我写了下面的代码。它输出系统中安装的所有字体的 CSV 及其文件名、Windows 名称和 Postscript 名称。

您需要安装 Photoshop 和 Python 才能运行它。在运行之前,还要保持 Photoshop 窗口打开,以便它可以从那里获取字体列表。

短名称函数来自这里 - https://gist.github.com/pklaus/dce37521579513c574d0

# This program lists all installed fonts on the computer with their font file name, Windows name and Postscript name.

import os
from fontTools import ttLib
from win32com.client import GetActiveObject
import pandas as pd

FONT_SPECIFIER_NAME_ID = 4
FONT_SPECIFIER_FAMILY_ID = 1
list = []
app = GetActiveObject("Photoshop.Application") # Get instance of open Photoshop window
df = pd.DataFrame(columns=['Font File Name', 'Windows Name', 'Postscript Name'])

def shortName(font):
    """Get the short name from the font's names table"""
    name = ""
    family = ""
    for record in font['name'].names:
        if b'\x00' in record.string:
            name_str = record.string.decode('utf-16-be')
        else:
            name_str = record.string.decode('utf-8')
        if record.nameID == FONT_SPECIFIER_NAME_ID and not name:
            name = name_str
        elif record.nameID == FONT_SPECIFIER_FAMILY_ID and not family:
            family = name_str
        if name and family: break
    return name, family

def getPostScriptName(winName):
    for i in range(0, len(app.fonts)):
        if(app.fonts[i].name == winName):
            return app.fonts[i].postScriptName

x = 0
for file in os.listdir(r'C:\Windows\Fonts'):
    if (file.endswith(".ttf") or file.endswith(".otf")):
        # list.append(file)
        try:
            fontfile = file
            file = "C:\\Windows\\Fonts\\" + file
            tt = ttLib.TTFont(file)
            psName = getPostScriptName(shortName(tt)[0])
            print(fontfile, shortName(tt)[0], psName)
            df.at[x, 'Font File Name'] = fontfile
            df.at[x, 'Windows Name'] = shortName(tt)[0]
            df.at[x, 'Postscript Name'] = psName
            x = x + 1
            df.to_csv("installed-fonts.csv",index=False)
        except Exception as e:
            print (e)
            continue

0
投票

对于 Windows,您可以使用 DirectWrite

适用于带有 SP2 及更多版本的 Windows Vista

#include <iostream>
#include <list>
#include <vector>
#include <atlbase.h>
#include <string.h>
#include <dwrite.h>
#pragma comment(lib, "dwrite.lib")


std::wstring get_file_path_from_dwrite_font_file(CComPtr<IDWriteFontFile> font_file)
{
    HRESULT hr;

    LPCVOID font_file_reference_key;
    UINT32 font_file_reference_key_size;
    hr = font_file->GetReferenceKey(&font_file_reference_key, &font_file_reference_key_size);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetReferenceKey.");
    }

    CComPtr<IDWriteFontFileLoader> loader;
    hr = font_file->GetLoader(&loader);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetLoader.");
    }

    CComPtr<IDWriteLocalFontFileLoader> local_loader;
    hr = loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader), reinterpret_cast<void**>(&local_loader));
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling QueryInterface.");
    }

    UINT32 path_length;
    hr = local_loader->GetFilePathLengthFromKey(font_file_reference_key, font_file_reference_key_size, &path_length);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetFilePathLengthFromKey.");
    }


    std::wstring path(path_length + 1, L'\0');
    hr = local_loader->GetFilePathFromKey(font_file_reference_key, font_file_reference_key_size, &path[0], path_length + 1);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetFilePathFromKey.");
    }   

    return path;
}

bool is_font_match_postscript_name(CComPtr<IDWriteFont> font, std::wstring requested_postcript_name)
{
    HRESULT hr;

    CComPtr<IDWriteLocalizedStrings> informational_strings;
    BOOL exists;
    hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &informational_strings, &exists);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetInformationalStrings.");
    }

    if (!exists) {
        return false;
    }

    for (UINT32 i = 0; i < informational_strings->GetCount(); i++)
    {
        UINT32 string_length;
        hr = informational_strings->GetStringLength(i, &string_length);
        if (FAILED(hr))
        {
            throw std::runtime_error("An error has occured when calling GetStringLength.");
        }

        std::wstring font_postscript_name(string_length + 1, L'\0');
        hr = informational_strings->GetString(i, &font_postscript_name[0], string_length + 1);
        if (FAILED(hr))
        {
            throw std::runtime_error("An error has occured when calling GetString.");
        }

        if (_wcsicmp(font_postscript_name.c_str(), requested_postcript_name.c_str()) == 0) {
            return true;
        }
    }

    return false;

}


std::list<std::wstring> get_fonts_from_postscript_name(const std::wstring& postscript_name)
{
    std::list<std::wstring> fonts_filename_list;
    HRESULT hr;

    CComPtr<IDWriteFactory> dwrite_factory;
    hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&dwrite_factory));
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling DWriteCreateFactory.");
    }

    CComPtr<IDWriteFontCollection> sys_collection;
    hr = dwrite_factory->GetSystemFontCollection(&sys_collection, true);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetSystemFontCollection.");
    }


    for (UINT32 i = 0; i < sys_collection->GetFontFamilyCount(); i++)
    {
        CComPtr<IDWriteFontFamily> font_family;
        hr = sys_collection->GetFontFamily(i, &font_family);
        if (FAILED(hr))
        {
            throw std::runtime_error("An error has occured when calling GetFontFamily.");
        }

        for (UINT32 j = 0; j < font_family->GetFontCount(); j++)
        {
            CComPtr<IDWriteFont> font;
            hr = font_family->GetFont(j, &font);
            if (FAILED(hr))
            {
                throw std::runtime_error("An error has occured when calling GetFont.");
            }

            if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE)
            {
                continue;
            }


            if (is_font_match_postscript_name(font, postscript_name)) {
                CComPtr<IDWriteFontFace> font_face;
                hr = font->CreateFontFace(&font_face);
                if (FAILED(hr))
                {
                    throw std::runtime_error("An error has occured when calling CreateFontFace.");
                }

                UINT32 file_count;
                hr = font_face->GetFiles(&file_count, NULL);
                if (FAILED(hr))
                {
                    throw std::runtime_error("An error has occured when calling GetFiles.");
                }


                std::vector<CComPtr<IDWriteFontFile>> font_files(file_count);
                hr = font_face->GetFiles(&file_count, reinterpret_cast<IDWriteFontFile**>(font_files.data()));
                if (FAILED(hr))
                {
                    throw std::runtime_error("An error has occured when calling GetFiles.");
                }

                for (int i = 0; i < file_count; i++)
                {
                    std::wstring font_filename = get_file_path_from_dwrite_font_file(font_files[i]);
                    fonts_filename_list.push_back(font_filename);
                }
            }

        }

    }


    return fonts_filename_list;
}


int main() {
    std::list<std::wstring> fonts_filename_list = get_fonts_from_postscript_name(L"ArialNarrow");


    for (std::wstring font_filename : fonts_filename_list)
    {
        std::wcout << L"Font filename: " << font_filename << std::endl;
    }

    return 0;
}

适用于 Windows 10 及更多版本

#include <iostream>
#include <list>
#include <vector>
#include <atlbase.h>
#include <dwrite.h>
#include <dwrite_3.h>
#pragma comment(lib, "dwrite.lib")



std::wstring get_file_path_from_dwrite_font_file(CComPtr<IDWriteFontFile> font_file)
{
    HRESULT hr;

    LPCVOID font_file_reference_key;
    UINT32 font_file_reference_key_size;
    hr = font_file->GetReferenceKey(&font_file_reference_key, &font_file_reference_key_size);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetReferenceKey.");
    }

    CComPtr<IDWriteFontFileLoader> loader;
    hr = font_file->GetLoader(&loader);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetLoader.");
    }

    CComPtr<IDWriteLocalFontFileLoader> local_loader;
    hr = loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader), reinterpret_cast<void**>(&local_loader));
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling QueryInterface.");
    }

    UINT32 path_length;
    hr = local_loader->GetFilePathLengthFromKey(font_file_reference_key, font_file_reference_key_size, &path_length);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetFilePathLengthFromKey.");
    }


    std::wstring path(path_length + 1, L'\0');
    hr = local_loader->GetFilePathFromKey(font_file_reference_key, font_file_reference_key_size, &path[0], path_length + 1);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetFilePathFromKey.");
    }   

    return path;
}


std::list<std::wstring> get_fonts_from_postscript_name(const std::wstring& postscript_name)
{
    std::list<std::wstring> fonts_filename_list;
    HRESULT hr;

    CComPtr<IDWriteFactory3> dwrite_factory;
    hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory3), reinterpret_cast<IUnknown**>(&dwrite_factory));
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling DWriteCreateFactory.");
    }

    CComPtr<IDWriteFontSet> font_set;
    hr = dwrite_factory->GetSystemFontSet(&font_set);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetSystemFontSet.");
    }

    DWRITE_FONT_PROPERTY font_property = { DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, postscript_name.c_str(), L"" };

    CComPtr<IDWriteFontSet> filtered_font_set;
    hr = font_set->GetMatchingFonts(&font_property, 1, &filtered_font_set);
    if (FAILED(hr))
    {
        throw std::runtime_error("An error has occured when calling GetMatchingFonts.");
    }

    for (UINT32 i = 0; i < filtered_font_set->GetFontCount(); i++)
    {
        CComPtr<IDWriteFontFaceReference> font_face_reference;
        hr = filtered_font_set->GetFontFaceReference(i, &font_face_reference);
        if (FAILED(hr))
        {
            throw std::runtime_error("An error has occured when calling GetMatchingFonts.");
        }

        CComPtr<IDWriteFontFile> font_file;
        hr = font_face_reference->GetFontFile(&font_file);
        if (FAILED(hr))
        {
            throw std::runtime_error("An error has occured when calling GetMatchingFonts.");
        }

        std::wstring font_filename = get_file_path_from_dwrite_font_file(font_file);
        fonts_filename_list.push_back(font_filename);
    }


    return fonts_filename_list;
}


int main() {
    std::list<std::wstring> fonts_filename_list = get_fonts_from_postscript_name(L"BaloneKids");


    for (std::wstring font_filename : fonts_filename_list)
    {
        std::wcout << L"Font filename: " << font_filename << std::endl;
    }

    return 0;
}

我没有 macOS 机器,但我的想法是这样的。

  1. CFDictionaryCreatekCTFontNameAttribute
  2. CTFontDescriptorCreateWithAttributes
  3. CTFontDescriptor创建匹配字体描述符
  4. CTFontCollection创建匹配字体描述符
  5. CTFontDescriptorCopyAttributekCTFontURLAttribute
© www.soinside.com 2019 - 2024. All rights reserved.