Add font import for Now, Gotham and Open Sauce One overrides; package fonts for Void
Font import: - Migration M6 adds user_fonts; files are stored content-addressed under the local data dir. New Rust commands inspect, import, list, read and remove fonts, refusing WOFF2, collections, variable fonts and restricted fsType, and unpacking WOFF1 to plain sfnt. - Imported fonts register in the render worker as user:<Face> families with an italic alias, and are pinned in the frozen render prefs so issued invoices can still re-render. Fonts referenced by issued invoices are hidden, never deleted. - Size and tracking compensations tuned for the substitutes apply only while the face is not overridden; default output and fingerprint goldens are unchanged. - Settings gets a Fonts section with a licence acknowledgement. Void packaging: - Install fonts to /usr/share/fonts/voiced with per-family OFL licences, set font_dirs, and add INSTALL/REMOVE scripts that run fc-cache. xbps-create carries both scripts (verified in a void-glibc container). - Fix xbps-create dependency specs in build-xbps.sh.
This commit is contained in:
Generated
+1
@@ -4290,6 +4290,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"flate2",
|
||||
"image",
|
||||
"percent-encoding",
|
||||
"rusqlite",
|
||||
|
||||
@@ -27,6 +27,7 @@ uuid = { version = "1", features = ["v4"] }
|
||||
thiserror = "2"
|
||||
base64 = "0.22"
|
||||
sha2 = "0.10"
|
||||
flate2 = "1"
|
||||
percent-encoding = "2"
|
||||
image = { version = "0.25.10", default-features = false, features = ["png", "jpeg", "webp"] }
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ pub mod archive;
|
||||
pub mod assets;
|
||||
pub mod clients;
|
||||
pub mod files;
|
||||
pub mod fonts;
|
||||
pub mod invoice;
|
||||
pub mod logo;
|
||||
pub mod raw;
|
||||
|
||||
+30
-3
@@ -10,7 +10,7 @@ const MAX_BACKUPS: usize = 10;
|
||||
const BACKUP_PREFIX: &str = "voiced-pre-v";
|
||||
|
||||
/// Highest schema version, i.e. the number of entries in `migrations()`.
|
||||
const LATEST_VERSION: i64 = 5;
|
||||
const LATEST_VERSION: i64 = 6;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum DbError {
|
||||
@@ -190,8 +190,35 @@ ALTER TABLE app_settings ADD COLUMN logo_meta TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE app_settings ADD COLUMN logo_includes_name TEXT NOT NULL DEFAULT 'auto';
|
||||
"#;
|
||||
|
||||
/// Version 6: user-imported fonts for the three licensed template faces. The files live content-addressed under
|
||||
/// `<local data dir>/fonts/<sha256>.<ttf|otf>`; invoices freeze the sha256 of the fonts they used in render_prefs.
|
||||
/// `hidden` retires a font that an issued invoice still references (never deleted while referenced).
|
||||
const M6: &str = r#"
|
||||
CREATE TABLE user_fonts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
face TEXT NOT NULL CHECK (face IN ('Now', 'Gotham', 'Open Sauce One')),
|
||||
family_name TEXT NOT NULL,
|
||||
full_name TEXT NOT NULL,
|
||||
style_name TEXT NOT NULL DEFAULT '',
|
||||
weight INTEGER NOT NULL CHECK (weight BETWEEN 100 AND 900),
|
||||
style TEXT NOT NULL CHECK (style IN ('normal', 'italic')),
|
||||
sha256 TEXT NOT NULL,
|
||||
file_name TEXT NOT NULL,
|
||||
format TEXT NOT NULL CHECK (format IN ('ttf', 'otf')),
|
||||
size INTEGER NOT NULL,
|
||||
fs_type INTEGER NOT NULL DEFAULT 0,
|
||||
has_rupee INTEGER NOT NULL DEFAULT 0,
|
||||
licence_ack_at TEXT NOT NULL,
|
||||
imported_at TEXT NOT NULL,
|
||||
hidden INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
CREATE INDEX idx_user_fonts_sha ON user_fonts(sha256);
|
||||
-- One visible font per face, weight and style; a hidden one keeps its row but frees the slot.
|
||||
CREATE UNIQUE INDEX idx_user_fonts_slot ON user_fonts(face, weight, style) WHERE hidden = 0;
|
||||
"#;
|
||||
|
||||
fn migrations() -> Migrations<'static> {
|
||||
Migrations::new(vec![M::up(SCHEMA), M::up(M2), M::up(M3), M::up(M4), M::up(M5)])
|
||||
Migrations::new(vec![M::up(SCHEMA), M::up(M2), M::up(M3), M::up(M4), M::up(M5), M::up(M6)])
|
||||
}
|
||||
|
||||
/// Open (creating if needed) the database at `path` and bring it to the latest schema.
|
||||
@@ -620,7 +647,7 @@ CREATE INDEX IF NOT EXISTS idx_invoices_created ON invoices(created_at DESC);
|
||||
assert_eq!(user_version(&old), 4);
|
||||
}
|
||||
let conn = open(&path, &dir.path().join("backups")).unwrap();
|
||||
assert_eq!(user_version(&conn), 5);
|
||||
assert_eq!(user_version(&conn), LATEST_VERSION);
|
||||
let (logo, meta): (String, String) = conn
|
||||
.query_row("SELECT logo_path, logo_meta FROM app_settings WHERE id = 1", [], |r| {
|
||||
Ok((r.get(0)?, r.get(1)?))
|
||||
|
||||
@@ -141,6 +141,11 @@ pub fn run() {
|
||||
commands::archive::archive_pdf,
|
||||
commands::archive::read_archive,
|
||||
commands::archive::archive_status,
|
||||
commands::fonts::inspect_font,
|
||||
commands::fonts::import_font,
|
||||
commands::fonts::list_user_fonts,
|
||||
commands::fonts::get_user_font_bytes,
|
||||
commands::fonts::remove_user_font,
|
||||
commands::files::write_export_file,
|
||||
commands::files::get_last_export_dir,
|
||||
commands::files::reveal_in_folder,
|
||||
|
||||
Reference in New Issue
Block a user