From e44d5babcaf128ae2f5633dee9e02d0c71d1d02f Mon Sep 17 00:00:00 2001 From: liquidev Date: Fri, 19 Jul 2024 19:15:24 +0200 Subject: [PATCH] add image sizes to emoji --- crates/treehouse/src/config.rs | 46 +++++++++++++++++---------- crates/treehouse/src/html/markdown.rs | 20 +++++++++--- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/crates/treehouse/src/config.rs b/crates/treehouse/src/config.rs index 184b2e0..5b4d567 100644 --- a/crates/treehouse/src/config.rs +++ b/crates/treehouse/src/config.rs @@ -1,7 +1,8 @@ use std::{collections::HashMap, ffi::OsStr, fs::File, io::BufReader, path::Path}; use anyhow::Context; -use log::debug; +use image::ImageError; +use log::{debug, error, warn}; use serde::{Deserialize, Serialize}; use walkdir::WalkDir; @@ -180,32 +181,43 @@ impl Config { /// Data derived from the config. #[derive(Debug, Clone, Default)] pub struct ConfigDerivedData { - pub pic_sizes: HashMap>, + pub image_sizes: HashMap>, } -/// Picture size. This is useful for emitting elements with a specific size to eliminate layout shifting. +/// Image size. This is useful for emitting elements with a specific size to eliminate +/// layout shifting. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct PicSize { +pub struct ImageSize { pub width: u32, pub height: u32, } impl ConfigDerivedData { - fn read_pic_size(config: &Config, pic_id: &str) -> Option { - let pic_filename = config.pics.get(pic_id)?; - let (width, height) = image::io::Reader::new(BufReader::new( - File::open(format!("static/pic/{pic_filename}")).ok()?, - )) - .into_dimensions() - .ok()?; - Some(PicSize { width, height }) + fn read_image_size(filename: &str) -> Option { + let (width, height) = image::io::Reader::new(BufReader::new(File::open(filename).ok()?)) + .with_guessed_format() + .map_err(ImageError::from) + .and_then(|i| i.into_dimensions()) + // NOTE: Not being able to determine the image size is not the end of the world, + // so just warn the user if we couldn't do it. + // For example, currently SVG is not supported at all, which causes this to fail. + .inspect_err(|e| warn!("cannot read image size of {filename}: {e}")) + .ok()?; + Some(ImageSize { width, height }) } - pub fn pic_size(&mut self, config: &Config, pic_id: &str) -> Option { - if !self.pic_sizes.contains_key(pic_id) { - self.pic_sizes - .insert(pic_id.to_owned(), Self::read_pic_size(config, pic_id)); + pub fn image_size(&mut self, filename: &str) -> Option { + if !self.image_sizes.contains_key(filename) { + self.image_sizes + .insert(filename.to_owned(), Self::read_image_size(filename)); } - self.pic_sizes.get(pic_id).copied().flatten() + self.image_sizes.get(filename).copied().flatten() + } + + pub fn pic_size(&mut self, config: &Config, pic_id: &str) -> Option { + config + .pics + .get(pic_id) + .and_then(|pic_filename| self.image_size(&format!("static/pic/{pic_filename}"))) } } diff --git a/crates/treehouse/src/html/markdown.rs b/crates/treehouse/src/html/markdown.rs index 308b66f..06b06d4 100644 --- a/crates/treehouse/src/html/markdown.rs +++ b/crates/treehouse/src/html/markdown.rs @@ -30,7 +30,7 @@ use pulldown_cmark::escape::{escape_href, escape_html, StrWrite}; use pulldown_cmark::{Alignment, CodeBlockKind, Event, LinkType, Tag}; use pulldown_cmark::{CowStr, Event::*}; -use crate::config::{Config, ConfigDerivedData, PicSize}; +use crate::config::{Config, ConfigDerivedData, ImageSize}; use crate::html::highlight::highlight; use crate::state::Treehouse; @@ -281,15 +281,13 @@ where if let LiterateCodeKind::Output { placeholder_pic_id } = kind { if !placeholder_pic_id.is_empty() { - self.write( - "")?; } + self.writer .write_str("\"")?;")?; + if branch_id.is_some() { self.writer.write_str("")?; }