From df94c45f5160a6031d4874690b608029f5cd04ed Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 22 Jan 2026 14:28:32 -0600 Subject: [PATCH] Inital commit --- .gitignore | 1 + Cargo.lock | 25 +++ Cargo.toml | 7 + src/bit_reader.rs | 64 +++++++ src/main.rs | 257 +++++++++++++++++++++++++++ src/u8g2_font_04b_03_tr.u8g2font | Bin 0 -> 740 bytes src/u8g2_font_8x13_tr.u8g2font | Bin 0 -> 1127 bytes src/u8g2_font_logisoso24_tr.u8g2font | Bin 0 -> 2410 bytes 8 files changed, 354 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/bit_reader.rs create mode 100644 src/main.rs create mode 100644 src/u8g2_font_04b_03_tr.u8g2font create mode 100644 src/u8g2_font_8x13_tr.u8g2font create mode 100644 src/u8g2_font_logisoso24_tr.u8g2font diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..be1c5c7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitreader" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886559b1e163d56c765bc3a985febb4eee8009f625244511d8ee3c432e08c066" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "u8g2-font-reader" +version = "0.1.0" +dependencies = [ + "bitreader", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a3c7a78 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "u8g2-font-reader" +version = "0.1.0" +edition = "2024" + +[dependencies] +bitreader = "0.3.11" diff --git a/src/bit_reader.rs b/src/bit_reader.rs new file mode 100644 index 0000000..bb48b83 --- /dev/null +++ b/src/bit_reader.rs @@ -0,0 +1,64 @@ + + +#[derive(Debug)] +pub struct ReverseBitVec<'a> { + data: &'a[u8], + bit_pointer: usize, +} + +impl<'a> ReverseBitVec<'a> { + pub const fn new(data: &'a[u8]) -> Self { + let bit_pointer = data.len() * 8; + ReverseBitVec { data, bit_pointer} + } + + pub fn read_u8(&mut self, bits: u8) -> Option { + let byte = (self.bit_pointer-1)/8; + let bit_in_byte = (8 - (self.bit_pointer % 8)) % 8; + let mask:u16 = ((1<> bit_in_byte; + + let out_u8 = out_u16.to_be_bytes()[1]; + + self.bit_pointer -= bits as usize; + + Some(out_u8) + } +} + +#[cfg(test)] +mod test { + use super::*; + + const DATA: [u8;3] = [0b0101_0101, 0b1100_1100, 0b0000_1111]; + + #[test] + fn full_aligned_byte() { + let mut info = ReverseBitVec::new(&DATA); + + let test = info.read_u8(8); + println!("{:08b}", test.unwrap()); + assert_eq!(Some(0b0000_1111), test); + } + + #[test] + fn partial_aligned_byte() { + let mut info = ReverseBitVec::new(&DATA); + let _ = info.read_u8(8); + let test = info.read_u8(4); + println!("{:08b}", test.unwrap()); + assert_eq!(Some(0b0000_1100), test); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..4d4892c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,257 @@ +use std::fmt::Display; + +mod bit_reader; + +fn main() { + let font_file = include_bytes!("u8g2_font_logisoso24_tr.u8g2font"); + + let header_bytes = &font_file[0..23]; + let mut data_bytes = &font_file[23..]; + + let header = FontHeader { + glyphs: header_bytes[0], + box_mode: header_bytes[1], + zero_bit_width: header_bytes[2], + one_bit_width: header_bytes[3], + bits_glyph_bitmap_width: header_bytes[4], + bits_glyph_bitmap_height: header_bytes[5], + bits_glyph_bitmap_x_offset: header_bytes[6], + bits_glyph_bitmap_y_offset: header_bytes[7], + bits_glyph_delta: header_bytes[8], + bound_box_width: header_bytes[9], + bound_box_height: header_bytes[10], + bound_box_x: header_bytes[11], + bound_box_y: header_bytes[12], + ascent_capital_a: header_bytes[13], + descent_lowercase_g: header_bytes[14], + paren_ascent: header_bytes[15], + paren_descent: header_bytes[16], + offset_of_capital_a: u16::from_be_bytes([header_bytes[17], header_bytes[18]]), + offset_of_lowercase_a: u16::from_be_bytes([header_bytes[19], header_bytes[20]]), + offset_of_0x0100: u16::from_be_bytes([header_bytes[21], header_bytes[22]]), + }; + + println!("{:?}", header); + + let mut bitvec: Vec = Vec::new(); + let mut glyphs: Vec = Vec::new(); + + for i in 0..header.glyphs { + let glyph = &data_bytes[0..2]; + + let unicode = glyph[0]; + let bytes = glyph[1]; + + let bitmap = &data_bytes[2..bytes as usize]; + for j in bitmap.iter().rev() { + bitvec.push(*j); + } + + /*print!("[ "); + for j in bitvec.iter() { + print!("{:08b} ", j) + } + println!("]");*/ + + let mut bitmap_bits = bit_reader::ReverseBitVec::new(&bitvec); + let glyph_width = bitmap_bits.read_u8(header.bits_glyph_bitmap_width).unwrap(); + let glyph_height = bitmap_bits.read_u8(header.bits_glyph_bitmap_height).unwrap(); + let glyph_x = bitmap_bits.read_u8(header.bits_glyph_bitmap_x_offset).unwrap(); + let glyph_y = bitmap_bits.read_u8(header.bits_glyph_bitmap_y_offset).unwrap(); + let glyph_d = bitmap_bits.read_u8(header.bits_glyph_delta).unwrap(); + + //println!("w: {:08b}, h: {:08b}, x: {:08b}, y: {:08b}, d: {:08b}", glyph_width, glyph_height, glyph_x, glyph_y, glyph_d); + + let glyph_x = glyph_x as i8 - (1<<(header.bits_glyph_bitmap_x_offset-1)); + let glyph_y = glyph_y as i8 - (1<<(header.bits_glyph_bitmap_y_offset-1)); + let glyph_d = glyph_d as i8 - (1<<(header.bits_glyph_delta-1)); + + let target_bitmap_size = glyph_width as u16 * glyph_height as u16; + let mut current_bitmap_size = 0_u16; + + let mut bitmap_entries = Vec::new(); + + loop { + //println!("Bitmap current size: {} target: {}", current_bitmap_size, target_bitmap_size); + if current_bitmap_size >= target_bitmap_size {break;} + let zeros = bitmap_bits.read_u8(header.zero_bit_width).unwrap(); + let ones = bitmap_bits.read_u8(header.one_bit_width).unwrap(); + let mut repeat = 0_u8; + + while bitmap_bits.read_u8(1).unwrap() != 0 { + repeat += 1; + } + let out_bitmap = BitmapEntry { + zeros, + ones, + repeat, + }; + + //println!("{:?}", out_bitmap); + current_bitmap_size += out_bitmap.length(); + bitmap_entries.push(out_bitmap); + } + + let finished_glyph = Glyph { + unicode, + delta: bytes, + glyph_width, + glyph_height, + glyph_x, + glyph_y, + glyph_d, + glyph_data: bitmap_entries, + }; + + //println!("{:?}", finished_glyph); + glyphs.push(finished_glyph); + + bitvec.clear(); + data_bytes = &data_bytes[bytes as usize..]; + } + + let mut bdf_file = String::new(); + + bdf_file.push_str("STARTFONT 2.1\n"); + bdf_file.push_str("u8g2_font_converted\n"); + bdf_file.push_str("SIZE 24 72 72\n"); + bdf_file.push_str(&format!("CHARS {}\n", header.glyphs)); + + for i in glyphs.iter() { + bdf_file.push_str(&format!("STARTCHAR {}\n", i.unicode as char)); + bdf_file.push_str(&format!("ENCODING {}\n", i.unicode)); + + let mut decoded_bits = Vec::new(); + + for j in i.glyph_data.iter() { + let mut tempvec = Vec::new(); + let mut count = j.zeros; + + while count > 0 { + tempvec.push(false); + count -= 1; + } + count = j.ones; + while count > 0 { + tempvec.push(true); + count -= 1; + } + count = j.repeat + 1; + while count > 0 { + decoded_bits.append(&mut tempvec.clone()); + count -= 1; + } + } + + let mut bdf_bitmap: Vec> = Vec::new(); + + while !decoded_bits.is_empty() { + for j in decoded_bits.iter().by_ref().take(i.glyph_width as usize) { + + } + } + } + + bdf_file.push_str("ENDFONT"); + +} + +#[derive(Debug)] +struct FontHeader { + glyphs: u8, + box_mode: u8, + zero_bit_width: u8, + one_bit_width: u8, + bits_glyph_bitmap_width: u8, + bits_glyph_bitmap_height: u8, + bits_glyph_bitmap_x_offset: u8, + bits_glyph_bitmap_y_offset: u8, + bits_glyph_delta: u8, + bound_box_width: u8, + bound_box_height: u8, + bound_box_x: u8, + bound_box_y: u8, + ascent_capital_a: u8, + descent_lowercase_g: u8, + paren_ascent: u8, + paren_descent: u8, + offset_of_capital_a: u16, + offset_of_lowercase_a: u16, + offset_of_0x0100: u16, +} + +#[derive(Debug)] +struct Glyph { + unicode: u8, + delta: u8, + glyph_width: u8, + glyph_height: u8, + glyph_x: i8, + glyph_y: i8, + glyph_d: i8, + glyph_data: Vec, +} + +impl Display for Glyph { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let c = self.unicode as char; + let bytes = self.delta; + let w = self.glyph_width; + let h = self.glyph_height; + let x = self.glyph_x; + let y = self.glyph_y; + let d = self.glyph_d; + + let mut glyph_bits: Vec = Vec::new(); + + let bitmap = for i in self.glyph_data.iter() { + let mut tempvec = Vec::new(); + let mut count = i.zeros; + + while count > 0 { + tempvec.push(false); + count -= 1; + } + count = i.ones; + while count > 0 { + tempvec.push(true); + count -= 1; + } + count = i.repeat + 1; + while count > 0 { + glyph_bits.append(&mut tempvec.clone()); + count -= 1; + } + }; + + let mut out = String::new(); + + for (pos, i) in glyph_bits.iter().enumerate() { + if *i { + out.push('I'); + } else { + out.push('.'); + } + + if (pos+1) % w as usize == 0 { + out.push('\n'); + } + } + + write!(f, "Character: {c}, Data size: {bytes}, size: {w}x{h} offsets X:{x}, Y:{y}, D: {d}\n{out}") + } +} + +#[derive(Debug)] +struct BitmapEntry { + zeros: u8, + ones: u8, + repeat: u8, +} + +impl BitmapEntry { + fn length(&self) -> u16 { + let base = self.zeros + self.ones; + base as u16 * (self.repeat as u16 + 1) + } +} \ No newline at end of file diff --git a/src/u8g2_font_04b_03_tr.u8g2font b/src/u8g2_font_04b_03_tr.u8g2font new file mode 100644 index 0000000000000000000000000000000000000000..086259019ac498948c4073ac303b6c440b43f2ee GIT binary patch literal 740 zcmXX^OHUI~6h1SUAoeYO&K&Y4L%Uhn1>SDT<&76r?YZ(iSP|(uE04 z2x2IS3)4o@A~7P8_yY(@O-u^1Fsxm=BQ9KkXTZBTC+9ogckXxY?E;qNIEE`B0&J6Q z0`Qyp#jYMNsZ&pofMPnyuUp-O>LSUFmW`HjI3;a;86L33SXqiVEt$?tg+YoWRhOL6 zohC&STge9p^ZSfK&}@;3!gpA6oJrV>24pxx)*`yIq}j@uiCbZ+#K_;uQ3~h8a6*}N zGZsE*&U301wjY(Jo4~r8Of<4KDZK3UQ3F(C#WiFr1G|Kbk288WFNW=O)ydXq1w;81 z>(G+-Z}s3LKNVvw=~mnq_|Rg`e35Lb->mj(O4KtMYLA#b{&hI0|I?Z+9Hs{MavGH*KO!rIXfwtWv z56Sw-{x0IN(??{j%F-?P6SQFKLGDeGCm=uapUAD~|hEgBbQ z;IR~o)56jeJ0NKN)&PEwKu}0V96ntLB^>#s9tdO66_NU!)TiXwLBWq3WQH`QLKdD# zv1+s&<%h*xsnV#>s|HrY5yV}YcMuao(ZI^FII@Z!E}?~22S!oMnEU=3o?>&(L&i{~ m=&3bA5^?&5jw30bVxMV)pW_p$b6I#H{1|o1fTv_<2jCxM(bWC` literal 0 HcmV?d00001 diff --git a/src/u8g2_font_8x13_tr.u8g2font b/src/u8g2_font_8x13_tr.u8g2font new file mode 100644 index 0000000000000000000000000000000000000000..a42a4816a25ba0a0bcfceec490e30f58ac52c7b0 GIT binary patch literal 1127 zcmXw(T~HfU7>2+65VFZ`D6wUL1Z`-72~9M`U~ACS>?V|Kk^%vh1eH>PVkot=)mCf0 z>Hs0jNS92eI$JvvGmLdsXPQ~@t`}{ACZ?5N#~JF4&Un+#c>p6+e?8TmQ-t)cB z_nxym1PZxAsi>+_Q}CF0On~gP{E?E~TLmXcQ+0vi7=3fKage*ad!O!Rr||XYKsG** ztpjt-Jz6}`lQr+~)&@y!*>#^5LP_2lx*f5s>!F3ZNgExB&8#n#foD~p4{|cA_D4oE zv)Nd>%0>nm&R)#2X&%!6Wz!;84v)IPY_6!(kyF zfai&B`cdNA2so+xwB5ndp9RtZIG{x+A@4l^Zjy!sXOBFlBSNe^+4=A^+R zaJaH}*(LsQO!+EK%tVA4y{(YG%gDX|we-7lW(8e>(S8SrCPCf1ad++?Tr|MxvdDqh=*rmeK43(v1j*85f=pg}NR&EGCHtNn=< zz1)Rjo(dus4rkNS673J(f)Ihm($KUltm~$^{$De*y91XK)KTo)^B~>DO6&FA6`+5v zkOcH#1}`ypn_rUm>VEbh(2L2Ox#2g6;FR%7B$Wu%_f@joK0i}Fl70=U&eZ*7fY&rg zw)PC_?e$vh7|vT$dG^Ysz!$PNFv3=!*&oTB4Z=VfD4b_wh1TnhQL-Xt8_y|XxWxD` z<8E@02r-=Z;m)o%(RJYt{dor7B1$N*hdX=UR$q;Y_Ulzc)ioZDfnzFugtHElODNi- zQ@wo|IF4JCM%R6leRVKWULdxQx0xZ1B7BhX8zzeSQ3~scX)lF%-$5HhTX5sl{6;6d zTeIR8{K5R#?6f&Fr5wYt<6^7uo@SXAjkO(=JV9=|OU7D5yCVwYI33B6%sRfY48sX@ zPmDLNsbmwngEZ$)Hrx1STSReEvqW=oT;zRi*|-VWo}yOVX!1@ty3q=gT5M}*9}O5z zm&HY1sy$Pod@4#H`B`#>7F@=h@MrX~8ZC^h4qqU{jA#k%Yu9edK2f3nMD;}y-K_Rf#6~R; TpAuJNLRTQC1OVleCjkEfN0^K8 literal 0 HcmV?d00001 diff --git a/src/u8g2_font_logisoso24_tr.u8g2font b/src/u8g2_font_logisoso24_tr.u8g2font new file mode 100644 index 0000000000000000000000000000000000000000..eef2e274e93fb594b636bc9c8c721a564eaeabe5 GIT binary patch literal 2410 zcmZuzZBSEJ8a|MCa{~$FCZP8Q)ZBa^5VmrYfS}fz4=w=_#DLcBwqg=vpwVSnb+u)e z0YaL%37a6cLG38gQmBp}<a2gvL7F&7t$eDtpw=$*l3?8tc^3jlPS=RRQ_xPhWp{ z>*|B*cdJyh{XMJ)nVgfVLpI|{(+pC}28tJ;PtKrR=0pk75Jg26w>P(}?Ov2yS<5V> zl@8+42|V>`4BCl40g8wemFiAV11gs;ZV!CKqU8ii_hf^2`%oCs(!F0eQ549 zjf%87kdM!{E%crxEiUhXHTL*s&=cW_WvQS*JbQQ{6x3P}-+(>#*clCy2A6=4BcL#= zdOz>@=6b0?Ls<5ckRAolN{>915&8sdGrF>A7Hgw?~T^dG$U!cu%iy;>B0>@Gm z)TOSKq$?NxbufSgx`6-sY}IMxVUA zPB%!NLkJRRR>Rv{OaYCpaVNVn1D1*xpl)wG(&UKW1tlw!#s&8)2!#@baX8{dK4OE$ zz*p%&DP#LIz?q^?@^@+NKH)%V1QC#j11z6nPT;rF~&MdfOgEGl8 zrZ;Gw_#EO()5%h4T`#@uR>U=$S=$oMKjVA5}9_s+y_zMh9 zuu=FiwfIUtWymMwErLc9H~mGvvS2a9`D*a!d=uET9A4{+>zyNFg`I~f6DA zNK9iJrqoMEvnd04-PQeMrfXyH-I`7?bR0c@ieCqb0*U^= zMA^nPHaz-cMT383s@bRcfS%l)TEG1NEKW9{+t)nLpn3M@l0-3Gsh7F>*X&?udLh(p_%`vURrs&OjLT@J zDI?d|s_PO7Py6pV*=yuwDX%7BEIk90zn1QCJjobT$%cvDoVv3QL!73x_rLp3$WPry z_mH)Pxape36ZI1%w&~ADZ#i@=(aU7mC6L~B`T{9tX4v7Jbou+ToiuN(5 zEO<@fPd%S$|4A3DI5fE5ZZNx#Wq0@9fvUMQ$$N>X_?2UG*H~|>)749IYGVkp^NPNC zb|$vNp=o=v5A2ih&LbjWwvrLvF|6A-qCMCW@3%K>9GmMA%Yi+~sh@*N>|-@&E>i|W z{s*10L|wIjXc1k%^!*oegG6Z}5%Utu_Zf$|C|o%^e`SlO)NK8k*f+ zQfC!->SZ+M$Uu}Mp&+CNRqq7*sm8)!7~Sq{kR09CwQUd!yNDc{BY0&`4~m!};c6Bb1Dm z@%-&FIv`d>ru@{BbfZOXk}PVzpJucJj|}D&2~ht`KKnA#rf1&^YZ1|Rg{{l=aRx1Di literal 0 HcmV?d00001