1use crate::service::DecodeService;
3use crate::{DecodeOptions, Decoder, FrameReader, ImageInfo, Pending};
4use std::sync::Arc;
5use std::time::Duration;
6use valo::{Image, ImageContext};
7
8#[derive(Clone)]
14pub struct ImageLoader {
15 service: Arc<DecodeService>,
16 runner: Runner,
17}
18
19#[derive(Clone)]
20enum Runner {
21 Inline,
22 #[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
23 Worker(crate::worker::Worker),
24}
25
26impl ImageLoader {
27 pub fn new(images: ImageContext, decoders: Vec<Box<dyn Decoder>>) -> Self {
32 Self {
33 service: Arc::new(DecodeService::new(images, decoders)),
34 runner: Runner::Inline,
35 }
36 }
37
38 #[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
43 pub fn with_worker(
44 images: ImageContext,
45 decoders: Vec<Box<dyn Decoder>>,
46 ) -> std::io::Result<Self> {
47 let service = Arc::new(DecodeService::new(images, decoders));
48 let worker = crate::worker::Worker::spawn(service.clone())?;
49 Ok(Self {
50 service,
51 runner: Runner::Worker(worker),
52 })
53 }
54
55 pub fn decode(&self, encoded: Arc<[u8]>, options: DecodeOptions) -> Pending<'static, Image> {
57 match &self.runner {
58 Runner::Inline => {
59 let service = self.service.clone();
60 Pending::from_future(async move { service.decode_still(encoded, options).await })
61 }
62 #[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
63 Runner::Worker(worker) => worker.decode(encoded, options),
64 }
65 }
66
67 pub fn open(&self, encoded: Arc<[u8]>, options: DecodeOptions) -> Pending<'static, Codec> {
71 match &self.runner {
72 Runner::Inline => {
73 let service = self.service.clone();
74 Pending::from_future(async move {
75 let reader = service.open(encoded, options).await?;
76 Ok(Codec::inline(service, reader, options.mipmaps))
77 })
78 }
79 #[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
80 Runner::Worker(worker) => worker.open(encoded, options),
81 }
82 }
83}
84
85pub struct Codec {
90 info: ImageInfo,
91 mipmaps: bool,
92 reader: Reader,
93}
94
95enum Reader {
96 Inline {
97 service: Arc<DecodeService>,
98 reader: Box<dyn FrameReader>,
99 },
100 #[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
101 Remote(crate::worker::RemoteReader),
102}
103
104impl Codec {
105 fn inline(service: Arc<DecodeService>, reader: Box<dyn FrameReader>, mipmaps: bool) -> Self {
106 Self {
107 info: reader.info(),
108 mipmaps,
109 reader: Reader::Inline { service, reader },
110 }
111 }
112
113 #[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
114 pub(crate) fn remote(
115 info: ImageInfo,
116 mipmaps: bool,
117 reader: crate::worker::RemoteReader,
118 ) -> Self {
119 Self {
120 info,
121 mipmaps,
122 reader: Reader::Remote(reader),
123 }
124 }
125
126 pub fn info(&self) -> ImageInfo {
128 self.info
129 }
130
131 pub fn next_frame(&mut self) -> Pending<'_, Frame> {
136 let mipmaps = self.mipmaps;
137 match &mut self.reader {
138 Reader::Inline { service, reader } => {
139 Pending::from_future(service.next_frame(reader.as_mut(), mipmaps))
140 }
141 #[cfg(all(feature = "worker", not(target_arch = "wasm32")))]
142 Reader::Remote(remote) => remote.next_frame(),
143 }
144 }
145}
146
147impl std::fmt::Debug for Codec {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("Codec").field("info", &self.info).finish()
150 }
151}
152
153#[derive(Clone, Debug)]
155pub struct Frame {
156 pub image: Image,
158
159 pub duration: Duration,
162}