use crate::service::DecodeService;
use crate::{DecodeOptions, Decoder, FrameReader, ImageInfo, Pending};
use std::sync::Arc;
use std::time::Duration;
use valo::{Image, ImageContext};
#[derive(Clone)]
pub struct ImageLoader {
service: Arc<DecodeService>,
runner: Runner,
}
#[derive(Clone)]
enum Runner {
Inline,
#[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
Worker(crate::worker::Worker),
}
impl ImageLoader {
pub fn new(images: ImageContext, decoders: Vec<Box<dyn Decoder>>) -> Self {
Self {
service: Arc::new(DecodeService::new(images, decoders)),
runner: Runner::Inline,
}
}
#[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
pub fn with_worker(
images: ImageContext,
decoders: Vec<Box<dyn Decoder>>,
) -> std::io::Result<Self> {
let service = Arc::new(DecodeService::new(images, decoders));
let worker = crate::worker::Worker::spawn(service.clone())?;
Ok(Self {
service,
runner: Runner::Worker(worker),
})
}
pub fn decode(&self, encoded: Arc<[u8]>, options: DecodeOptions) -> Pending<'static, Image> {
match &self.runner {
Runner::Inline => {
let service = self.service.clone();
Pending::from_future(async move { service.decode_still(encoded, options).await })
}
#[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
Runner::Worker(worker) => worker.decode(encoded, options),
}
}
pub fn open(&self, encoded: Arc<[u8]>, options: DecodeOptions) -> Pending<'static, Codec> {
match &self.runner {
Runner::Inline => {
let service = self.service.clone();
Pending::from_future(async move {
let reader = service.open(encoded, options).await?;
Ok(Codec::inline(service, reader, options.mipmaps))
})
}
#[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
Runner::Worker(worker) => worker.open(encoded, options),
}
}
}
pub struct Codec {
info: ImageInfo,
mipmaps: bool,
reader: Reader,
}
enum Reader {
Inline {
service: Arc<DecodeService>,
reader: Box<dyn FrameReader>,
},
#[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
Remote(crate::worker::RemoteReader),
}
impl Codec {
fn inline(service: Arc<DecodeService>, reader: Box<dyn FrameReader>, mipmaps: bool) -> Self {
Self {
info: reader.info(),
mipmaps,
reader: Reader::Inline { service, reader },
}
}
#[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
pub(crate) fn remote(
info: ImageInfo,
mipmaps: bool,
reader: crate::worker::RemoteReader,
) -> Self {
Self {
info,
mipmaps,
reader: Reader::Remote(reader),
}
}
pub fn info(&self) -> ImageInfo {
self.info
}
pub fn next_frame(&mut self) -> Pending<'_, Frame> {
let mipmaps = self.mipmaps;
match &mut self.reader {
Reader::Inline { service, reader } => {
Pending::from_future(service.next_frame(reader.as_mut(), mipmaps))
}
#[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
Reader::Remote(remote) => remote.next_frame(),
}
}
}
impl std::fmt::Debug for Codec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Codec").field("info", &self.info).finish()
}
}
#[derive(Clone, Debug)]
pub struct Frame {
pub image: Image,
pub duration: Duration,
}