diff --git a/.github/workflows/linux.yaml b/.github/workflows/linux.yaml
index 3599ba5..740971b 100644
--- a/.github/workflows/linux.yaml
+++ b/.github/workflows/linux.yaml
@@ -33,5 +33,5 @@ jobs:
- name: Run the application
run: |
- ./target/release/fontmanager
+ ./target/release/display-fonts
shell: bash
\ No newline at end of file
diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml
index 950bf86..d3ee8fe 100644
--- a/.github/workflows/macos.yaml
+++ b/.github/workflows/macos.yaml
@@ -32,6 +32,5 @@ jobs:
- name: Run the application
run: |
- ./target/release/fontmanager
+ ./target/release/display-fonts
shell: bash
- if: ${{ matrix.os != 'windows-latest' }}
diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml
index 05aff3d..9f9f815 100644
--- a/.github/workflows/windows.yaml
+++ b/.github/workflows/windows.yaml
@@ -32,5 +32,5 @@ jobs:
- name: Run the application (Windows)
run: |
- .\target\release\fontmanager.exe
+ .\target\release\display-fonts.exe
shell: cmd
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index d4d3af8..15019ad 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,15 @@ name = "fontmanager"
version = "0.1.0"
edition = "2021"
+[[bin]]
+name = "display-fonts"
+path = "src/bin/display-fonts.rs"
+
+[[bin]]
+name = "generate-svg"
+path = "src/bin/generate-svg.rs"
+
+
[dependencies]
colog = "1.3.0"
font-kit = "0.14.2"
diff --git a/src/bin/display-fonts.rs b/src/bin/display-fonts.rs
new file mode 100644
index 0000000..d2f2eff
--- /dev/null
+++ b/src/bin/display-fonts.rs
@@ -0,0 +1,34 @@
+use prettytable::{Attr, Cell, Row, Table};
+use fontmanager::font_manager::FontManager;
+
+fn main() {
+ colog::init();
+
+ let manager = FontManager::new();
+
+ let mut table = Table::new();
+ table.set_format(*prettytable::format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
+ table.set_titles(Row::new(vec![
+ Cell::new("Family").with_style(Attr::Bold),
+ Cell::new("Style").with_style(Attr::Bold),
+ Cell::new("Weight").with_style(Attr::Bold),
+ Cell::new("Stretch").with_style(Attr::Bold),
+ Cell::new("Monospaced").with_style(Attr::Bold),
+ Cell::new("Path").with_style(Attr::Bold),
+ Cell::new("Index").with_style(Attr::Bold),
+ ]));
+
+ for info in manager.available_fonts() {
+ table.add_row(Row::new(vec![
+ Cell::new(&info.family),
+ Cell::new(&format!("{}", &info.style)),
+ Cell::new(&info.weight.to_string()),
+ Cell::new(&info.stretch.to_string()),
+ Cell::new(&info.monospaced.to_string()),
+ Cell::new(&info.path.to_str().unwrap()),
+ Cell::new(&info.index.unwrap_or(0).to_string()),
+ ]));
+ }
+
+ table.printstd();
+}
\ No newline at end of file
diff --git a/src/bin/generate-svg.rs b/src/bin/generate-svg.rs
new file mode 100644
index 0000000..94d6d6b
--- /dev/null
+++ b/src/bin/generate-svg.rs
@@ -0,0 +1,108 @@
+use freetype::Face;
+use fontmanager::font_manager::{FontManager, FontStyle};
+
+// const TEST_STRING1: &str = "A B C D E\n \u{EA84} a b c d e";
+
+const TEST_STRING: &str = r"A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+a b c d e f g h i j k l m n o p q r s t u v w x y z
+0 1 2 3 4 5 6 7 8 9 ( ) $ % @ & ¢ € [ \ ] ^ _ ` { | } ~ < > # = + - * / : ; , . ! ?
+¡ ¿ ˆ ˜ ¨ ´ ` ˘ ˙ ˚ ˝ ˛ ˇ ˆ ˇ ˘ ˙ ˚ ˛ ˜ ˝ ˇ ˘ ˙ ˚ ˛ ˜ ˝ ˇ ˘ ˙ ˚ ˛ ˜ ˝
+À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý Þ ß
+à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ
+Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ
+Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĩ ĩ Ī ī Ĭ ĭ Į į İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ
+Ŀ ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ
+Ş ş Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž
+ſ ƀ Ɓ Ƃ ƃ Ƅ ƅ Ɔ Ƈ ƈ Ɖ Ɗ Ƌ ƌ ƍ Ǝ Ə Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ
+Ơ ơ Ƣ ƣ Ƥ ƥ Ʀ Ƨ ƨ Ʃ ƪ ƫ Ƭ ƭ Ʈ Ư ư Ʊ Ʋ Ƴ ƴ Ƶ ƶ Ʒ Ƹ ƹ ƺ ƻ Ƽ ƽ ƾ ƿ
+ǀ ǁ ǂ ǃ DŽ Dž dž LJ Lj lj NJ Nj nj Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ Ǘ ǘ Ǚ ǚ Ǜ ǜ ǝ
+Ǟ ǟ Ǡ ǡ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ ǰ DZ Dz dz Ǵ ǵ Ƕ Ƿ Ǹ ǹ Ǻ ǻ
+Ǽ ǽ Ǿ ǿ Ȁ ȁ Ȃ ȃ Ȅ ȅ Ȇ ȇ Ȉ ȉ Ȋ ȋ Ȍ ȍ Ȏ ȏ Ȑ ȑ Ȓ ȓ Ȕ ȕ Ȗ ȗ Ș ș Ț ț
+Ȝ ȝ Ȟ ȟ Ƞ ȡ Ȣ ȣ Ȥ ȥ Ȧ ȧ Ȩ ȩ Ȫ ȫ Ȭ ȭ Ȯ ȯ Ȱ ȱ Ȳ ȳ ȴ ȵ ȶ ȷ ȸ ȹ Ⱥ
+Ȼ ȼ Ƚ Ⱦ ȿ ɀ Ɂ ɂ Ƀ Ʉ Ʌ Ɇ ɇ Ɉ ɉ Ɋ ɋ Ɍ ɍ Ɏ ɏ ɐ ɑ ɒ ɓ ɔ ɕ ɖ ɗ ɘ ə ɚ
+ɜ ɝ ɞ ɟ ɠ ɡ ɢ ɣ ɤ ɥ ɦ ɧ ɨ ɩ ɪ ɫ ɬ ɭ ɮ ɯ ɰ ɱ ɲ ɳ ɴ ɵ ɶ ɷ ɸ ɹ
+Hello world from the Gosub FontManager system!
+";
+
+fn main() {
+ colog::init();
+
+ let manager = FontManager::new();
+
+ let info = manager.find(vec!["Nimbus Sans Narrow"], FontStyle::Normal);
+ let face = manager.load(info.unwrap()).unwrap();
+ char_to_svg(face, TEST_STRING);
+}
+
+fn char_to_svg(face: Face, content: &str) {
+ face.set_char_size(10 * 64, 0, 10, 0).unwrap();
+
+ println!("");
+ println!("");
+ println!("");
+}
+
+
+fn draw_curve(curve: freetype::outline::Curve) {
+ match curve {
+ freetype::outline::Curve::Line(pt) => println!("L {} {}", pt.x, -pt.y),
+ freetype::outline::Curve::Bezier2(pt1, pt2) => {
+ println!("Q {} {} {} {}", pt1.x, -pt1.y, pt2.x, -pt2.y)
+ }
+ freetype::outline::Curve::Bezier3(pt1, pt2, pt3) => println!(
+ "C {} {} {} {} {} {}",
+ pt1.x, -pt1.y, pt2.x, -pt2.y, pt3.x, -pt3.y
+ ),
+ }
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/font_manager.rs
similarity index 57%
rename from src/main.rs
rename to src/font_manager.rs
index dc7a207..61cf5f2 100644
--- a/src/main.rs
+++ b/src/font_manager.rs
@@ -9,10 +9,12 @@ use font_kit::properties::Properties;
use font_kit::source::SystemSource;
use freetype::{Face, Library};
use log::info;
-use prettytable::{Attr, Cell, Row, Table};
+
+#[allow(dead_code)]
+const LOG_TARGET: &str = "font-manager";
#[derive(Clone, Debug)]
-enum FontStyle {
+pub enum FontStyle {
Normal,
Italic,
Oblique,
@@ -29,28 +31,37 @@ impl Display for FontStyle {
}
#[derive(Clone, Debug)]
-struct FontInfo {
+pub struct FontInfo {
+ /// Family name of the font (e.g. "Arial")
pub family: String,
+ /// Style of the font
pub style: FontStyle,
+ /// Weight (400 normal, 700 bold)
pub weight: f32,
+ /// Stretch (1.0 normal, < 1.0 condensed)
pub stretch: f32,
+ /// Font is monospaced
pub monospaced: bool,
-
+ /// Path to the font file
pub path: PathBuf,
+ /// Index of the face in the font-file
pub index: Option,
}
-struct FontManager {
+#[allow(unused)]
+pub struct FontManager {
source: SystemSource,
ft_library: Library,
- info: Vec,
+ /// Vec of all font-info structures found
+ font_info: Vec,
+ /// List of all font handles
handles: Vec,
/// Cache of font faces that are loaded through freetype
face_cache: Arc>>,
}
impl FontManager {
- fn new() -> Self {
+ pub fn new() -> Self {
let library = Library::init().expect("unable to init freetype library");
let source = SystemSource::new();
@@ -66,12 +77,21 @@ impl FontManager {
FontManager {
source,
ft_library: library,
- info: font_info,
+ font_info: font_info,
handles,
face_cache: Arc::new(Mutex::new(HashMap::new())),
}
}
+ /// Returns all available fonts
+ pub fn available_fonts(&self) -> Vec {
+ let mut fonts = self.font_info.clone();
+ fonts.sort_by_key(|fi| fi.family.clone());
+
+ fonts
+ }
+
+ /// Returns the first font that matches the given family and style
pub fn find(&self, families: Vec<&str>, style: FontStyle) -> Option {
let mut f = Vec::new();
for family in families {
@@ -100,10 +120,11 @@ impl FontManager {
}
}
+ /// Load the font face for the given font info
pub fn load(&self, font_info: FontInfo) -> Result {
let cache_key = format!("{}:{}", font_info.family, font_info.style);
if let Some(font_face) = self.face_cache.lock().unwrap().get(&cache_key) {
- info!(target: "font", "Font loaded from cache: {}", cache_key);
+ info!(target: LOG_TARGET, "Font loaded from cache: {}", cache_key);
// @todo: Can we somehow return the face within the cache so we don't need to copy it?
return Ok(font_face.clone());
}
@@ -116,15 +137,14 @@ impl FontManager {
}
};
-
- info!(target: "font",
+ info!(target: LOG_TARGET,
"Font loaded: {} (number of glyphs: {})",
face.family_name().unwrap_or("Unknown".parse()?),
face.num_glyphs()
);
// @todo: same here.. we use a clone to store into cache, but can we just use the data we loaded through freetype?
- info!(target: "font", "Caching font face: {}", cache_key);
+ info!(target: LOG_TARGET, "Caching font face: {}", cache_key);
self.face_cache.lock().unwrap().insert(cache_key.clone(), face.clone());
Ok(face)
}
@@ -159,70 +179,3 @@ impl FontManager {
}
}
}
-
-const TEST_STRING: &str = r"A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
-a b c d e f g h i j k l m n o p q r s t u v w x y z
-0 1 2 3 4 5 6 7 8 9 ( ) $ % @ & ¢ € [ \ ] ^ _ ` { | } ~ < > # = + - * / : ; , . ! ?
-¡ ¿ ˆ ˜ ¨ ´ ` ˘ ˙ ˚ ˝ ˛ ˇ ˆ ˇ ˘ ˙ ˚ ˛ ˜ ˝ ˇ ˘ ˙ ˚ ˛ ˜ ˝ ˇ ˘ ˙ ˚ ˛ ˜ ˝
-À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý Þ ß
-à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ
-Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ
-Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĩ ĩ Ī ī Ĭ ĭ Į į İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ
-Ŀ ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ
-Ş ş Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž
-ſ ƀ Ɓ Ƃ ƃ Ƅ ƅ Ɔ Ƈ ƈ Ɖ Ɗ Ƌ ƌ ƍ Ǝ Ə Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ
-Ơ ơ Ƣ ƣ Ƥ ƥ Ʀ Ƨ ƨ Ʃ ƪ ƫ Ƭ ƭ Ʈ Ư ư Ʊ Ʋ Ƴ ƴ Ƶ ƶ Ʒ Ƹ ƹ ƺ ƻ Ƽ ƽ ƾ ƿ
-ǀ ǁ ǂ ǃ DŽ Dž dž LJ Lj lj NJ Nj nj Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ Ǘ ǘ Ǚ ǚ Ǜ ǜ ǝ
-Ǟ ǟ Ǡ ǡ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ ǰ DZ Dz dz Ǵ ǵ Ƕ Ƿ Ǹ ǹ Ǻ ǻ
-Ǽ ǽ Ǿ ǿ Ȁ ȁ Ȃ ȃ Ȅ ȅ Ȇ ȇ Ȉ ȉ Ȋ ȋ Ȍ ȍ Ȏ ȏ Ȑ ȑ Ȓ ȓ Ȕ ȕ Ȗ ȗ Ș ș Ț ț
-Ȝ ȝ Ȟ ȟ Ƞ ȡ Ȣ ȣ Ȥ ȥ Ȧ ȧ Ȩ ȩ Ȫ ȫ Ȭ ȭ Ȯ ȯ Ȱ ȱ Ȳ ȳ ȴ ȵ ȶ ȷ ȸ ȹ Ⱥ
-Ȼ ȼ Ƚ Ⱦ ȿ ɀ Ɂ ɂ Ƀ Ʉ Ʌ Ɇ ɇ Ɉ ɉ Ɋ ɋ Ɍ ɍ Ɏ ɏ ɐ ɑ ɒ ɓ ɔ ɕ ɖ ɗ ɘ ə ɚ
-ɛ ɜ ɝ ɞ ɟ ɠ ɡ ɢ ɣ ɤ ɥ ɦ ɧ ɨ ɩ ɪ ɫ ɬ ɭ ɮ ɯ ɰ ɱ ɲ ɳ ɴ ɵ ɶ ɷ ɸ ɹ
-Hello world from the Gosub FontManager system!
-";
-
-fn main() {
- colog::init();
-
- let manager = FontManager::new();
-
- print_font_table(&manager);
-
- let info = manager.find(vec!["arial"], FontStyle::Normal);
- dbg!(&info);
- let info = manager.find(vec!["serif"], FontStyle::Normal);
- dbg!(&info);
- let info = manager.find(vec!["monospace"], FontStyle::Normal);
- dbg!(&info);
-
- char_to_svg(&manager, "Arial", "Regular", '');
-}
-
-fn print_font_table(manager: &FontManager) {
- let mut table = Table::new();
- table.set_format(*prettytable::format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
- table.set_titles(Row::new(vec![
- Cell::new("PostScript Name").with_style(Attr::Bold),
- Cell::new("Name").with_style(Attr::Bold),
- Cell::new("Family").with_style(Attr::Bold),
- Cell::new("Path").with_style(Attr::Bold),
- Cell::new("Monospaced").with_style(Attr::Bold),
- Cell::new("Style").with_style(Attr::Bold),
- Cell::new("Weight").with_style(Attr::Bold),
- Cell::new("Stretch").with_style(Attr::Bold),
- ]));
-
- for info in manager.info.iter() {
- table.add_row(Row::new(vec![
- Cell::new(&info.family),
- Cell::new(&format!("{}", &info.style)),
- Cell::new(&info.weight.to_string()),
- Cell::new(&info.stretch.to_string()),
- Cell::new(&info.monospaced.to_string()),
- Cell::new(&info.path.to_str().unwrap()),
- Cell::new(&info.index.unwrap_or(0).to_string()),
- ]));
- }
-
- table.printstd();
-}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..78c3f4b
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1 @@
+pub mod font_manager;
\ No newline at end of file
diff --git a/src/test.rs b/src/test.rs
deleted file mode 100644
index 7a1d238..0000000
--- a/src/test.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-// We need to deal with the following:
-// - fontconfig: what about Windows and MacOS, they use different systems
-// - can we somehow not copy fontfaces but use references or something?
-// - deal when font is not found (it now defaults to a certain font?)
-
-fn blaatmain() {
- colog::init();
-
- let fm = FontManager::new();
- let f = fm.find("Arial", Some("Regular")).expect("unable to find font");
- let face = fm.load(f).expect("unable to load font");
- let f = fm.find("Arial", Some("Regular")).expect("unable to find font");
- let _face = fm.load(f).expect("unable to load font");
- let f = fm.find("Arial", Some("Bold")).expect("unable to find font");
- let _face = fm.load(f).expect("unable to load font");
- let f = fm.find("Arial", Some("Regular")).expect("unable to find font");
- let _face = fm.load(f).expect("unable to load font");
- let f = fm.find("Monospace", Some("Bold")).expect("unable to find font");
- let face = fm.load(f).expect("unable to load font");
-
- face.set_char_size(40 * 64, 0, 50, 0).unwrap();
- face.load_char('@' as usize, freetype::face::LoadFlag::NO_SCALE).unwrap();
-
- let glyph = face.glyph();
- let metrics = glyph.metrics();
- let xmin = metrics.horiBearingX - 5;
- let width = metrics.width + 10;
- let ymin = -metrics.horiBearingY - 5;
- let height = metrics.height + 10;
- let outline = glyph.outline().unwrap();
-
- println!("");
- println!("");
- println!(
- "");
-}
-
-fn draw_curve(curve: freetype::outline::Curve) {
- match curve {
- freetype::outline::Curve::Line(pt) => println!("L {} {}", pt.x, -pt.y),
- freetype::outline::Curve::Bezier2(pt1, pt2) => {
- println!("Q {} {} {} {}", pt1.x, -pt1.y, pt2.x, -pt2.y)
- }
- freetype::outline::Curve::Bezier3(pt1, pt2, pt3) => println!(
- "C {} {} {} {} {} {}",
- pt1.x, -pt1.y, pt2.x, -pt2.y, pt3.x, -pt3.y
- ),
- }
-}
\ No newline at end of file