mirror of
https://github.com/Astatin3/RusTeX.git
synced 2026-06-08 16:18:09 -06:00
Start making element system
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
use icy_sixel::{sixel_string, DiffusionMethod, MethodForLargest, MethodForRep, PixelFormat, Quality};
|
||||
|
||||
pub struct Bitmap {
|
||||
pub data: Vec<u8>,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
}
|
||||
|
||||
impl Bitmap {
|
||||
pub fn new(width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
data: vec![0; width*height],
|
||||
width,
|
||||
height
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_data(data: Vec<u8>, width: usize, height: usize) -> Self {
|
||||
assert!(data.len() == width * height);
|
||||
Self {
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlay(&mut self, other: &Bitmap, xoffset: usize, yoffset:usize) {
|
||||
for y in 0..other.height {
|
||||
for x in 0..other.width {
|
||||
self.data[(y+yoffset as usize)*self.width + (x+xoffset as usize)] = other.data[y*other.width + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a 1 byte per pixel greyscale bitmap to Sixel format in console
|
||||
pub fn print(&self) {
|
||||
let mut bitmap_rgb888 = vec![0; self.width*self.height*3];
|
||||
|
||||
for y in 0..self.height {
|
||||
for x in 0..self.width {
|
||||
let index = y*self.width + x;
|
||||
|
||||
let pixel = self.data[index];
|
||||
|
||||
bitmap_rgb888[index*3] = pixel;
|
||||
bitmap_rgb888[index*3 + 1] = pixel;
|
||||
bitmap_rgb888[index*3 + 2] = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
let sixel_data = sixel_string(
|
||||
&bitmap_rgb888,
|
||||
self.width as i32,
|
||||
self.height as i32,
|
||||
PixelFormat::RGB888,
|
||||
DiffusionMethod::None,
|
||||
MethodForLargest::Auto,
|
||||
MethodForRep::Auto,
|
||||
Quality::AUTO,
|
||||
).unwrap();
|
||||
|
||||
println!("{}", sixel_data);
|
||||
|
||||
}
|
||||
}
|
||||
+48
-79
@@ -1,105 +1,74 @@
|
||||
#[allow(non_upper_case_globals)]
|
||||
|
||||
mod fonts;
|
||||
mod parser;
|
||||
mod bitmap;
|
||||
|
||||
use fontdue::{layout::{CoordinateSystem, Layout, LayoutSettings, TextStyle}};
|
||||
use icy_sixel::{
|
||||
DiffusionMethod, MethodForLargest, MethodForRep, PixelFormat, Quality, sixel_string,
|
||||
};
|
||||
use std::{rc::Rc, time::Instant};
|
||||
|
||||
use fontdue::{layout::{CoordinateSystem, Layout, LayoutSettings}};
|
||||
|
||||
use crate::{bitmap::Bitmap, parser::{KElement}};
|
||||
|
||||
fn main() -> Result<(), std::fmt::Error> {
|
||||
let mut rustex = RusTeX::new();
|
||||
rustex.add_text(&TextStyle::new("testi12345ng! e^23", 35.0, 0));
|
||||
let (bitmap, (width, height)) = rustex.rasterize();
|
||||
print_bitmap(&bitmap, width, height);
|
||||
let start = Instant::now();
|
||||
|
||||
let mut rustex = RusTeX::new(TeXSettings { scale: 100. });
|
||||
|
||||
let element = KElement::LinearGroup(vec![
|
||||
KElement::Fraction(
|
||||
Rc::new(KElement::Integer(123)),
|
||||
Rc::new(KElement::Integer(12))
|
||||
),
|
||||
// KElement::Integer(12),
|
||||
// KElement::Integer(12),
|
||||
KElement::Decimal(12.34),
|
||||
KElement::Fraction(
|
||||
Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Integer(12)))),
|
||||
Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Fraction(Rc::new(KElement::Integer(123)),Rc::new(KElement::Decimal(1234.5678)))))))))))))))),
|
||||
),
|
||||
]);
|
||||
|
||||
// rustex.add_text(&TextStyle::new("testi12345ng! e^23", 100.0, 0));
|
||||
let bitmap = rustex.rasterize(element);
|
||||
|
||||
println!("Rasterizing time: {:?}", start.elapsed());
|
||||
|
||||
bitmap.print();
|
||||
|
||||
// print_bitmap(&bitmap, width, height);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct RusTeX {
|
||||
layout: Layout,
|
||||
settings: TeXSettings,
|
||||
layout: Layout
|
||||
}
|
||||
|
||||
struct TeXSettings {
|
||||
scale: f32,
|
||||
}
|
||||
|
||||
impl RusTeX {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(settings: TeXSettings) -> Self {
|
||||
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
|
||||
// By default, layout is initialized with the default layout settings. This call is redundant, but
|
||||
// demonstrates setting the value with your custom settings.
|
||||
|
||||
layout.reset(&LayoutSettings {
|
||||
..LayoutSettings::default()
|
||||
});
|
||||
|
||||
Self {
|
||||
settings,
|
||||
layout,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_text(&mut self, text_style: &TextStyle) {
|
||||
self.layout.append(&fonts::FONTS, text_style);
|
||||
}
|
||||
// pub fn add_text_style(&mut self, text_style: &TextStyle) {
|
||||
// // self.layout.append(&fonts::FONTS, text_style);
|
||||
// }
|
||||
|
||||
pub fn rasterize(&mut self) -> (Vec<u8>, (usize, usize)) {
|
||||
let (mut maxx, mut maxy): (usize, usize) = (0,0);
|
||||
for glyph in self.layout.glyphs() {
|
||||
maxx = maxx.max(glyph.x as usize + glyph.width);
|
||||
maxy = maxy.max(glyph.y as usize + glyph.height);
|
||||
}
|
||||
|
||||
let mut bitmap: Vec<u8> = vec![0; maxx*maxy];
|
||||
|
||||
for glyph in self.layout.glyphs() {
|
||||
|
||||
let font = &fonts::FONTS[glyph.font_index];
|
||||
let (metrics, char_bitmap) = font.rasterize_config(glyph.key);
|
||||
|
||||
|
||||
|
||||
for y in 0..metrics.height {
|
||||
for x in 0..metrics.width {
|
||||
let pixel = char_bitmap[y*glyph.width + x];
|
||||
|
||||
// let index = (x+glyph.x as usize)*maxy + (y+glyph.y as usize);
|
||||
let index = (y+glyph.y as usize)*maxx + (x+glyph.x as usize);
|
||||
|
||||
bitmap[index] = pixel;
|
||||
pub fn rasterize(&mut self, root_element: KElement) -> Bitmap {
|
||||
root_element.rasterize(&mut self.layout, self.settings.scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(bitmap, (maxx, maxy))
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a 1 byte per pixel greyscale bitmap to Sixel format in console
|
||||
fn print_bitmap(bitmap: &Vec<u8>, width: usize, height: usize) {
|
||||
let mut bitmap_rgb888 = vec![0; width*height*3];
|
||||
|
||||
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let index = y*width + x;
|
||||
|
||||
let pixel = bitmap[index];
|
||||
|
||||
bitmap_rgb888[index*3] = pixel;
|
||||
bitmap_rgb888[index*3 + 1] = pixel;
|
||||
bitmap_rgb888[index*3 + 2] = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let sixel_data = sixel_string(
|
||||
&bitmap_rgb888,
|
||||
width as i32,
|
||||
height as i32,
|
||||
PixelFormat::RGB888,
|
||||
DiffusionMethod::None,
|
||||
MethodForLargest::Auto,
|
||||
MethodForRep::Auto,
|
||||
Quality::AUTO,
|
||||
).unwrap();
|
||||
|
||||
println!("{}", sixel_data);
|
||||
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use fontdue::layout::{Layout, TextStyle};
|
||||
|
||||
use crate::{bitmap::Bitmap, fonts::FONTS};
|
||||
|
||||
pub enum KElement {
|
||||
LinearGroup(Vec<KElement>),
|
||||
Integer(i64),
|
||||
Decimal(f64),
|
||||
Fraction(Rc<KElement>, Rc<KElement>),
|
||||
}
|
||||
|
||||
pub static FRACTION_SCALE: f32 = 1.;
|
||||
// pub static FRACTION_PADDING: usize = 10;
|
||||
|
||||
// pub enum KSymbol {
|
||||
// Text {
|
||||
// data: String,
|
||||
// x: f32,
|
||||
// y: f32,
|
||||
// scale: f32
|
||||
// },
|
||||
// None,
|
||||
// }
|
||||
|
||||
impl KElement {
|
||||
pub fn rasterize(&self, layout: &mut Layout, scale: f32) -> Bitmap {
|
||||
match self {
|
||||
KElement::LinearGroup(elems) => {
|
||||
let (mut totalx, mut maxy) = (0,0);
|
||||
let mut positions = Vec::new();
|
||||
for elem in elems {
|
||||
let (x,y) = elem.get_bounds(layout, scale);
|
||||
positions.push((totalx,y));
|
||||
totalx += x;
|
||||
maxy = maxy.max(y);
|
||||
}
|
||||
|
||||
let mut bitmap = Bitmap::new(totalx, maxy);
|
||||
|
||||
for i in 0..elems.len() {
|
||||
let elem = &elems[i];
|
||||
let pos = positions[i];
|
||||
let new_bitmap = elem.rasterize(layout, scale);
|
||||
// println!("{:?} {:?} {:?}", (bitmap.width, bitmap.height), pos, (new_bitmap.width, new_bitmap.height));
|
||||
bitmap.overlay(&new_bitmap, pos.0, (maxy-pos.1)/2);
|
||||
}
|
||||
|
||||
bitmap
|
||||
}
|
||||
KElement::Integer(i) => {
|
||||
render_text_block(layout, &i.to_string(), scale)
|
||||
},
|
||||
KElement::Decimal(i) => {
|
||||
render_text_block(layout, &i.to_string(), scale)
|
||||
},
|
||||
KElement::Fraction(a,b) => {
|
||||
let (ax,ay) = a.get_bounds(layout, scale * FRACTION_SCALE);
|
||||
let (bx,by) = b.get_bounds(layout, scale * FRACTION_SCALE);
|
||||
let (width, height) = (ax.max(bx), ay+by);
|
||||
|
||||
let mut bitmap = Bitmap::new(width, height);
|
||||
|
||||
let bitmap_a = &mut a.rasterize(layout, scale * FRACTION_SCALE);
|
||||
let bitmap_b = &mut b.rasterize(layout, scale * FRACTION_SCALE);
|
||||
|
||||
if bitmap_a.width > bitmap_b.width {
|
||||
bitmap.overlay(&bitmap_a, 0, 0);
|
||||
bitmap.overlay(&bitmap_b, (bitmap_a.width-bitmap_b.width)/2, ay);
|
||||
} else {
|
||||
bitmap.overlay(&bitmap_a, (bitmap_b.width-bitmap_a.width)/2, 0);
|
||||
bitmap.overlay(&bitmap_b, 0, ay);
|
||||
}
|
||||
|
||||
bitmap
|
||||
|
||||
// symbols.append();
|
||||
// symbols.append(&mut b.to_text_style(x, midy, scale / 2.));
|
||||
// symbols
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get_bounds(&self, layout: &mut Layout, scale: f32) -> (usize, usize) {
|
||||
match self {
|
||||
KElement::LinearGroup(elems) => {
|
||||
let (mut totalx, mut maxy) = (0,0);
|
||||
for elem in elems {
|
||||
let (x,y) = elem.get_bounds(layout, scale);
|
||||
totalx += x;
|
||||
maxy = maxy.max(y);
|
||||
}
|
||||
(totalx, maxy)
|
||||
}
|
||||
KElement::Integer(i) => {
|
||||
measure_text_bounds(layout, &i.to_string(), scale)
|
||||
},
|
||||
KElement::Decimal(i) => {
|
||||
measure_text_bounds(layout, &i.to_string(), scale)
|
||||
},
|
||||
KElement::Fraction(a,b) => {
|
||||
let (ax,ay) = a.get_bounds(layout, scale * FRACTION_SCALE);
|
||||
let (bx,by) = b.get_bounds(layout, scale * FRACTION_SCALE);
|
||||
(ax.max(bx), ay+by)
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl KSymbol {
|
||||
// // pub fn get_max_bounds(&self) -> (f32, f32) {
|
||||
// // match self {
|
||||
// // KSymbol::Text { x, y, ..} => (*x,*y),
|
||||
// // _ => (0.,0.)
|
||||
// // }
|
||||
// // }
|
||||
// pub fn rasterize(&self, layout: &mut Layout, bitmap: &mut Bitmap) {
|
||||
// match self {
|
||||
// KSymbol::Text { data, x, y, scale } => {
|
||||
// let new_bitmap = render_text_block(layout, data, *scale);
|
||||
// bitmap.overlay(&new_bitmap, *x as usize, *y as usize);
|
||||
// },
|
||||
// KSymbol::None => {},
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
fn measure_text_bounds(layout: &mut Layout, text: &str, scale:f32) -> (usize, usize) {
|
||||
layout.clear();
|
||||
layout.append(&FONTS, &TextStyle::new(text, scale, 0));
|
||||
|
||||
let (mut width, mut height): (usize, usize) = (0,0);
|
||||
for glyph in layout.glyphs() {
|
||||
width = width.max(glyph.x as usize + glyph.width);
|
||||
height = height.max(glyph.y as usize + glyph.height);
|
||||
}
|
||||
|
||||
(width, height)
|
||||
|
||||
}
|
||||
|
||||
fn render_text_block(layout: &mut Layout, text: &str, scale:f32) -> Bitmap {
|
||||
layout.clear();
|
||||
|
||||
layout.append(&FONTS, &TextStyle::new(text, scale, 0));
|
||||
|
||||
let (mut width, mut height): (usize, usize) = (0,0);
|
||||
for glyph in layout.glyphs() {
|
||||
width = width.max(glyph.x as usize + glyph.width);
|
||||
height = height.max(glyph.y as usize + glyph.height);
|
||||
}
|
||||
|
||||
let mut new_bitmap = Bitmap::new(width, height);
|
||||
|
||||
for glyph in layout.glyphs() {
|
||||
|
||||
let font = &FONTS[glyph.font_index];
|
||||
let (_, char_bitmap) = font.rasterize_config(glyph.key);
|
||||
|
||||
new_bitmap.overlay(&Bitmap::from_data(char_bitmap, glyph.width, glyph.height), glyph.x as usize, glyph.y as usize);
|
||||
}
|
||||
|
||||
new_bitmap
|
||||
}
|
||||
Reference in New Issue
Block a user