use std::io::Write;
use url::Url;
use crate::{ResourceUrlHandler, TerminalSize};
pub trait InlineImageProtocol {
fn write_inline_image(
&self,
writer: &mut dyn Write,
resource_handler: &dyn ResourceUrlHandler,
url: &Url,
terminal_size: TerminalSize,
) -> std::io::Result<()>;
}
#[cfg(feature = "image-processing")]
pub fn downsize_to_columns(
image: &image::DynamicImage,
size: TerminalSize,
) -> Option<image::DynamicImage> {
use image::{imageops::FilterType, GenericImageView};
use tracing::{event, Level};
let win_size = size.pixels?;
event!(
Level::DEBUG,
"Terminal size {:?}; image is {:?}",
size,
image.dimensions()
);
let (image_width, _) = image.dimensions();
if win_size.x < image_width {
Some(image.resize(win_size.x, win_size.y, FilterType::Nearest))
} else {
None
}
}
#[cfg(feature = "image-processing")]
pub fn decode_image(
mime_data: &crate::resources::MimeData,
) -> std::io::Result<image::DynamicImage> {
use image::ImageFormat;
use std::io::Error;
if mime_data.mime_type_essence() == Some("image/svg+xml") {
let png = crate::resources::svg::render_svg_to_png(&mime_data.data)?;
return image::load_from_memory_with_format(&png, ImageFormat::Png)
.map_err(|err| Error::other(format!("rendered SVG was not valid PNG: {err}")));
}
let format_hint = mime_data
.mime_type_essence()
.and_then(image::ImageFormat::from_mime_type);
match format_hint {
Some(format) => image::load_from_memory_with_format(&mime_data.data, format)
.map_err(|err| Error::other(format!("image decode failed: {err}"))),
None => image::load_from_memory(&mime_data.data)
.map_err(|err| Error::other(format!("image decode failed: {err}"))),
}
}