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::{ColorProfilePreference, MemoryFormat, MemoryFormatInfo};
6use gufo_common::orientation::Orientation;
7use gufo_common::physical_dimension;
8#[cfg(feature = "external")]
9use zbus::zvariant::as_value::{self, optional};
10#[cfg(feature = "external")]
11use zbus::zvariant::{self, Optional, Type};
12
13use crate::error::DimensionTooLargerError;
14use crate::safe_math::{SafeConversion, SafeMath};
15use crate::{ByteData, FungibleMemory, Limits, MemoryAllocationError, ProcessError};
16
17pub trait LoaderImplementation: Send + Sync + Sized + 'static {
18    fn load<B: ByteData, R: Read + Send + 'static>(
19        stream: R,
20        mime_type: String,
21        details: InitializationDetails,
22    ) -> Result<(Self, ImageDetails<B>), ProcessError>;
23
24    fn specific_frame<T: ByteData>(
25        &mut self,
26        frame_request: FrameRequest,
27    ) -> Result<Frame<T>, ProcessError>;
28}
29
30#[cfg(feature = "external")]
31#[derive(serde::Deserialize, serde::Serialize, Type, Debug)]
32pub struct InitRequest {
33    /// Source from which the loader reads the image data
34    pub fd: zvariant::OwnedFd,
35    pub mime_type: String,
36    pub details: InitializationDetails,
37}
38
39#[derive(Debug, Default)]
40#[cfg_attr(
41    feature = "external",
42    derive(serde::Deserialize, serde::Serialize, Type)
43)]
44#[cfg_attr(feature = "external", zvariant(signature = "a{sv}"))]
45#[cfg_attr(feature = "external", serde(default))]
46#[non_exhaustive]
47pub struct InitializationDetails {
48    #[cfg_attr(
49        feature = "external",
50        serde(with = "optional", skip_serializing_if = "Option::is_none")
51    )]
52    pub base_dir: Option<std::path::PathBuf>,
53    #[cfg_attr(feature = "external", serde(with = "as_value"))]
54    pub limits: Limits,
55}
56
57#[cfg(feature = "external")]
58const fn true_const() -> bool {
59    true
60}
61
62#[derive(Debug, Clone)]
63#[cfg_attr(
64    feature = "external",
65    derive(serde::Deserialize, serde::Serialize, Type)
66)]
67#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
68#[non_exhaustive]
69pub struct FrameRequest {
70    /// Scale image to these dimensions
71    #[cfg_attr(
72        feature = "external",
73        serde(with = "optional", skip_serializing_if = "Option::is_none", default)
74    )]
75    pub scale: Option<(u32, u32)>,
76    /// Instruction to only decode part of the image
77    #[cfg_attr(
78        feature = "external",
79        serde(with = "optional", skip_serializing_if = "Option::is_none", default)
80    )]
81    pub clip: Option<(u32, u32, u32, u32)>,
82    /// Get first frame, if previously selected frame was the last one
83    #[cfg_attr(feature = "external", serde(with = "as_value", default = "true_const"))]
84    pub loop_animation: bool,
85}
86
87impl Default for FrameRequest {
88    fn default() -> Self {
89        Self {
90            scale: None,
91            clip: None,
92            loop_animation: true,
93        }
94    }
95}
96
97/// Various image metadata
98///
99/// This is returned from the initial `InitRequest` call
100#[cfg(feature = "external")]
101#[derive(Debug, Type, serde::Serialize, serde::Deserialize)]
102#[serde(bound(
103    serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
104    deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
105))]
106#[non_exhaustive]
107pub struct RemoteImage<B: ByteData> {
108    pub frame_request: zvariant::OwnedObjectPath,
109    pub details: ImageDetails<B>,
110}
111
112#[cfg(feature = "external")]
113impl<B: ByteData> RemoteImage<B> {
114    pub fn new(details: ImageDetails<B>, frame_request: zvariant::OwnedObjectPath) -> Self {
115        Self {
116            frame_request,
117            details,
118        }
119    }
120
121    pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
122        self.details.initial_seal().await
123    }
124
125    pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
126        self.details.final_seal().await
127    }
128}
129
130#[derive(Debug)]
131#[cfg_attr(
132    feature = "external",
133    derive(Type, serde::Serialize, serde::Deserialize)
134)]
135#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
136#[cfg_attr(
137    feature = "external",
138    serde(bound(
139        serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
140        deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
141    ))
142)]
143#[non_exhaustive]
144pub struct ImageDetails<B: ByteData> {
145    /// Early dimension information.
146    ///
147    /// This information is often correct. However, it should only be used for
148    /// an early rendering estimates. For everything else, the specific frame
149    /// information should be used.
150    #[cfg_attr(feature = "external", serde(with = "as_value"))]
151    pub width: u32,
152    #[cfg_attr(feature = "external", serde(with = "as_value"))]
153    pub height: u32,
154    /// Image dimensions in inch
155    #[cfg_attr(
156        feature = "external",
157        serde(
158            with = "as_value::optional",
159            skip_serializing_if = "Option::is_none",
160            default
161        )
162    )]
163    #[deprecated]
164    pub dimensions_inch: Option<(f64, f64)>,
165    #[cfg_attr(
166        feature = "external",
167        serde(
168            with = "as_value::optional",
169            skip_serializing_if = "Option::is_none",
170            default
171        )
172    )]
173    pub info_format_name: Option<String>,
174    /// Textual description of the image dimensions
175    #[cfg_attr(
176        feature = "external",
177        serde(
178            with = "as_value::optional",
179            skip_serializing_if = "Option::is_none",
180            default
181        )
182    )]
183    pub info_dimensions_text: Option<String>,
184    #[cfg_attr(
185        feature = "external",
186        serde(
187            with = "as_value::optional",
188            skip_serializing_if = "Option::is_none",
189            default
190        )
191    )]
192    pub metadata_exif: Option<B>,
193    #[cfg_attr(
194        feature = "external",
195        serde(
196            with = "as_value::optional",
197            skip_serializing_if = "Option::is_none",
198            default
199        )
200    )]
201    pub metadata_xmp: Option<B>,
202    #[cfg_attr(
203        feature = "external",
204        serde(
205            with = "as_value::optional",
206            skip_serializing_if = "Option::is_none",
207            default
208        )
209    )]
210    pub metadata_key_value: Option<BTreeMap<String, String>>,
211    #[cfg_attr(feature = "external", serde(with = "as_value"))]
212    pub transformation_ignore_exif: bool,
213    /// Explicit orientation. If `None` check Exif or XMP.
214    #[cfg_attr(
215        feature = "external",
216        serde(
217            with = "as_value::optional",
218            skip_serializing_if = "Option::is_none",
219            default
220        )
221    )]
222    pub transformation_orientation: Option<Orientation>,
223}
224
225impl<B: ByteData> ImageDetails<B> {
226    pub fn new(width: u32, height: u32) -> Self {
227        Self {
228            width,
229            height,
230            #[allow(deprecated)]
231            dimensions_inch: None,
232            info_dimensions_text: None,
233            info_format_name: None,
234            metadata_exif: None,
235            metadata_xmp: None,
236            metadata_key_value: None,
237            transformation_ignore_exif: false,
238            transformation_orientation: None,
239        }
240    }
241
242    pub fn into_fungible(self) -> ImageDetails<FungibleMemory> {
243        ImageDetails {
244            width: self.width,
245            height: self.height,
246            #[allow(deprecated)]
247            dimensions_inch: self.dimensions_inch,
248            info_format_name: self.info_format_name,
249            info_dimensions_text: self.info_dimensions_text,
250            metadata_exif: self.metadata_exif.map(B::into_fungible),
251            metadata_xmp: self.metadata_xmp.map(B::into_fungible),
252            metadata_key_value: self.metadata_key_value,
253            transformation_ignore_exif: self.transformation_ignore_exif,
254            transformation_orientation: self.transformation_orientation,
255        }
256    }
257
258    pub fn into_other<O: ByteData>(self) -> Result<ImageDetails<O>, MemoryAllocationError> {
259        Ok(ImageDetails {
260            width: self.width,
261            height: self.height,
262            #[allow(deprecated)]
263            dimensions_inch: self.dimensions_inch,
264            info_format_name: self.info_format_name,
265            info_dimensions_text: self.info_dimensions_text,
266            metadata_exif: self.metadata_exif.map(|x| x.into_other()).transpose()?,
267            metadata_xmp: self.metadata_xmp.map(|x| x.into_other()).transpose()?,
268            metadata_key_value: self.metadata_key_value,
269            transformation_ignore_exif: self.transformation_ignore_exif,
270            transformation_orientation: self.transformation_orientation,
271        })
272    }
273
274    pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
275        if let Some(metadata_exif) = &mut self.metadata_exif {
276            metadata_exif.initial_seal().await?;
277        }
278
279        if let Some(metadata_xmp) = &mut self.metadata_xmp {
280            metadata_xmp.initial_seal().await?;
281        }
282
283        Ok(())
284    }
285
286    pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
287        if let Some(metadata_exif) = &mut self.metadata_exif {
288            metadata_exif.final_seal().await?;
289        }
290
291        if let Some(metadata_xmp) = &mut self.metadata_xmp {
292            metadata_xmp.final_seal().await?;
293        }
294
295        Ok(())
296    }
297}
298
299impl<B: ByteData> Default for FrameDetails<B> {
300    fn default() -> Self {
301        Self {
302            color_icc_profile: None,
303            color_cicp: None,
304            color_profile_preference: None,
305            info_bit_depth: None,
306            info_alpha_channel: None,
307            info_grayscale: None,
308            n_frame: None,
309            pixel_density: None,
310            physical_size: None,
311        }
312    }
313}
314
315#[cfg(not(feature = "external"))]
316pub type Optional<T> = Option<T>;
317
318#[derive(Debug)]
319#[cfg_attr(feature = "external", derive(serde::Serialize, serde::Deserialize))]
320#[cfg_attr(
321    feature = "external",
322    serde(bound(
323        serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
324        deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
325    ))
326)]
327pub struct Frame<B: ByteData> {
328    pub width: u32,
329    pub height: u32,
330    /// Line stride
331    pub stride: u32,
332    pub memory_format: MemoryFormat,
333    pub texture: B,
334    /// Duration to show frame for animations.
335    ///
336    /// If the value is not set, the image is not animated.
337    pub delay: Optional<Duration>,
338    pub details: FrameDetails<B>,
339}
340
341#[cfg(feature = "external")]
342impl<B: ByteData + zvariant::Type> zvariant::Type for Frame<B> {
343    const SIGNATURE: &'static zvariant::Signature = <(
344        u32,
345        u32,
346        u32,
347        MemoryFormat,
348        B,
349        Optional<Duration>,
350        FrameDetails<B>,
351    )>::SIGNATURE;
352}
353
354impl<B: ByteData> Frame<B> {
355    pub fn new(
356        width: u32,
357        height: u32,
358        memory_format: MemoryFormat,
359        texture: B,
360    ) -> Result<Self, DimensionTooLargerError> {
361        let stride = memory_format
362            .n_bytes()
363            .u32()
364            .checked_mul(width)
365            .ok_or(DimensionTooLargerError)?;
366
367        Ok(Self {
368            width,
369            height,
370            stride,
371            memory_format,
372            texture,
373            delay: None.into(),
374            details: Default::default(),
375        })
376    }
377
378    pub fn n_bytes(&self) -> Result<usize, DimensionTooLargerError> {
379        self.stride.try_usize()?.smul(self.height.try_usize()?)
380    }
381
382    pub fn into_fungible(self) -> Frame<FungibleMemory> {
383        Frame {
384            width: self.width,
385            height: self.height,
386            stride: self.stride,
387            memory_format: self.memory_format,
388            texture: self.texture.into_fungible(),
389            delay: self.delay,
390            details: self.details.into_fungible(),
391        }
392    }
393
394    pub fn into_other<O: ByteData>(self) -> Result<Frame<O>, MemoryAllocationError> {
395        Ok(Frame {
396            width: self.width,
397            height: self.height,
398            stride: self.stride,
399            memory_format: self.memory_format,
400            texture: self.texture.into_other()?,
401            delay: self.delay,
402            details: self.details.into_other()?,
403        })
404    }
405
406    pub fn desc(&self) -> String {
407        format!(
408            "{}x{} stride: {}, natural_stride: {}",
409            self.width,
410            self.height,
411            self.stride,
412            self.width * self.memory_format.n_bytes().u32()
413        )
414    }
415
416    pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
417        self.texture.initial_seal().await?;
418        self.details.initial_seal().await
419    }
420
421    pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
422        self.texture.final_seal().await?;
423        self.details.final_seal().await
424    }
425}
426
427#[derive(Debug)]
428#[cfg_attr(
429    feature = "external",
430    derive(Type, serde::Serialize, serde::Deserialize)
431)]
432#[cfg_attr(feature = "external", zvariant(signature = "dict"))]
433#[cfg_attr(
434    feature = "external",
435    serde(bound(
436        serialize = "B: ByteData + serde::Serialize + zbus::zvariant::Type + 'static",
437        deserialize = "B: ByteData + serde::de::DeserializeOwned + zbus::zvariant::Type + 'static"
438    ))
439)]
440//#[serde(bound(deserialize = "B: ByteData"))]
441#[non_exhaustive]
442/// More information about a frame
443pub struct FrameDetails<B: ByteData> {
444    /// ICC color profile
445    #[cfg_attr(
446        feature = "external",
447        serde(
448            with = "as_value::optional",
449            skip_serializing_if = "Option::is_none",
450            default
451        )
452    )]
453    pub color_icc_profile: Option<B>,
454    /// Coding-independent code points (HDR information)
455    #[cfg_attr(
456        feature = "external",
457        serde(
458            with = "as_value::optional",
459            skip_serializing_if = "Option::is_none",
460            default
461        )
462    )]
463    pub color_cicp: Option<[u8; 4]>,
464    /// Which profile to use if ICC profile and CICP are defined
465    #[cfg_attr(
466        feature = "external",
467        serde(
468            with = "as_value::optional",
469            skip_serializing_if = "Option::is_none",
470            default
471        )
472    )]
473    pub color_profile_preference: Option<ColorProfilePreference>,
474    /// Bit depth per channel
475    ///
476    /// Only set if it can differ for the format
477    #[cfg_attr(
478        feature = "external",
479        serde(
480            with = "as_value::optional",
481            skip_serializing_if = "Option::is_none",
482            default
483        )
484    )]
485    pub info_bit_depth: Option<u8>,
486    /// Image has alpha channel
487    ///
488    /// Only set if it can differ for the format
489    #[cfg_attr(
490        feature = "external",
491        serde(
492            with = "as_value::optional",
493            skip_serializing_if = "Option::is_none",
494            default
495        )
496    )]
497    pub info_alpha_channel: Option<bool>,
498    /// Image uses grayscale mode
499    ///
500    /// Only set if it can differ for the format
501    #[cfg_attr(
502        feature = "external",
503        serde(
504            with = "as_value::optional",
505            skip_serializing_if = "Option::is_none",
506            default
507        )
508    )]
509    pub info_grayscale: Option<bool>,
510    #[cfg_attr(
511        feature = "external",
512        serde(
513            with = "as_value::optional",
514            skip_serializing_if = "Option::is_none",
515            default
516        )
517    )]
518    pub n_frame: Option<u64>,
519    #[cfg_attr(
520        feature = "external",
521        serde(
522            with = "as_value::optional",
523            skip_serializing_if = "Option::is_none",
524            default
525        )
526    )]
527    pub pixel_density: Option<physical_dimension::PixelDensity>,
528    #[cfg_attr(
529        feature = "external",
530        serde(
531            with = "as_value::optional",
532            skip_serializing_if = "Option::is_none",
533            default
534        )
535    )]
536    pub physical_size: Option<physical_dimension::PhysicalSize>,
537}
538
539impl<B: ByteData> FrameDetails<B> {
540    pub fn into_fungible(self) -> FrameDetails<FungibleMemory> {
541        FrameDetails {
542            color_icc_profile: self.color_icc_profile.map(B::into_fungible),
543            color_cicp: self.color_cicp,
544            color_profile_preference: self.color_profile_preference,
545            info_bit_depth: self.info_bit_depth,
546            info_alpha_channel: self.info_alpha_channel,
547            info_grayscale: self.info_grayscale,
548            n_frame: self.n_frame,
549            pixel_density: self.pixel_density,
550            physical_size: self.physical_size,
551        }
552    }
553
554    pub fn into_other<O: ByteData>(self) -> Result<FrameDetails<O>, MemoryAllocationError> {
555        Ok(FrameDetails {
556            color_icc_profile: self.color_icc_profile.map(B::into_other).transpose()?,
557            color_cicp: self.color_cicp,
558            color_profile_preference: self.color_profile_preference,
559            info_bit_depth: self.info_bit_depth,
560            info_alpha_channel: self.info_alpha_channel,
561            info_grayscale: self.info_grayscale,
562            n_frame: self.n_frame,
563            pixel_density: self.pixel_density,
564            physical_size: self.physical_size,
565        })
566    }
567
568    pub async fn initial_seal(&mut self) -> Result<(), MemoryAllocationError> {
569        if let Some(color_icc_profile) = &mut self.color_icc_profile {
570            color_icc_profile.initial_seal().await?;
571        }
572
573        Ok(())
574    }
575
576    pub async fn final_seal(&mut self) -> Result<(), MemoryAllocationError> {
577        if let Some(color_icc_profile) = &mut self.color_icc_profile {
578            color_icc_profile.final_seal().await?;
579        }
580
581        Ok(())
582    }
583}