Skip to main content

glycin_utils/api/
loader.rs

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    /// Source from which the loader reads the image data
33    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    /// Scale image to these dimensions
70    #[cfg_attr(
71        feature = "external",
72        serde(with = "optional", skip_serializing_if = "Option::is_none", default)
73    )]
74    pub scale: Option<(u32, u32)>,
75    /// Instruction to only decode part of the image
76    #[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    /// Get first frame, if previously selected frame was the last one
82    #[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/// Various image metadata
97///
98/// This is returned from the initial `InitRequest` call
99#[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    /// Early dimension information.
145    ///
146    /// This information is often correct. However, it should only be used for
147    /// an early rendering estimates. For everything else, the specific frame
148    /// information should be used.
149    #[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    /// Image dimensions in inch
154    #[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    /// Textual description of the image dimensions
173    #[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    /// Explicit orientation. If `None` check Exif or XMP.
212    #[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    /// Line stride
323    pub stride: u32,
324    pub memory_format: MemoryFormat,
325    pub texture: B,
326    /// Duration to show frame for animations.
327    ///
328    /// If the value is not set, the image is not animated.
329    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//#[serde(bound(deserialize = "B: ByteData"))]
433#[non_exhaustive]
434/// More information about a frame
435pub struct FrameDetails<B: ByteData> {
436    /// ICC color profile
437    #[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    /// Coding-independent code points (HDR information)
447    #[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    /// Bit depth per channel
457    ///
458    /// Only set if it can differ for the format
459    #[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    /// Image has alpha channel
469    ///
470    /// Only set if it can differ for the format
471    #[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    /// Image uses grayscale mode
481    ///
482    /// Only set if it can differ for the format
483    #[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}