Skip to content

Commit

Permalink
Add decoding hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
fintelia committed Oct 28, 2024
1 parent 277be64 commit c69cddb
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
45 changes: 45 additions & 0 deletions src/hooks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! This module provides a way to register decoding hooks for image formats not directly supported
//! by this crate.

use std::{
collections::HashMap,
io::{BufReader, Read, Seek},
sync::RwLock,
};

use crate::{ImageDecoder, ImageFormat, ImageResult};

pub(crate) trait ReadSeek: Read + Seek {}
impl<T: Read + Seek> ReadSeek for T {}

pub(crate) static DECODING_HOOKS: RwLock<Option<HashMap<ImageFormat, DecodingHook>>> =
RwLock::new(None);

/// A wrapper around a type-erased trait object that implements `Read` and `Seek`.
pub struct BoxReadSeek<'a>(pub(crate) Box<dyn ReadSeek + 'a>);
impl<'a> Read for BoxReadSeek<'a> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.0.read(buf)
}
}
impl<'a> Seek for BoxReadSeek<'a> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.0.seek(pos)
}
}

/// A function to produce an `ImageDecoder` for a given image format.
pub type DecodingHook = Box<
dyn for<'a> Fn(BufReader<BoxReadSeek<'a>>) -> ImageResult<Box<dyn ImageDecoder + 'a>>
+ Send
+ Sync,
>;

/// Register a new decoding hook or replace an existing one.
pub fn register_decoding_hook(format: ImageFormat, hook: DecodingHook) {
let mut hooks = DECODING_HOOKS.write().unwrap();
if hooks.is_none() {
*hooks = Some(HashMap::new());
}
hooks.as_mut().unwrap().insert(format, hook);
}
10 changes: 9 additions & 1 deletion src/image_reader/image_reader_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::path::Path;

use crate::dynimage::DynamicImage;
use crate::error::{ImageFormatHint, UnsupportedError, UnsupportedErrorKind};
use crate::hooks::{BoxReadSeek, DECODING_HOOKS};
use crate::image::ImageFormat;
use crate::{ImageDecoder, ImageError, ImageResult};

Expand Down Expand Up @@ -178,9 +179,16 @@ impl<'a, R: 'a + BufRead + Seek> ImageReader<R> {
#[cfg(feature = "qoi")]
ImageFormat::Qoi => Box::new(qoi::QoiDecoder::new(reader)?),
format => {
let hooks = DECODING_HOOKS.read().unwrap();
if let Some(hooks) = hooks.as_ref() {
if let Some(hook) = hooks.get(&format) {
return hook(BufReader::new(BoxReadSeek(Box::new(reader))));
}
}

return Err(ImageError::Unsupported(
ImageFormatHint::Exact(format).into(),
))
));
}
})
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ mod buffer_;
mod buffer_par;
mod color;
mod dynimage;
pub mod hooks;
mod image;
mod image_reader;
pub mod metadata;
Expand Down

0 comments on commit c69cddb

Please sign in to comment.