arona/src/image.rs

86 lines
2.5 KiB
Rust

use image::imageops::FilterType;
use image::io::Reader as ImageReader;
use image::{Rgba, RgbaImage};
use lazy_static::lazy_static;
use log::{error, info, warn};
use std::collections::HashMap;
use std::io::Cursor;
use std::sync::Mutex;
type Cache = Mutex<HashMap<String, RgbaImage>>;
lazy_static! {
static ref CACHE: Cache = Mutex::new(HashMap::new());
}
pub async fn get_image_from_url(url: &str, width: u32, height: u32) -> RgbaImage {
if let Some(img) = check_cache(url) {
info!("Cache Hit for {}", url);
return img;
}
info!("Downloading {}", url);
match reqwest::get(url).await {
Ok(resp) => match resp.bytes().await {
Ok(bytes) => match ImageReader::new(Cursor::new(bytes)).with_guessed_format() {
Ok(img_reader) => match img_reader.decode() {
Ok(dynamic_img) => {
info!("Successfully decoded image from {}", url);
let img = image::imageops::resize(
&dynamic_img,
width,
height,
FilterType::Nearest,
);
add_to_cache(url, &img);
img
}
Err(err) => {
warn!("Decoding Error: {}", err);
generate_default_img(width, height)
}
},
Err(err) => {
error!("Unexpected IO Error Occurred: {}", err);
// We can recover here, but maybe it's worth panicking here?
generate_default_img(width, height)
}
},
Err(err) => {
warn!("Response Parse failed: {:}?", err);
generate_default_img(width, height)
}
},
Err(err) => {
warn!("Download failed: {:?}", err);
generate_default_img(width, height)
}
}
}
fn check_cache(url: &str) -> Option<RgbaImage> {
if let Ok(lock) = CACHE.lock() {
lock.get(url).cloned()
} else {
None
}
}
fn add_to_cache(url: &str, img: &RgbaImage) {
if let Ok(ref mut lock) = CACHE.lock() {
lock.insert(url.to_string(), img.clone());
}
}
fn generate_default_img(width: u32, height: u32) -> RgbaImage {
let mut img = RgbaImage::new(width, height);
for x in 0..height {
for y in 0..width {
img.put_pixel(x, y, Rgba([160, 32, 240, 1]));
}
}
img
}