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