clap with commands: inspect, split, create, split-and-create
This commit is contained in:
parent
386b3d042d
commit
56d5adc2c5
4 changed files with 384 additions and 59 deletions
194
Cargo.lock
generated
194
Cargo.lock
generated
|
|
@ -17,6 +17,56 @@ dependencies = [
|
||||||
"equator",
|
"equator",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell_polyfill",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.98"
|
version = "1.0.98"
|
||||||
|
|
@ -150,12 +200,58 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -377,6 +473,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
|
@ -412,6 +514,7 @@ checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
|
||||||
name = "karlos-helper"
|
name = "karlos-helper"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"clap",
|
||||||
"image",
|
"image",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -564,6 +667,12 @@ version = "1.21.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
|
|
@ -842,6 +951,12 @@ version = "1.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.104"
|
version = "2.0.104"
|
||||||
|
|
@ -943,6 +1058,12 @@ version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "v_frame"
|
name = "v_frame"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
@ -1039,6 +1160,79 @@ version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
|
checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.12"
|
version = "0.7.12"
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
clap = { version = "4.5.42", features = ["derive"] }
|
||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
serde = { version="1.0.219", features=["derive"] }
|
serde = { version="1.0.219", features=["derive"] }
|
||||||
serde_json = "1.0.141"
|
serde_json = "1.0.141"
|
||||||
|
|
|
||||||
180
src/main.rs
180
src/main.rs
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
mod image_wrapper;
|
mod image_wrapper;
|
||||||
|
use clap::Parser;
|
||||||
use image_wrapper::BWImage;
|
use image_wrapper::BWImage;
|
||||||
mod sff;
|
mod sff;
|
||||||
|
|
||||||
|
|
@ -35,6 +36,7 @@ fn load_font_dir<P: AsRef<Path>>(dir_with_images: P) -> HashMap<u32, BWImage> {
|
||||||
assert!(!map.contains_key(&number));
|
assert!(!map.contains_key(&number));
|
||||||
map.insert(number, img);
|
map.insert(number, img);
|
||||||
}
|
}
|
||||||
|
assert!(!map.is_empty());
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,59 +153,31 @@ struct Index {
|
||||||
splitters: Vec<Splitter>,
|
splitters: Vec<Splitter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn do_inspect<P: AsRef<Path>>(path: P) {
|
||||||
std::fs::remove_dir_all("font").unwrap();
|
let read_file = std::fs::read(path).unwrap();
|
||||||
std::fs::create_dir("font").unwrap();
|
let fd = sff::decode(&read_file);
|
||||||
let args: Vec<String> = std::env::args().collect();
|
for i in 32..128 {
|
||||||
let index: Index = serde_json::from_str(&std::fs::read_to_string(&args[1]).unwrap()).unwrap();
|
fd.print_symbol(fd.find_codepoint(i).unwrap());
|
||||||
for splitter in index.splitters {
|
|
||||||
match splitter {
|
|
||||||
Splitter::Table {
|
|
||||||
path,
|
|
||||||
nrows,
|
|
||||||
ncols,
|
|
||||||
start_number,
|
|
||||||
} => {
|
|
||||||
image_split_table(
|
|
||||||
path,
|
|
||||||
"font",
|
|
||||||
start_number,
|
|
||||||
nrows,
|
|
||||||
ncols,
|
|
||||||
index.char_width,
|
|
||||||
index.char_height,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Splitter::Individual { path, numbers } => {
|
|
||||||
image_split_individual(
|
|
||||||
path,
|
|
||||||
"font",
|
|
||||||
&numbers[..],
|
|
||||||
index.char_width,
|
|
||||||
index.char_height,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Splitter::Single { path, number } => {
|
|
||||||
image_split_individual(
|
|
||||||
path,
|
|
||||||
"font",
|
|
||||||
&[number][..],
|
|
||||||
index.char_width,
|
|
||||||
index.char_height,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let map = load_font_dir("font");
|
fn do_create<P: AsRef<Path>, Q: AsRef<Path>>(font_dir: P, dest: Q, encoding: sff::Encoding) {
|
||||||
|
let map = load_font_dir(font_dir);
|
||||||
|
let (char_width, char_height) = {
|
||||||
|
let random_element = map.values().next().unwrap();
|
||||||
|
(
|
||||||
|
random_element.width as usize,
|
||||||
|
random_element.height as usize,
|
||||||
|
)
|
||||||
|
};
|
||||||
let mut sorted_keys: Vec<u32> = map.keys().copied().collect();
|
let mut sorted_keys: Vec<u32> = map.keys().copied().collect();
|
||||||
sorted_keys.sort();
|
sorted_keys.sort();
|
||||||
let ranges = sorted_numbers_into_ranges(&sorted_keys);
|
let ranges = sorted_numbers_into_ranges(&sorted_keys);
|
||||||
|
|
||||||
let fdo = sff::FileDescOut {
|
let fdo = sff::FileDescOut {
|
||||||
char_width: 8,
|
char_width,
|
||||||
char_height: 18,
|
char_height,
|
||||||
encoding: sff::Encoding::BitPerPix4,
|
encoding,
|
||||||
tables: ranges
|
tables: ranges
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|rng| sff::TableOut {
|
.map(|rng| sff::TableOut {
|
||||||
|
|
@ -217,7 +191,121 @@ fn main() {
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
std::fs::write("font.sff", fdo.encode()).unwrap();
|
std::fs::write(dest, fdo.encode()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_split<P: AsRef<Path>, Q: AsRef<Path>>(index: P, font_dir: Q) {
|
||||||
|
if std::fs::exists(font_dir.as_ref()).unwrap() {
|
||||||
|
std::fs::remove_dir_all(font_dir.as_ref()).unwrap();
|
||||||
|
}
|
||||||
|
std::fs::create_dir(font_dir.as_ref()).unwrap();
|
||||||
|
let index: Index = serde_json::from_str(&std::fs::read_to_string(index).unwrap()).unwrap();
|
||||||
|
println!("{:#?}", index);
|
||||||
|
for splitter in index.splitters {
|
||||||
|
match splitter {
|
||||||
|
Splitter::Table {
|
||||||
|
path,
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
start_number,
|
||||||
|
} => {
|
||||||
|
image_split_table(
|
||||||
|
path,
|
||||||
|
font_dir.as_ref(),
|
||||||
|
start_number,
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
index.char_width,
|
||||||
|
index.char_height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Splitter::Individual { path, numbers } => {
|
||||||
|
image_split_individual(
|
||||||
|
path,
|
||||||
|
font_dir.as_ref(),
|
||||||
|
&numbers[..],
|
||||||
|
index.char_width,
|
||||||
|
index.char_height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Splitter::Single { path, number } => {
|
||||||
|
image_split_individual(
|
||||||
|
path,
|
||||||
|
font_dir.as_ref(),
|
||||||
|
&[number][..],
|
||||||
|
index.char_width,
|
||||||
|
index.char_height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Parser, Debug)]
|
||||||
|
struct Cli {
|
||||||
|
#[command(subcommand)]
|
||||||
|
cmd: Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Subcommand, Debug)]
|
||||||
|
enum Command {
|
||||||
|
Inspect {
|
||||||
|
path: String,
|
||||||
|
},
|
||||||
|
Create {
|
||||||
|
#[arg(long)]
|
||||||
|
font_dir: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
encoding: String,
|
||||||
|
dest: String,
|
||||||
|
},
|
||||||
|
Split {
|
||||||
|
#[arg(long)]
|
||||||
|
index: String,
|
||||||
|
#[arg(long)]
|
||||||
|
font_dir: String,
|
||||||
|
},
|
||||||
|
SplitAndCreate {
|
||||||
|
#[arg(long)]
|
||||||
|
index: String,
|
||||||
|
#[arg(long)]
|
||||||
|
font_dir: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
encoding: String,
|
||||||
|
dest: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn str_to_encoding(s: &str) -> sff::Encoding {
|
||||||
|
match s {
|
||||||
|
"BitPerPix1" => sff::Encoding::BitPerPix1,
|
||||||
|
"BitPerPix2" => sff::Encoding::BitPerPix2,
|
||||||
|
"BitPerPix4" => sff::Encoding::BitPerPix4,
|
||||||
|
"BitPerPix8" => sff::Encoding::BitPerPix8,
|
||||||
|
_ => panic!("unknown encoding"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
match cli.cmd {
|
||||||
|
Command::Inspect { path } => do_inspect(path),
|
||||||
|
Command::Create {
|
||||||
|
font_dir,
|
||||||
|
encoding,
|
||||||
|
dest,
|
||||||
|
} => do_create(font_dir, dest, str_to_encoding(&encoding)),
|
||||||
|
Command::Split { index, font_dir } => do_split(index, font_dir),
|
||||||
|
Command::SplitAndCreate {
|
||||||
|
index,
|
||||||
|
font_dir,
|
||||||
|
encoding,
|
||||||
|
dest,
|
||||||
|
} => {
|
||||||
|
do_split(index, &font_dir);
|
||||||
|
do_create(&font_dir, dest, str_to_encoding(&encoding));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
66
src/sff.rs
66
src/sff.rs
|
|
@ -58,7 +58,17 @@ impl Encoding {
|
||||||
fn compress(self, input: &[u8]) -> Vec<u8> {
|
fn compress(self, input: &[u8]) -> Vec<u8> {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
match self {
|
match self {
|
||||||
Encoding::BitPerPix1 => todo!(),
|
Encoding::BitPerPix1 => {
|
||||||
|
assert!(input.len() % 8 == 0); // TODO not strictly necessary
|
||||||
|
for c in 0..input.len() / 8 {
|
||||||
|
let mut byte = 0u8;
|
||||||
|
for i in 0..8 {
|
||||||
|
let piece = input[(c << 3) + i] >> 7;
|
||||||
|
byte |= piece << (7 - i);
|
||||||
|
}
|
||||||
|
out.push(byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
Encoding::BitPerPix2 => todo!(),
|
Encoding::BitPerPix2 => todo!(),
|
||||||
Encoding::BitPerPix4 => {
|
Encoding::BitPerPix4 => {
|
||||||
assert!(input.len() % 2 == 0); // TODO not strictly necessary
|
assert!(input.len() % 2 == 0); // TODO not strictly necessary
|
||||||
|
|
@ -88,7 +98,7 @@ fn get_u32(input: &[u8], byte_offset: usize) -> u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FileDesc<'a> {
|
pub struct FileDesc<'a> {
|
||||||
input: &'a [u8],
|
input: &'a [u8],
|
||||||
char_width: usize,
|
char_width: usize,
|
||||||
char_height: usize,
|
char_height: usize,
|
||||||
|
|
@ -96,6 +106,9 @@ struct FileDesc<'a> {
|
||||||
tables: Vec<Table>,
|
tables: Vec<Table>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct GlyphOffset(u32);
|
||||||
|
|
||||||
impl<'a> FileDesc<'a> {
|
impl<'a> FileDesc<'a> {
|
||||||
fn bytes_per_codepoint(&self) -> usize {
|
fn bytes_per_codepoint(&self) -> usize {
|
||||||
let px_per_codepoint = self.char_width * self.char_height;
|
let px_per_codepoint = self.char_width * self.char_height;
|
||||||
|
|
@ -107,7 +120,7 @@ impl<'a> FileDesc<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_codepoint(&self, codepoint: u32) -> Option<&[u8]> {
|
pub fn find_codepoint(&self, codepoint: u32) -> Option<GlyphOffset> {
|
||||||
self.tables
|
self.tables
|
||||||
.iter()
|
.iter()
|
||||||
.find(|tab| {
|
.find(|tab| {
|
||||||
|
|
@ -117,26 +130,55 @@ impl<'a> FileDesc<'a> {
|
||||||
.map(|tab| {
|
.map(|tab| {
|
||||||
let off = tab.offset as usize
|
let off = tab.offset as usize
|
||||||
+ (codepoint - tab.first_codepoint) as usize * self.bytes_per_codepoint();
|
+ (codepoint - tab.first_codepoint) as usize * self.bytes_per_codepoint();
|
||||||
&self.input[off..off + self.bytes_per_codepoint()]
|
GlyphOffset(off as u32)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// input should be result of find_codepoint here
|
// returns the unscaled pixel value!
|
||||||
fn get_pixel_value(&self, input: &[u8], row: u8, col: u8) -> Option<u8> {
|
pub fn get_pixel_value_raw(&self, off: GlyphOffset, row: usize, col: usize) -> u8 {
|
||||||
if row as usize >= self.char_height || col as usize >= self.char_width {
|
assert!(row < self.char_height);
|
||||||
return None;
|
assert!(col < self.char_width);
|
||||||
}
|
let px_index = row * self.char_width + col;
|
||||||
let px_index = row as usize * self.char_width + col as usize;
|
|
||||||
let Access {
|
let Access {
|
||||||
byte_index,
|
byte_index,
|
||||||
shift,
|
shift,
|
||||||
mask,
|
mask,
|
||||||
} = self.encoding.access_from_index(px_index);
|
} = self.encoding.access_from_index(px_index);
|
||||||
Some((input[byte_index] >> shift) & mask)
|
(self.input[off.0 as usize + byte_index] >> shift) & mask
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pixel_value_scaled(&self, off: GlyphOffset, row: usize, col: usize) -> u8 {
|
||||||
|
let raw = self.get_pixel_value_raw(off, row, col);
|
||||||
|
match self.encoding {
|
||||||
|
Encoding::BitPerPix1 => raw * 255,
|
||||||
|
Encoding::BitPerPix2 => (raw as usize * 255 / 3) as u8,
|
||||||
|
Encoding::BitPerPix4 => (raw as usize * 255 / 15) as u8,
|
||||||
|
Encoding::BitPerPix8 => raw,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(input: &[u8]) -> FileDesc<'_> {
|
pub fn print_symbol(&self, off: GlyphOffset) {
|
||||||
|
println!("warning: assuming dark mode console");
|
||||||
|
let p100 = '█';
|
||||||
|
let p75 = '▓';
|
||||||
|
let p50 = '▒';
|
||||||
|
let p25 = '░';
|
||||||
|
let p0 = ' ';
|
||||||
|
let chars = [p0, p25, p50, p75, p100];
|
||||||
|
|
||||||
|
for row in 0..self.char_height {
|
||||||
|
for col in 0..self.char_width {
|
||||||
|
let value = self.get_pixel_value_scaled(off, row, col);
|
||||||
|
// map 0..=255 to 0..=4
|
||||||
|
let c = chars[value as usize * 4 / 255];
|
||||||
|
print!("{}{}", c, c);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(input: &[u8]) -> FileDesc<'_> {
|
||||||
if input[0] != b's' || input[1] != b'f' || input[2] != b'f' || input[3] != b'\0' {
|
if input[0] != b's' || input[1] != b'f' || input[2] != b'f' || input[3] != b'\0' {
|
||||||
panic!("invalid header magic");
|
panic!("invalid header magic");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue