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 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 #[cfg_attr(
72 feature = "external",
73 serde(with = "optional", skip_serializing_if = "Option::is_none", default)
74 )]
75 pub scale: Option<(u32, u32)>,
76 #[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 #[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#[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 #[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 #[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 #[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 #[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 pub stride: u32,
332 pub memory_format: MemoryFormat,
333 pub texture: B,
334 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#[non_exhaustive]
442pub struct FrameDetails<B: ByteData> {
444 #[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 #[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 #[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 #[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 #[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 #[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}