diff --git a/src/main.rs b/src/main.rs index 6fb1cd4..21e3a60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,11 @@ use crate::quad_tree::QuadTree; use non_nan_float::NonNaNF32; use std::{ borrow::Borrow, + cell::RefCell, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, fmt, + num::NonZero, + rc::Rc, sync::OnceLock, }; @@ -96,6 +99,15 @@ macro_rules! make_enum_font { } impl $Font { + fn new(font_name: &str, size: NonNaNF32) -> Self { + match (font_name, size.get()) { + $($(($known_font_name, $known_font_size) => Self::$KnownFont,)*)* + _ => Self::Other { + font_name: Box::from(font_name), + size, + } + } + } const fn size(&self) -> f32 { match *self { Self::$Other { size, .. } => size.get(), @@ -535,7 +547,6 @@ impl Font { struct Char { font: Font, text: String, - adv: NonNaNF32, min_x: NonNaNF32, min_y: NonNaNF32, max_x: NonNaNF32, @@ -1711,4 +1722,178 @@ impl TextSection { } } -fn main() {} +#[derive(Clone, Debug, Default)] +struct MyDevice { + chars: Rc>>, +} + +impl MyDevice { + fn text(&mut self, text: &mupdf::Text, cmt: mupdf::Matrix) { + for span in text.spans() { + let span_font = span.font(); + let font_name = span_font.name(); + const ROUND_FACTOR: f32 = 1000.0; + let Some(size) = + NonNaNF32::new((span.trm().expansion() * ROUND_FACTOR).round() / ROUND_FACTOR) + else { + continue; + }; + let font = Font::new(font_name, size); + for item in span.items() { + let Some(ch) = u32::try_from(item.ucs()) + .ok() + .and_then(|v| char::try_from(v).ok()) + else { + continue; + }; + let mut m = span.trm(); + m.e = item.x(); + m.f = item.y(); + m.concat(cmt); + let (min_x, min_y, max_x, max_y) = match span.wmode() { + mupdf::WriteMode::Horizontal => { + todo!(); + } + mupdf::WriteMode::Vertical => todo!(), + }; + self.chars.borrow_mut().push(Char { + font, + text: String::from(ch), + min_x, + min_y, + max_x, + max_y, + }); + } + } + } +} + +impl mupdf::NativeDevice for MyDevice { + fn fill_path( + &mut self, + path: &mupdf::Path, + even_odd: bool, + cmt: mupdf::Matrix, + color_space: &mupdf::Colorspace, + color: &[f32], + alpha: f32, + cp: mupdf::ColorParams, + ) { + // TODO + } + + fn stroke_path( + &mut self, + path: &mupdf::Path, + stroke_state: &mupdf::StrokeState, + cmt: mupdf::Matrix, + color_space: &mupdf::Colorspace, + color: &[f32], + alpha: f32, + cp: mupdf::ColorParams, + ) { + // TODO + } + + fn clip_path( + &mut self, + path: &mupdf::Path, + even_odd: bool, + cmt: mupdf::Matrix, + scissor: mupdf::Rect, + ) { + // TODO + } + + fn clip_stroke_path( + &mut self, + path: &mupdf::Path, + stroke_state: &mupdf::StrokeState, + cmt: mupdf::Matrix, + scissor: mupdf::Rect, + ) { + // TODO + } + + fn fill_text( + &mut self, + text: &mupdf::Text, + cmt: mupdf::Matrix, + _color_space: &mupdf::Colorspace, + _color: &[f32], + _alpha: f32, + _cp: mupdf::ColorParams, + ) { + self.text(text, cmt); + } + + fn stroke_text( + &mut self, + text: &mupdf::Text, + _stroke_state: &mupdf::StrokeState, + cmt: mupdf::Matrix, + _color_space: &mupdf::Colorspace, + _color: &[f32], + _alpha: f32, + _cp: mupdf::ColorParams, + ) { + self.text(text, cmt); + } + + fn clip_text(&mut self, text: &mupdf::Text, cmt: mupdf::Matrix, _scissor: mupdf::Rect) { + self.text(text, cmt); + } + + fn clip_stroke_text( + &mut self, + text: &mupdf::Text, + _stroke_state: &mupdf::StrokeState, + cmt: mupdf::Matrix, + _scissor: mupdf::Rect, + ) { + self.text(text, cmt); + } + + fn ignore_text(&mut self, text: &mupdf::Text, cmt: mupdf::Matrix) { + self.text(text, cmt); + } +} + +fn main() -> Result<(), Box> { + let args: Vec = std::env::args().collect(); + let page_numbers: Option>>> = if 2 < args.len() { + Some(if let Some((start, end)) = args[2].split_once(":") { + let start: NonZero = start.trim().parse()?; + let end: NonZero = end.trim().parse()?; + Box::new( + (start.get()..end.get()).map(|v| NonZero::new(v).expect("known to be non-zero")), + ) + } else { + Box::new( + Result::>, _>::from_iter( + args[2].split(",").map(|v| v.trim().parse()), + )? + .into_iter(), + ) + }) + } else { + None + }; + let document = mupdf::Document::open(&args[1])?; + let pages: Vec<_> = document.pages()?.collect::>()?; + let page_numbers = page_numbers.unwrap_or_else(|| { + Box::new( + (0..pages.len()).map(|i| NonZero::new((i + 1) as u32).expect("known to be non-zero")), + ) + }); + for page_num in page_numbers { + let device = MyDevice::default(); + pages[page_num.get() as usize - 1].run( + &mupdf::Device::from_native(device.clone())?, + &mupdf::Matrix::IDENTITY, + )?; + println!("{device:?}"); + } + Ok(()) +}