1use std::collections::BTreeMap;
2use std::io::Read;
3use std::time::Duration;
4
5use glycin_common::{MemoryFormat, MemoryFormatInfo};
6use gufo_common::orientation::Orientation;
7#[cfg(feature = "external")]
8use zbus::zvariant::as_value::{self, optional};
9#[cfg(feature = "external")]
10use zbus::zvariant::{self, Optional, Type};
11
12use crate::error::DimensionTooLargerError;
13use crate::safe_math::{SafeConversion, SafeMath};
14use crate::{ByteData, FungibleMemory, Limits, MemoryAllocationError, ProcessError};
15
16pub trait LoaderImplementation: Send + Sync + Sized + 'static {
17 fn load<B: ByteData, R: Read + Send + 'static>(
18 stream: R,
19 mime_type: String,
20 details: InitializationDetails,
21 ) -> Result<(Self, ImageDetails<B>), ProcessError>;
22
23 fn specific_frame<T: ByteData>(
24 &mut self,
25 frame_request: FrameRequest,
26 ) -> Result<Frame<T>, ProcessError>;
27}
28
29#[cfg(feature = "external")]
30#[derive(serde::Deserialize, serde::Serialize, Type, Debug)]
31pub struct InitRequest {
32 pub fd: zvariant::OwnedFd,
34 pub mime_type: String,
35 pub details: InitializationDetails,
36}
37
38#[derive(Debug, Default)]
39#[cfg_attr(
40 feature = "external",
41 derive(serde::Deserialize, serde::Serialize, Type)
42)]
43#[cfg_attr(feature = "external", zvariant(signature = "a{sv}"))]
44#[cfg_attr(feature = "external", serde(default))]
45#[non_exhaustive]
46pub struct InitializationDetails {
47 #[cfg_attr(
48 feature = "external",
49 serde(with = "optional", skip_serializing_if = "Option::is_none")
50 )]
51 pub base_dir: Option<std::path::PathBuf>,
52 #[cfg_attr(feature = "external", serde(with = "as_value"))]
53 pub limits: Limits,
54}
55
56#[cfg(feature = "external")]
57const fn true_const() -> bool {
58 true
59}
60
61#[derive(Debug, Clone)]
62#[cfg_attr(
63 feature = "external",
64 derive(serde::Deserialize, serde::Serialize, Type)
65)]
66#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
67#[non_exhaustive]
68pub struct FrameRequest {
69 #[cfg_attr(
71 feature = "external",
72 serde(with = "optional", skip_serializing_if = "Option::is_none", default)
73 )]
74 pub scale: Option<(u32, u32)>,
75 #[cfg_attr(
77 feature = "external",
78 serde(with = "optional", skip_serializing_if = "Option::is_none", default)
79 )]
80 pub clip: Option<(u32, u32, u32, u32)>,
81 #[cfg_attr(feature = "external", serde(with = "as_value", default = "true_const"))]
83 pub loop_animation: bool,
84}
85
86impl Default for FrameRequest {
87 fn default() -> Self {
88 Self {
89 scale: None,
90 clip: None,
91 loop_animation: true,
92 }
93 }
94}
95
96#[cfg(feature = "external")]
100#[derive(Debug, Type, serde::Serialize, serde::Deserialize)]
101#[serde(bound(
102 serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
103 deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
104))]
105#[non_exhaustive]
106pub struct RemoteImage<B: ByteData> {
107 pub frame_request: zvariant::OwnedObjectPath,
108 pub details: ImageDetails<B>,
109}
110
111#[cfg(feature = "external")]
112impl<B: ByteData> RemoteImage<B> {
113 pub fn new(details: ImageDetails<B>, frame_request: zvariant::OwnedObjectPath) -> Self {
114 Self {
115 frame_request,
116 details,
117 }
118 }
119
120 pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
121 self.details.initial_seal().await
122 }
123
124 pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
125 self.details.final_seal().await
126 }
127}
128
129#[derive(Debug)]
130#[cfg_attr(
131 feature = "external",
132 derive(Type, serde::Serialize, serde::Deserialize)
133)]
134#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
135#[cfg_attr(
136 feature = "external",
137 serde(bound(
138 serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
139 deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
140 ))
141)]
142#[non_exhaustive]
143pub struct ImageDetails<B: ByteData> {
144 #[cfg_attr(feature = "external", serde(with = "as_value"))]
150 pub width: u32,
151 #[cfg_attr(feature = "external", serde(with = "as_value"))]
152 pub height: u32,
153 #[cfg_attr(
155 feature = "external",
156 serde(
157 with = "as_value::optional",
158 skip_serializing_if = "Option::is_none",
159 default
160 )
161 )]
162 pub dimensions_inch: Option<(f64, f64)>,
163 #[cfg_attr(
164 feature = "external",
165 serde(
166 with = "as_value::optional",
167 skip_serializing_if = "Option::is_none",
168 default
169 )
170 )]
171 pub info_format_name: Option<String>,
172 #[cfg_attr(
174 feature = "external",
175 serde(
176 with = "as_value::optional",
177 skip_serializing_if = "Option::is_none",
178 default
179 )
180 )]
181 pub info_dimensions_text: Option<String>,
182 #[cfg_attr(
183 feature = "external",
184 serde(
185 with = "as_value::optional",
186 skip_serializing_if = "Option::is_none",
187 default
188 )
189 )]
190 pub metadata_exif: Option<B>,
191 #[cfg_attr(
192 feature = "external",
193 serde(
194 with = "as_value::optional",
195 skip_serializing_if = "Option::is_none",
196 default
197 )
198 )]
199 pub metadata_xmp: Option<B>,
200 #[cfg_attr(
201 feature = "external",
202 serde(
203 with = "as_value::optional",
204 skip_serializing_if = "Option::is_none",
205 default
206 )
207 )]
208 pub metadata_key_value: Option<BTreeMap<String, String>>,
209 #[cfg_attr(feature = "external", serde(with = "as_value"))]
210 pub transformation_ignore_exif: bool,
211 #[cfg_attr(
213 feature = "external",
214 serde(
215 with = "as_value::optional",
216 skip_serializing_if = "Option::is_none",
217 default
218 )
219 )]
220 pub transformation_orientation: Option<Orientation>,
221}
222
223impl<B: ByteData> ImageDetails<B> {
224 pub fn new(width: u32, height: u32) -> Self {
225 Self {
226 width,
227 height,
228 dimensions_inch: None,
229 info_dimensions_text: None,
230 info_format_name: None,
231 metadata_exif: None,
232 metadata_xmp: None,
233 metadata_key_value: None,
234 transformation_ignore_exif: false,
235 transformation_orientation: None,
236 }
237 }
238
239 pub fn into_fungible(self) -> ImageDetails<FungibleMemory> {
240 ImageDetails {
241 width: self.width,
242 height: self.height,
243 dimensions_inch: self.dimensions_inch,
244 info_format_name: self.info_format_name,
245 info_dimensions_text: self.info_dimensions_text,
246 metadata_exif: self.metadata_exif.map(B::into_fungible),
247 metadata_xmp: self.metadata_xmp.map(B::into_fungible),
248 metadata_key_value: self.metadata_key_value,
249 transformation_ignore_exif: self.transformation_ignore_exif,
250 transformation_orientation: self.transformation_orientation,
251 }
252 }
253
254 pub fn into_other<O: ByteData>(self) -> Result<ImageDetails<O>, MemoryAllocationError> {
255 Ok(ImageDetails {
256 width: self.width,
257 height: self.height,
258 dimensions_inch: self.dimensions_inch,
259 info_format_name: self.info_format_name,
260 info_dimensions_text: self.info_dimensions_text,
261 metadata_exif: self.metadata_exif.map(|x| x.into_other()).transpose()?,
262 metadata_xmp: self.metadata_xmp.map(|x| x.into_other()).transpose()?,
263 metadata_key_value: self.metadata_key_value,
264 transformation_ignore_exif: self.transformation_ignore_exif,
265 transformation_orientation: self.transformation_orientation,
266 })
267 }
268
269 pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
270 if let Some(metadata_exif) = &mut self.metadata_exif {
271 metadata_exif.initial_seal().await?;
272 }
273
274 if let Some(metadata_xmp) = &mut self.metadata_xmp {
275 metadata_xmp.initial_seal().await?;
276 }
277
278 Ok(())
279 }
280
281 pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
282 if let Some(metadata_exif) = &mut self.metadata_exif {
283 metadata_exif.final_seal().await?;
284 }
285
286 if let Some(metadata_xmp) = &mut self.metadata_xmp {
287 metadata_xmp.final_seal().await?;
288 }
289
290 Ok(())
291 }
292}
293
294impl<B: ByteData> Default for FrameDetails<B> {
295 fn default() -> Self {
296 Self {
297 color_icc_profile: None,
298 color_cicp: None,
299 info_bit_depth: None,
300 info_alpha_channel: None,
301 info_grayscale: None,
302 n_frame: None,
303 }
304 }
305}
306
307#[cfg(not(feature = "external"))]
308pub type Optional<T> = Option<T>;
309
310#[derive(Debug)]
311#[cfg_attr(feature = "external", derive(serde::Serialize, serde::Deserialize))]
312#[cfg_attr(
313 feature = "external",
314 serde(bound(
315 serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
316 deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
317 ))
318)]
319pub struct Frame<B: ByteData> {
320 pub width: u32,
321 pub height: u32,
322 pub stride: u32,
324 pub memory_format: MemoryFormat,
325 pub texture: B,
326 pub delay: Optional<Duration>,
330 pub details: FrameDetails<B>,
331}
332
333#[cfg(feature = "external")]
334impl<B: ByteData + zvariant::Type> zvariant::Type for Frame<B> {
335 const SIGNATURE: &'static zvariant::Signature = <(
336 u32,
337 u32,
338 u32,
339 MemoryFormat,
340 B,
341 Optional<Duration>,
342 FrameDetails<B>,
343 )>::SIGNATURE;
344}
345
346impl<B: ByteData> Frame<B> {
347 pub fn new(
348 width: u32,
349 height: u32,
350 memory_format: MemoryFormat,
351 texture: B,
352 ) -> Result<Self, DimensionTooLargerError> {
353 let stride = memory_format
354 .n_bytes()
355 .u32()
356 .checked_mul(width)
357 .ok_or(DimensionTooLargerError)?;
358
359 Ok(Self {
360 width,
361 height,
362 stride,
363 memory_format,
364 texture,
365 delay: None.into(),
366 details: Default::default(),
367 })
368 }
369
370 pub fn n_bytes(&self) -> Result<usize, DimensionTooLargerError> {
371 self.stride.try_usize()?.smul(self.height.try_usize()?)
372 }
373
374 pub fn into_fungible(self) -> Frame<FungibleMemory> {
375 Frame {
376 width: self.width,
377 height: self.height,
378 stride: self.stride,
379 memory_format: self.memory_format,
380 texture: self.texture.into_fungible(),
381 delay: self.delay,
382 details: self.details.into_fungible(),
383 }
384 }
385
386 pub fn into_other<O: ByteData>(self) -> Result<Frame<O>, MemoryAllocationError> {
387 Ok(Frame {
388 width: self.width,
389 height: self.height,
390 stride: self.stride,
391 memory_format: self.memory_format,
392 texture: self.texture.into_other()?,
393 delay: self.delay,
394 details: self.details.into_other()?,
395 })
396 }
397
398 pub fn desc(&self) -> String {
399 format!(
400 "{}x{} stride: {}, natural_stride: {}",
401 self.width,
402 self.height,
403 self.stride,
404 self.width * self.memory_format.n_bytes().u32()
405 )
406 }
407
408 pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
409 self.texture.initial_seal().await?;
410 self.details.initial_seal().await
411 }
412
413 pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
414 self.texture.final_seal().await?;
415 self.details.final_seal().await
416 }
417}
418
419#[derive(Debug)]
420#[cfg_attr(
421 feature = "external",
422 derive(Type, serde::Serialize, serde::Deserialize)
423)]
424#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
425#[cfg_attr(
426 feature = "external",
427 serde(bound(
428 serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
429 deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
430 ))
431)]
432#[non_exhaustive]
434pub struct FrameDetails<B: ByteData> {
436 #[cfg_attr(
438 feature = "external",
439 serde(
440 with = "as_value::optional",
441 skip_serializing_if = "Option::is_none",
442 default
443 )
444 )]
445 pub color_icc_profile: Option<B>,
446 #[cfg_attr(
448 feature = "external",
449 serde(
450 with = "as_value::optional",
451 skip_serializing_if = "Option::is_none",
452 default
453 )
454 )]
455 pub color_cicp: Option<[u8; 4]>,
456 #[cfg_attr(
460 feature = "external",
461 serde(
462 with = "as_value::optional",
463 skip_serializing_if = "Option::is_none",
464 default
465 )
466 )]
467 pub info_bit_depth: Option<u8>,
468 #[cfg_attr(
472 feature = "external",
473 serde(
474 with = "as_value::optional",
475 skip_serializing_if = "Option::is_none",
476 default
477 )
478 )]
479 pub info_alpha_channel: Option<bool>,
480 #[cfg_attr(
484 feature = "external",
485 serde(
486 with = "as_value::optional",
487 skip_serializing_if = "Option::is_none",
488 default
489 )
490 )]
491 pub info_grayscale: Option<bool>,
492 #[cfg_attr(
493 feature = "external",
494 serde(
495 with = "as_value::optional",
496 skip_serializing_if = "Option::is_none",
497 default
498 )
499 )]
500 pub n_frame: Option<u64>,
501}
502
503impl<B: ByteData> FrameDetails<B> {
504 pub fn into_fungible(self) -> FrameDetails<FungibleMemory> {
505 FrameDetails {
506 color_icc_profile: self.color_icc_profile.map(B::into_fungible),
507 color_cicp: self.color_cicp,
508 info_bit_depth: self.info_bit_depth,
509 info_alpha_channel: self.info_alpha_channel,
510 info_grayscale: self.info_grayscale,
511 n_frame: self.n_frame,
512 }
513 }
514
515 pub fn into_other<O: ByteData>(self) -> Result<FrameDetails<O>, MemoryAllocationError> {
516 Ok(FrameDetails {
517 color_icc_profile: self.color_icc_profile.map(B::into_other).transpose()?,
518 color_cicp: self.color_cicp,
519 info_bit_depth: self.info_bit_depth,
520 info_alpha_channel: self.info_alpha_channel,
521 info_grayscale: self.info_grayscale,
522 n_frame: self.n_frame,
523 })
524 }
525
526 pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
527 if let Some(color_icc_profile) = &mut self.color_icc_profile {
528 color_icc_profile.initial_seal().await?;
529 }
530
531 Ok(())
532 }
533
534 pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
535 if let Some(color_icc_profile) = &mut self.color_icc_profile {
536 color_icc_profile.final_seal().await?;
537 }
538
539 Ok(())
540 }
541}