Skip to main content

img_gen_spec/validators/layers/
background.rs

1use super::{ColorKind, PreserveAspect};
2
3#[cfg(feature = "pyo3")]
4use pyo3::prelude::*;
5
6use serde::{Deserialize, Serialize};
7
8/// An attribute to describe a [`Layer`](struct@crate::Layer)'s
9/// ``background``.
10#[cfg_attr(
11    feature = "pyo3",
12    pyclass(module = "img_gen", get_all, set_all, from_py_object)
13)]
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct Background {
16    /// A path to an image file.
17    ///
18    /// If the given image path has no file extension, then
19    /// it will be treated as an SVG image.
20    ///
21    /// This also supports built-in SVG icons from the following icon packs:
22    ///
23    /// - Material Design Icons (``material/{icon_slug}``)
24    /// - Simple Icons (``simple/{icon_slug}``)
25    /// - Octicons (``octicons/{icon_slug}``)
26    /// - FontAwesome Free (``fontawesome/<brands|solid|regular>/{icon_slug}``)
27    ///
28    /// Otherwise, the image file's path is resolved via a search through the list of
29    /// ``external_resource_paths`` provided to the ``Generator`` (in `img_gen_renderer` crate),
30    /// which defaults to the current working directory if unspecified or an empty list.
31    pub image: Option<String>,
32    /// A color overlaid on top of the `image`.
33    /// If no image is specified, then the layer is simple filled with this color.
34    #[serde(
35        alias = "linear_gradient",
36        alias = "radial_gradient",
37        alias = "conical_gradient",
38        alias = "linear-gradient",
39        alias = "radial-gradient",
40        alias = "conical-gradient"
41    )]
42    pub color: Option<ColorKind>,
43    /// This controls how the original image is rendered into the layer.
44    /// Default is to preserve the original image's width and height.
45    #[serde(default = "Background::default_preserve_aspect")]
46    pub preserve_aspect: PreserveAspect,
47}
48
49impl Background {
50    const fn default_preserve_aspect() -> PreserveAspect {
51        PreserveAspect::Off
52    }
53}
54
55impl Default for Background {
56    fn default() -> Self {
57        Self {
58            image: None,
59            color: None,
60            preserve_aspect: Self::default_preserve_aspect(),
61        }
62    }
63}
64
65#[cfg(test)]
66mod test {
67    #![allow(clippy::unwrap_used, clippy::panic)]
68
69    use super::Background;
70
71    #[test]
72    fn duplicate_color_last_wins() {
73        let yaml = "color: red\ncolor: blue\n";
74        let opts = serde_saphyr::options! {
75            duplicate_keys: serde_saphyr::options::DuplicateKeyPolicy::LastWins,
76        };
77        // Parse into an intermediate `serde_json::Value` with LastWins, then deserialize
78        let bg: Background = serde_saphyr::from_str_with_options(yaml, opts).unwrap();
79        assert!(
80            matches!(bg.color.unwrap(), super::ColorKind::SolidColor(sc) if sc.to_tuple() == (0, 0, 255, 255))
81        );
82    }
83}