[go: up one dir, main page]

gltf/
image.rs

1#[allow(unused)]
2use crate::{buffer, Document, Error, Result};
3
4#[cfg(feature = "import")]
5#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
6use image_crate::DynamicImage;
7#[cfg(feature = "extensions")]
8use serde_json::{Map, Value};
9
10/// Format of image pixel data.
11#[cfg(feature = "import")]
12#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
13#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14pub enum Format {
15    /// Red only.
16    R8,
17
18    /// Red, green.
19    R8G8,
20
21    /// Red, green, blue.
22    R8G8B8,
23
24    /// Red, green, blue, alpha.
25    R8G8B8A8,
26
27    /// Red only (16 bits).
28    R16,
29
30    /// Red, green (16 bits).
31    R16G16,
32
33    /// Red, green, blue (16 bits).
34    R16G16B16,
35
36    /// Red, green, blue, alpha (16 bits).
37    R16G16B16A16,
38
39    /// Red, green, blue (32 bits float)
40    R32G32B32FLOAT,
41
42    /// Red, green, blue, alpha (32 bits float)
43    R32G32B32A32FLOAT,
44}
45
46/// Describes an image data source.
47#[derive(Clone, Debug)]
48pub enum Source<'a> {
49    /// Image data is contained in a buffer view.
50    View {
51        /// The buffer view containing the encoded image data.
52        view: buffer::View<'a>,
53
54        /// The image data MIME type.
55        mime_type: &'a str,
56    },
57
58    /// Image data is contained in an external data source.
59    Uri {
60        /// The URI of the external data source.
61        uri: &'a str,
62
63        /// The image data MIME type, if provided.
64        mime_type: Option<&'a str>,
65    },
66}
67
68/// Image data used to create a texture.
69#[derive(Clone, Debug)]
70pub struct Image<'a> {
71    /// The parent `Document` struct.
72    document: &'a Document,
73
74    /// The corresponding JSON index.
75    index: usize,
76
77    /// The corresponding JSON struct.
78    json: &'a json::image::Image,
79}
80
81/// Image data belonging to an imported glTF asset.
82#[cfg(feature = "import")]
83#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
84#[derive(Clone, Debug)]
85pub struct Data {
86    /// The image pixel data (8 bits per channel).
87    pub pixels: Vec<u8>,
88
89    /// The image pixel data format.
90    pub format: Format,
91
92    /// The image width in pixels.
93    pub width: u32,
94
95    /// The image height in pixels.
96    pub height: u32,
97}
98
99impl<'a> Image<'a> {
100    /// Constructs an `Image` from owned data.
101    pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::image::Image) -> Self {
102        Self {
103            document,
104            index,
105            json,
106        }
107    }
108
109    /// Returns the internal JSON index.
110    pub fn index(&self) -> usize {
111        self.index
112    }
113
114    /// Optional user-defined name for this object.
115    #[cfg(feature = "names")]
116    #[cfg_attr(docsrs, doc(cfg(feature = "names")))]
117    pub fn name(&self) -> Option<&'a str> {
118        self.json.name.as_deref()
119    }
120
121    /// Returns the image data source.
122    pub fn source(&self) -> Source<'a> {
123        if let Some(index) = self.json.buffer_view.as_ref() {
124            let view = self.document.views().nth(index.value()).unwrap();
125            let mime_type = self.json.mime_type.as_ref().map(|x| x.0.as_str()).unwrap();
126            Source::View { view, mime_type }
127        } else {
128            let uri = self.json.uri.as_ref().unwrap();
129            let mime_type = self.json.mime_type.as_ref().map(|x| x.0.as_str());
130            Source::Uri { uri, mime_type }
131        }
132    }
133
134    /// Returns extension data unknown to this crate version.
135    #[cfg(feature = "extensions")]
136    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
137    pub fn extensions(&self) -> Option<&Map<String, Value>> {
138        let ext = self.json.extensions.as_ref()?;
139        Some(&ext.others)
140    }
141
142    /// Queries extension data unknown to this crate version.
143    #[cfg(feature = "extensions")]
144    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
145    pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
146        let ext = self.json.extensions.as_ref()?;
147        ext.others.get(ext_name)
148    }
149
150    /// Optional application specific data.
151    pub fn extras(&self) -> &'a json::Extras {
152        &self.json.extras
153    }
154}
155
156#[cfg(feature = "import")]
157impl Data {
158    /// Note: We don't implement `From<DynamicImage>` since we don't want
159    /// to expose such functionality to the user.
160    pub(crate) fn new(image: DynamicImage) -> Result<Self> {
161        use image_crate::GenericImageView;
162        let format = match image {
163            DynamicImage::ImageLuma8(_) => Format::R8,
164            DynamicImage::ImageLumaA8(_) => Format::R8G8,
165            DynamicImage::ImageRgb8(_) => Format::R8G8B8,
166            DynamicImage::ImageRgba8(_) => Format::R8G8B8A8,
167            DynamicImage::ImageLuma16(_) => Format::R16,
168            DynamicImage::ImageLumaA16(_) => Format::R16G16,
169            DynamicImage::ImageRgb16(_) => Format::R16G16B16,
170            DynamicImage::ImageRgba16(_) => Format::R16G16B16A16,
171            DynamicImage::ImageRgb32F(_) => Format::R32G32B32FLOAT,
172            DynamicImage::ImageRgba32F(_) => Format::R32G32B32A32FLOAT,
173            image => return Err(Error::UnsupportedImageFormat(image)),
174        };
175        let (width, height) = image.dimensions();
176        let pixels = image.into_bytes();
177        Ok(Data {
178            format,
179            width,
180            height,
181            pixels,
182        })
183    }
184}