Rustで.ttcファイルを1つ以上の.ttfファイルへ変換しよう!
Rustのeguiで日本語を表示するには.ttfファイルを指定する必要が有るのですが、.ttcファイルしかないフォントが多いので、.ttcファイルを1つ以上の.ttfファイルへ変換するアプリケーションを作ってみました。
ただし、.ttfファイルが正しいかどうか確認する方法が分からないので、アプリケーションの動作が正しいかどうか確認できていません。
不具合が有るかもしれないので利用は自己責任でお願いいたします。
Cargo.toml
――――――――――――――――――――
[package]
name = "ttc_to_ttf"
version = "0.1.0"
edition = "2021"
[dependencies]
regex = "1"
eframe = "0.16"
dirs = "4.0"
――――――――――――――――――――
main.rs
――――――――――――――――――――
use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::io::BufWriter;
use std::io::Write;
use regex::Regex;
use eframe::epi::App;
use eframe::egui::CtxRef;
use eframe::epi::Frame;
use eframe::epi::Storage;
use eframe::egui::Vec2;
use eframe::egui::FontDefinitions;
use eframe::egui::FontData;
use eframe::egui::FontFamily;
use eframe::egui::CentralPanel;
use eframe::NativeOptions;
use std::path::PathBuf;
fn ttc_to_ttf(ttc: &str, out_dir: &str) -> Vec<String> {
let mut buf_reader = BufReader::new(File::open(ttc).unwrap());
//.ttcファイルはビッグ エンディアン(ネス)
//TTC Headerを読み込んでいく
let mut byte_array: [u8; 4] = [0; 4];
//4バイトのASCII文字列のTTC Tagを読み込みUTF-8へ変換
//"ttcf"
buf_reader.read(&mut byte_array).unwrap();
//let ttc_tag = String::from_utf8(byte_array.to_vec()).unwrap();
//4バイトのVersionを読み込み16進数表記のUTF-8文字列へ変換
//"00010000"か"00020000"
//"00010000"はTTC Header Version 1.0を意味
//"00020000"はTTC Header Version 2.0を意味
buf_reader.read(&mut byte_array).unwrap();
//let version = byte_array.iter().map(|byte| format!("{:>02x}", byte)).collect::<Vec<String>>().join("");
//4バイトのnumFontsを読み込み整数へ変換
buf_reader.read(&mut byte_array).unwrap();
let num_fonts = u32::from_be_bytes(byte_array);
let mut offset_vec: Vec<u64> = Vec::new();
//numFontsの数だけ、くり返し
for _number in 1..(num_fonts + 1) {
//4バイトの各フォントのデータの開始バイトを読み込みへ整数へ変換
//0バイト目から開始バイトまでのバイト数
buf_reader.read(&mut byte_array).unwrap();
offset_vec.push(u32::from_be_bytes(byte_array) as u64);
}
//TTC Header Version 2.0の場合は、numFontsの後にデジタル署名のTTC Headerが有るが、無視
let max_index = num_fonts - 1;
let font_name = Regex::new(r"^.+[/\\]|.[tT][tT][cC]$").unwrap().replace_all(ttc, "").to_string();
let mut ttf_vec: Vec<String> = Vec::new();
//numFontsの数だけ、くり返し
for index in 0..num_fonts {
let mut byte_vec: Vec<u8>;
let current_index = index as usize;
buf_reader.seek(SeekFrom::Start(offset_vec[current_index])).unwrap();
if index == max_index {
byte_vec = Vec::new();
buf_reader.read_to_end(&mut byte_vec).unwrap();
} else {
let next_index = (index + 1) as usize;
let size = (offset_vec[next_index] - offset_vec[current_index]) as usize;
byte_vec = vec![0; size];
buf_reader.read(&mut byte_vec).unwrap();
}
let ttf = format!("{}{}{}.ttf", out_dir, font_name, (index + 1));
let mut buf_writer = BufWriter::new(File::create(&ttf).unwrap());
buf_writer.write(&byte_vec).unwrap();
buf_writer.flush().unwrap();
ttf_vec.push(ttf);
}
return ttf_vec;
}
struct AppImpl {
ttc: String,
out_dir: String,
message: String,
}
impl App for AppImpl {
//ウィンドウのタイトルなどに利用されます。
fn name(&self) -> &str {
return ".ttcファイルを1つ以上の.ttfファイルに変換";
}
//描画の前に1回だけ起動されます。
fn setup(&mut self, ctx: &CtxRef, _frame: &Frame, _storage: Option<&dyn Storage>) {
//日本語のフォントを設定
//.ttfか.otf
let mut font_definitions = FontDefinitions::default();
font_definitions.font_data.insert(
"ja".to_owned(),
FontData::from_static(include_bytes!("/usr/share/fonts/truetype/takao-gothic/TakaoPGothic.ttf"))
);
font_definitions.fonts_for_family.get_mut(&FontFamily::Proportional).unwrap().insert(0, "ja".to_owned());
font_definitions.fonts_for_family.get_mut(&FontFamily::Monospace).unwrap().insert(0, "ja".to_owned());
ctx.set_fonts(font_definitions);
//ウィンドウのサイズを設定
_frame.set_window_size(Vec2::new(800.0, 500.0));
}
//描画のたびに起動されます。
fn update(&mut self, ctx: &CtxRef, _frame: &Frame) {
//拡大
ctx.set_pixels_per_point(1.5);
CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label(".ttcファイル");
ui.text_edit_singleline(&mut self.ttc);
});
ui.horizontal(|ui| {
ui.label("書き込みディレクトリ");
ui.text_edit_singleline(&mut self.out_dir);
});
if ui.button(".ttcファイルを1つ以上の.ttfファイルに変換").clicked() {
let ttc = self.ttc.clone();
let out_dir = self.out_dir.clone();
self.message = String::from("");
if ttc.is_empty() {
self.message = String::from(".ttcファイルを記入してください。");
return;
}
if out_dir.is_empty() {
self.message = String::from("書き込みディレクトリを記入してください。");
return;
}
if PathBuf::from(&ttc).is_file() == false {
self.message = String::from(".ttcファイルに存在するファイルを記入してください。");
return;
}
if PathBuf::from(&out_dir).is_dir() == false {
self.message = String::from("書き込みディレクトリに存在するディレクトリを記入してください。");
return;
}
ttc_to_ttf(&ttc, &out_dir);
self.message = String::from(".ttcファイルから1つ以上の.ttfファイルへの変換が完了しました。");
}
ui.label(&self.message);
});
}
}
fn main() {
eframe::run_native(
Box::new(
AppImpl{
ttc: dirs::desktop_dir().unwrap().to_str().unwrap().to_string() + "/",
out_dir: dirs::desktop_dir().unwrap().to_str().unwrap().to_string() + "/",
message: String::from(""),
}
),
NativeOptions::default()
);
}
――――――――――――――――――――
コピペする場合は、2文字の全角空白を4文字の半角空白に、/usr/share/fonts/truetype/takao-gothic/TakaoPGothic.ttfを適切な日本語のフォントのファイルのパスに、置換してください。
.ttcファイルを1つ以上の.ttfファイルへ変換しよう! エリファス1810 @Eliphas1810
★で称える
この小説が面白かったら★をつけてください。おすすめレビューも書けます。
カクヨムを、もっと楽しもう
カクヨムにユーザー登録すると、この小説を他の読者へ★やレビューでおすすめできます。気になる小説や作者の更新チェックに便利なフォロー機能もお試しください。
新規ユーザー登録(無料)簡単に登録できます
この小説のタグ
同じコレクションの次の小説
関連小説
アンドロイド スマホのアプリを作ろう!/エリファス1810
★0 エッセイ・ノンフィクション 完結済 10話
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます