1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
use annotation::Annotation; use error::Result; use image::{self, DynamicImage, FilterType, GenericImage, ImageFormat, imageops, RgbaImage}; use rusttype::Font; use std::io; use AA_FACTOR; pub struct Canvas { base: DynamicImage, overlay: DynamicImage, width: u32, height: u32, } impl Canvas { pub fn read_from_buffer(buf: &[u8]) -> Result<Canvas> { let base = image::load_from_memory(buf)?; let (width, height) = base.dimensions(); Ok(Canvas { base, overlay: DynamicImage::ImageRgba8(RgbaImage::new(width * AA_FACTOR, height * AA_FACTOR)), width, height, }) } pub fn add_annotation<'a>(&mut self, annotation: &Annotation, font: &Font<'a>, scale_multiplier: f32) { let scale_factor = (self.height as f32 / 10.0) * scale_multiplier; annotation.render_text(&mut self.overlay, font, scale_factor, self.width, self.height); } pub fn render(&mut self) { let downsampled_text = imageops::resize(&self.overlay, self.width, self.height, FilterType::CatmullRom); imageops::overlay(&mut self.base, &mut DynamicImage::ImageRgba8(downsampled_text), 0, 0); } pub fn save_jpg<W: io::Write>(&self, stream: &mut W) -> io::Result<()> { self.base.save(stream, ImageFormat::JPEG) .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) } pub fn save_png<W: io::Write>(&self, stream: &mut W) -> io::Result<()> { self.base.save(stream, ImageFormat::PNG) .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) } }