Benchmark more jpeg decoders. Do downsizing decode with jpeg_decoder.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufReader;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
@@ -10,8 +11,10 @@ use image::imageops;
|
||||
use image::DynamicImage;
|
||||
use image::GenericImage;
|
||||
use image::GenericImageView;
|
||||
use image::ImageBuffer;
|
||||
use image::ImageFormat;
|
||||
use image::ImageResult;
|
||||
use jpeg_decoder::Decoder;
|
||||
use log::error;
|
||||
use log::info;
|
||||
use log::warn;
|
||||
@@ -22,7 +25,7 @@ use rocksdb::IteratorMode;
|
||||
use rocksdb::DB;
|
||||
|
||||
// Used to ensure DB is invalidated after schema changes.
|
||||
const LIBRARY_GENERATION: &'static str = "12";
|
||||
const LIBRARY_GENERATION: &'static str = "13";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Library {
|
||||
@@ -31,13 +34,35 @@ pub struct Library {
|
||||
cache_db: Arc<DB>,
|
||||
}
|
||||
|
||||
pub fn load_image<P>(path: P) -> ImageResult<DynamicImage>
|
||||
pub fn load_image<P>(
|
||||
path: P,
|
||||
width_hint: Option<u32>,
|
||||
height_hint: Option<u32>,
|
||||
) -> Result<DynamicImage, Box<dyn std::error::Error>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
image::io::Reader::open(&path)?
|
||||
.with_guessed_format()?
|
||||
.decode()
|
||||
// TODO(wathiede): fall back to image::load_image when jpeg decoding fails.
|
||||
let file = File::open(path).expect("failed to open file");
|
||||
let mut decoder = Decoder::new(BufReader::new(file));
|
||||
let (w, h) = match (width_hint, height_hint) {
|
||||
(Some(w), Some(h)) => {
|
||||
let got = decoder.scale(w as u16, h as u16)?;
|
||||
info!("Hinted at {}x{}, got {}x{}", w, h, got.0, got.1);
|
||||
(got.0 as u32, got.1 as u32)
|
||||
}
|
||||
// TODO(wathiede): handle partial hints by grabbing info and then computing the absent
|
||||
// dimenison.
|
||||
_ => {
|
||||
decoder.read_info()?;
|
||||
let info = decoder.info().unwrap();
|
||||
(info.width as u32, info.height as u32)
|
||||
}
|
||||
};
|
||||
let pixels = decoder.decode().expect("failed to decode image");
|
||||
Ok(DynamicImage::ImageRgb8(
|
||||
ImageBuffer::from_raw(w, h, pixels).expect("pixels to small for given dimensions"),
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -241,18 +266,15 @@ impl Library {
|
||||
media_items_id: &str,
|
||||
dimensions: (Option<u32>, Option<u32>),
|
||||
filter: FilterType,
|
||||
) -> Result<Vec<u8>, io::Error> {
|
||||
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
match self.original(&media_items_id) {
|
||||
None => {
|
||||
warn!("Couldn't find original {}", &media_items_id);
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!("{}", media_items_id),
|
||||
))
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, format!("{}", media_items_id)).into())
|
||||
}
|
||||
Some(path) => {
|
||||
let orig_img =
|
||||
load_image(&path).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
let orig_img = load_image(&path, dimensions.0, dimensions.1)?;
|
||||
//.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
let img = resize(&orig_img, dimensions, filter);
|
||||
let buf = save_to_jpeg_bytes(&img)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
@@ -288,7 +310,8 @@ impl Library {
|
||||
let bytes = match self.generate_thumbnail(
|
||||
media_items_id,
|
||||
dimensions,
|
||||
FilterType::Builtin(imageops::FilterType::Lanczos3),
|
||||
FilterType::Nearest,
|
||||
//FilterType::Builtin(imageops::FilterType::Lanczos3),
|
||||
) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user