//! A small example that shows how you can extract unicode characters from //! glyphs. Please note that Unicode extraction is still experimental, so it //! might not work fully correctly in certain cases. Note also that generating //! div elements for every single character is clearly not desirable and there //! should be some word/sentence merging algorithm in-place, but this is //! out-of-scope for this example. use hayro_interpret::font::Glyph; use hayro_interpret::{ BlendMode, ClipPath, Context, Device, GlyphDrawMode, Image, InterpreterCache, InterpreterSettings, Paint, PathDrawMode, SoftMask, interpret_page, }; use hayro_syntax::Pdf; use std::fmt::Write; use hayro_cmap::BfString; use kurbo::{Affine, BezPath, Point, Rect}; use std::path::PathBuf; fn main() { let args: Vec = std::env::args().collect(); let relative_path = args .get(1) .expect("Please provide a relative path to the PDF file as the first argument"); let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(relative_path); let data = std::fs::read(path).unwrap(); let pdf = Pdf::new(data).unwrap(); let settings = InterpreterSettings::default(); let cache = InterpreterCache::new(); // Pass dummy values for bbox and initial transform, since we don't care about those. let mut context = Context::new( Affine::IDENTITY, Rect::new(0.0, 0.0, 1.0, 1.0), &cache, pdf.xref(), settings, ); // Run everything! let page = &pdf.pages()[0]; let mut extractor = TextExtractor { dimensions: page.render_dimensions(), ..Default::default() }; writeln!(extractor.text, " ").unwrap(); writeln!(extractor.text, "", 0).unwrap(); writeln!( extractor.text, "
", 0, extractor.dimensions.0, extractor.dimensions.1 ).unwrap(); interpret_page(page, &mut context, &mut extractor); writeln!(extractor.text, "
").unwrap(); print!("{}", extractor.text); } #[derive(Default)] struct TextExtractor { text: String, dimensions: (f32, f32), } /// Implement `Device` for `TextExtractor`. We extract Unicode text from glyphs. impl Device<'_> for TextExtractor { fn set_soft_mask(&mut self, _: Option>) {} fn draw_path(&mut self, _: &BezPath, _: Affine, _: &Paint<'_>, _: &PathDrawMode) {} fn push_clip_path(&mut self, _: &ClipPath) {} fn push_transparency_group(&mut self, _: f32, _: Option>, _: BlendMode) {} fn draw_glyph( &mut self, glyph: &Glyph<'_>, transform: Affine, glyph_transform: Affine, _: &Paint<'_>, _: &GlyphDrawMode, ) { if let Some(unicode_char) = glyph.as_unicode() { // Apply vertical flip transformation to combined transform // to place origin at top-left corner. let flip_transform = Affine::translate((0.0, self.dimensions.1 as f64)) * Affine::scale_non_uniform(1.0, -1.0); let transform = flip_transform * transform * glyph_transform; let point = Point::new(0.0, 0.0); let position = transform * point; writeln!( self.text, "
{}
", position.x, position.y, 6, match unicode_char { BfString::Char(c) => c.to_string(), BfString::String(s) => s } ).unwrap(); } else { // Fallback for glyphs without Unicode mapping. self.text.push('�'); } } fn pop_clip_path(&mut self) {} fn pop_transparency_group(&mut self) {} fn draw_image(&mut self, _: Image<'_, '_>, _: Affine) {} fn set_blend_mode(&mut self, _: BlendMode) {} }