#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import json
import fontforge
DOC= """
transform a batch of SVG to a font usable in QML. a QML object is generated to serve as an index
known issues:
- SVG should not have overlapping
- SVG should have a viewbox equal to the size of the SVG, ie:
<svg width="48" height="48" viewBox="0 0 48 48">
Input files must respect the format described by CONFIG_SCHEMA
"""
CONFIG_SCHEMA = {
"type": "object",
"properties": {
"hpp_name": { "type" : "string", "description" : "name of the generated C++ class header {{qml_name}}.hpp" },
"cpp_name": { "type" : "string", "description" : "name of the generated C++ class source {{qml_name}}.cpp" },
"qml_prefix": { "type" : "string", "description" : "import path within QML" },
"font_file": { "type" : "string", "description" : "output font file" },
"font_name": { "type" : "string", "description": "font family name" },
"glyphs" : {
"type" : "array",
"items" : {
"type": "object",
"properties" : {
"key" : { "type" : "string", "description": "keyword of the glyph, should be unique within the list" },
"path" : { "type" : "string", "description" : "path of the SVG to use for glyph" },
"charcode" : { "type" : "string", "description": "utf8 code" },
},
"required": ["key", "path"]
}
}
},
"required": ["glyphs", "hpp_name", "cpp_name", "font_name", "font_file", "qml_prefix"]
}
#decorator to help iterating over lists
def iterlist(func):
def inner(listArg):
return "\n".join([func(arg) for arg in listArg])
return inner
def renderHpp(*, qml_prefix, font_name, glyphs, **kwargs):
@iterlist
def _qproperties(glyph):
return f""" Q_PROPERTY(QChar {glyph["key"]} MEMBER {glyph["key"]} CONSTANT FINAL)"""
@iterlist
def _members(glyph):
return f""" static constexpr inline QChar {glyph["key"]}{{ u'{glyph["charcode"]}' }};"""
return f"""
/**
* This file was generated by makeIconFont.py, please do not edit by hand
*/
#ifndef VLCICONS_HPP
#define VLCICONS_HPP
#include <QString>
#include <QQmlEngine>
class VLCIcons : public QObject {{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(QString fontFamily MEMBER fontFamily CONSTANT FINAL)
{ _qproperties(glyphs) }
public:
VLCIcons(QObject* parent = nullptr);
public:
static const inline QString fontFamily{{ QStringLiteral("{font_name}") }};
// Icons
public:
{ _members(glyphs) }
}};
#endif /* VLCICONS_HPP */"""
def renderCpp(*, qml_prefix, font_file, **kwargs):
return f"""
/**
* This file was generated by makeIconFont.py, please do not edit by hand
*/
#include <QFontDatabase>
#include <QQmlFile>
#include "vlcicons.hpp"
VLCIcons::VLCIcons(QObject* parent)
: QObject(parent)
{{
QString localFile = QQmlFile::urlToLocalFileOrQrc(QStringLiteral("{qml_prefix}{font_file}"));
QFontDatabase::addApplicationFont(localFile);
}}"""
UTF8_AREA = 0xE000
def genQml(data):
with open(data["hpp_name"], "w+") as fd:
output = renderHpp(**data)
fd.write(output)
with open(data["cpp_name"], "w+") as fd:
output = renderCpp(**data)
fd.write(output)
def validateModel(model):
try:
import jsonschema
except ImportError:
return True
jsonschema.validate(model, CONFIG_SCHEMA)
return True
def main(model_fd):
data = json.load(model_fd)
if not data:
return
validateModel(data)
font = fontforge.font()
font.familyname = data["font_name"]
font.fontname = data["font_name"]
font.design_size = 1024.0
font.hasvmetrics = True
font.upos=0
font.ascent = 1024
font.descent = 0
font.hhea_ascent = 1024
font.hhea_ascent_add = False
font.hhea_descent = 0
font.hhea_descent_add = False
font.hhea_linegap = 0
font.os2_use_typo_metrics = True
font.os2_typoascent = 1024
font.os2_typoascent_add = False
font.os2_typodescent = 0
font.os2_typodescent_add = False
font.os2_typolinegap = 0
font.os2_winascent = 1024
font.os2_winascent_add = False
font.os2_windescent = 0
font.os2_windescent_add = False
for i, glyph in enumerate(data["glyphs"]):
charcode = UTF8_AREA + i
c = font.createChar(charcode)
glyph["charcode"] = "\\u{:x}".format(charcode)
c.importOutlines(glyph["path"])
#scale glyph to fit between 200 (base line) and 800 (x 0.6)
#c.transform((0.6, 0.0, 0.0, 0.6, 200, 200.))
c.vwidth = 1024
c.width = 1024
font.generate(data["font_file"])
genQml(data)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="generate an icon font for QML from SVG")
parser.add_argument("model", metavar="model",type=argparse.FileType("r"), default=sys.stdin,
help="the input model")
args = parser.parse_args()
main(args.model)
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|