moxcms/
tag.rs

1/*
2 * // Copyright (c) Radzivon Bartoshyk 3/2025. All rights reserved.
3 * //
4 * // Redistribution and use in source and binary forms, with or without modification,
5 * // are permitted provided that the following conditions are met:
6 * //
7 * // 1.  Redistributions of source code must retain the above copyright notice, this
8 * // list of conditions and the following disclaimer.
9 * //
10 * // 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * // this list of conditions and the following disclaimer in the documentation
12 * // and/or other materials provided with the distribution.
13 * //
14 * // 3.  Neither the name of the copyright holder nor the names of its
15 * // contributors may be used to endorse or promote products derived from
16 * // this software without specific prior written permission.
17 * //
18 * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29use crate::CmsError;
30
31pub(crate) const TAG_SIZE: usize = 12;
32
33#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
34pub(crate) enum Tag {
35    RedXyz,
36    GreenXyz,
37    BlueXyz,
38    RedToneReproduction,
39    GreenToneReproduction,
40    BlueToneReproduction,
41    GreyToneReproduction,
42    MediaWhitePoint,
43    CodeIndependentPoints,
44    ChromaticAdaptation,
45    BlackPoint,
46    DeviceToPcsLutPerceptual,
47    DeviceToPcsLutColorimetric,
48    DeviceToPcsLutSaturation,
49    PcsToDeviceLutPerceptual,
50    PcsToDeviceLutColorimetric,
51    PcsToDeviceLutSaturation,
52    ProfileDescription,
53    Copyright,
54    ViewingConditionsDescription,
55    DeviceManufacturer,
56    DeviceModel,
57    Gamut,
58    Luminance,
59    Measurement,
60    Chromaticity,
61    ObserverConditions,
62    CharTarget,
63    Technology,
64    CalibrationDateTime,
65}
66
67impl TryFrom<u32> for Tag {
68    type Error = CmsError;
69
70    fn try_from(value: u32) -> Result<Self, Self::Error> {
71        if value == u32::from_ne_bytes(*b"rXYZ").to_be() {
72            return Ok(Self::RedXyz);
73        } else if value == u32::from_ne_bytes(*b"gXYZ").to_be() {
74            return Ok(Self::GreenXyz);
75        } else if value == u32::from_ne_bytes(*b"bXYZ").to_be() {
76            return Ok(Self::BlueXyz);
77        } else if value == u32::from_ne_bytes(*b"rTRC").to_be() {
78            return Ok(Self::RedToneReproduction);
79        } else if value == u32::from_ne_bytes(*b"gTRC").to_be() {
80            return Ok(Self::GreenToneReproduction);
81        } else if value == u32::from_ne_bytes(*b"bTRC").to_be() {
82            return Ok(Self::BlueToneReproduction);
83        } else if value == u32::from_ne_bytes(*b"kTRC").to_be() {
84            return Ok(Self::GreyToneReproduction);
85        } else if value == u32::from_ne_bytes(*b"wtpt").to_be() {
86            return Ok(Self::MediaWhitePoint);
87        } else if value == u32::from_ne_bytes(*b"cicp").to_be() {
88            return Ok(Self::CodeIndependentPoints);
89        } else if value == u32::from_ne_bytes(*b"chad").to_be() {
90            return Ok(Self::ChromaticAdaptation);
91        } else if value == u32::from_ne_bytes(*b"bkpt").to_be() {
92            return Ok(Self::BlackPoint);
93        } else if value == u32::from_ne_bytes(*b"A2B0").to_be() {
94            return Ok(Self::DeviceToPcsLutPerceptual);
95        } else if value == u32::from_ne_bytes(*b"A2B1").to_be() {
96            return Ok(Self::DeviceToPcsLutColorimetric);
97        } else if value == u32::from_ne_bytes(*b"A2B2").to_be() {
98            return Ok(Self::DeviceToPcsLutSaturation);
99        } else if value == u32::from_ne_bytes(*b"B2A0").to_be() {
100            return Ok(Self::PcsToDeviceLutPerceptual);
101        } else if value == u32::from_ne_bytes(*b"B2A1").to_be() {
102            return Ok(Self::PcsToDeviceLutColorimetric);
103        } else if value == u32::from_ne_bytes(*b"B2A2").to_be() {
104            return Ok(Self::PcsToDeviceLutSaturation);
105        } else if value == u32::from_ne_bytes(*b"desc").to_be() {
106            return Ok(Self::ProfileDescription);
107        } else if value == u32::from_ne_bytes(*b"cprt").to_be() {
108            return Ok(Self::Copyright);
109        } else if value == u32::from_ne_bytes(*b"vued").to_be() {
110            return Ok(Self::ViewingConditionsDescription);
111        } else if value == u32::from_ne_bytes(*b"dmnd").to_be() {
112            return Ok(Self::DeviceManufacturer);
113        } else if value == u32::from_ne_bytes(*b"dmdd").to_be() {
114            return Ok(Self::DeviceModel);
115        } else if value == u32::from_ne_bytes(*b"gamt").to_be() {
116            return Ok(Self::Gamut);
117        } else if value == u32::from_ne_bytes(*b"lumi").to_be() {
118            return Ok(Self::Luminance);
119        } else if value == u32::from_ne_bytes(*b"meas").to_be() {
120            return Ok(Self::Measurement);
121        } else if value == u32::from_ne_bytes(*b"chrm").to_be() {
122            return Ok(Self::Chromaticity);
123        } else if value == u32::from_ne_bytes(*b"view").to_be() {
124            return Ok(Self::ObserverConditions);
125        } else if value == u32::from_ne_bytes(*b"targ").to_be() {
126            return Ok(Self::CharTarget);
127        } else if value == u32::from_ne_bytes(*b"tech").to_be() {
128            return Ok(Self::Technology);
129        } else if value == u32::from_ne_bytes(*b"calt").to_be() {
130            return Ok(Self::CalibrationDateTime);
131        }
132        Err(CmsError::UnknownTag(value))
133    }
134}
135
136impl From<Tag> for u32 {
137    fn from(value: Tag) -> Self {
138        match value {
139            Tag::RedXyz => u32::from_ne_bytes(*b"rXYZ").to_be(),
140            Tag::GreenXyz => u32::from_ne_bytes(*b"gXYZ").to_be(),
141            Tag::BlueXyz => u32::from_ne_bytes(*b"bXYZ").to_be(),
142            Tag::RedToneReproduction => u32::from_ne_bytes(*b"rTRC").to_be(),
143            Tag::GreenToneReproduction => u32::from_ne_bytes(*b"gTRC").to_be(),
144            Tag::BlueToneReproduction => u32::from_ne_bytes(*b"bTRC").to_be(),
145            Tag::GreyToneReproduction => u32::from_ne_bytes(*b"kTRC").to_be(),
146            Tag::MediaWhitePoint => u32::from_ne_bytes(*b"wtpt").to_be(),
147            Tag::CodeIndependentPoints => u32::from_ne_bytes(*b"cicp").to_be(),
148            Tag::ChromaticAdaptation => u32::from_ne_bytes(*b"chad").to_be(),
149            Tag::BlackPoint => u32::from_ne_bytes(*b"bkpt").to_be(),
150            Tag::DeviceToPcsLutPerceptual => u32::from_ne_bytes(*b"A2B0").to_be(),
151            Tag::DeviceToPcsLutColorimetric => u32::from_ne_bytes(*b"A2B1").to_be(),
152            Tag::DeviceToPcsLutSaturation => u32::from_ne_bytes(*b"A2B2").to_be(),
153            Tag::PcsToDeviceLutPerceptual => u32::from_ne_bytes(*b"B2A0").to_be(),
154            Tag::PcsToDeviceLutColorimetric => u32::from_ne_bytes(*b"B2A1").to_be(),
155            Tag::PcsToDeviceLutSaturation => u32::from_ne_bytes(*b"B2A2").to_be(),
156            Tag::ProfileDescription => u32::from_ne_bytes(*b"desc").to_be(),
157            Tag::Copyright => u32::from_ne_bytes(*b"cprt").to_be(),
158            Tag::ViewingConditionsDescription => u32::from_ne_bytes(*b"vued").to_be(),
159            Tag::DeviceManufacturer => u32::from_ne_bytes(*b"dmnd").to_be(),
160            Tag::DeviceModel => u32::from_ne_bytes(*b"dmdd").to_be(),
161            Tag::Gamut => u32::from_ne_bytes(*b"gamt").to_be(),
162            Tag::Luminance => u32::from_ne_bytes(*b"lumi").to_be(),
163            Tag::Measurement => u32::from_ne_bytes(*b"meas").to_be(),
164            Tag::Chromaticity => u32::from_ne_bytes(*b"chrm").to_be(),
165            Tag::ObserverConditions => u32::from_ne_bytes(*b"view").to_be(),
166            Tag::CharTarget => u32::from_ne_bytes(*b"targ").to_be(),
167            Tag::Technology => u32::from_ne_bytes(*b"tech").to_be(),
168            Tag::CalibrationDateTime => u32::from_ne_bytes(*b"calt").to_be(),
169        }
170    }
171}
172
173#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
174pub(crate) enum TagTypeDefinition {
175    Text,
176    MultiLocalizedUnicode,
177    Description,
178    MabLut,
179    MbaLut,
180    ParametricToneCurve,
181    LutToneCurve,
182    Xyz,
183    MultiProcessElement,
184    DefViewingConditions,
185    Signature,
186    Cicp,
187    DateTime,
188    S15Fixed16Array,
189    U8Array,
190    U16Fixed16Array,
191    U16Array,
192    U32Array,
193    U64Array,
194    Measurement,
195    NotAllowed,
196}
197
198impl From<u32> for TagTypeDefinition {
199    fn from(value: u32) -> Self {
200        if value == u32::from_ne_bytes(*b"mluc").to_be() {
201            return TagTypeDefinition::MultiLocalizedUnicode;
202        } else if value == u32::from_ne_bytes(*b"desc").to_be() {
203            return TagTypeDefinition::Description;
204        } else if value == u32::from_ne_bytes(*b"text").to_be() {
205            return TagTypeDefinition::Text;
206        } else if value == u32::from_ne_bytes(*b"mAB ").to_be() {
207            return TagTypeDefinition::MabLut;
208        } else if value == u32::from_ne_bytes(*b"mBA ").to_be() {
209            return TagTypeDefinition::MbaLut;
210        } else if value == u32::from_ne_bytes(*b"para").to_be() {
211            return TagTypeDefinition::ParametricToneCurve;
212        } else if value == u32::from_ne_bytes(*b"curv").to_be() {
213            return TagTypeDefinition::LutToneCurve;
214        } else if value == u32::from_ne_bytes(*b"XYZ ").to_be() {
215            return TagTypeDefinition::Xyz;
216        } else if value == u32::from_ne_bytes(*b"mpet").to_be() {
217            return TagTypeDefinition::MultiProcessElement;
218        } else if value == u32::from_ne_bytes(*b"view").to_be() {
219            return TagTypeDefinition::DefViewingConditions;
220        } else if value == u32::from_ne_bytes(*b"sig ").to_be() {
221            return TagTypeDefinition::Signature;
222        } else if value == u32::from_ne_bytes(*b"cicp").to_be() {
223            return TagTypeDefinition::Cicp;
224        } else if value == u32::from_ne_bytes(*b"dtim").to_be() {
225            return TagTypeDefinition::DateTime;
226        } else if value == u32::from_ne_bytes(*b"meas").to_be() {
227            return TagTypeDefinition::Measurement;
228        } else if value == u32::from_ne_bytes(*b"sf32").to_be() {
229            return TagTypeDefinition::S15Fixed16Array;
230        } else if value == u32::from_ne_bytes(*b"uf32").to_be() {
231            return TagTypeDefinition::U16Fixed16Array;
232        } else if value == u32::from_ne_bytes(*b"ui16").to_be() {
233            return TagTypeDefinition::U16Array;
234        } else if value == u32::from_ne_bytes(*b"ui32").to_be() {
235            return TagTypeDefinition::U32Array;
236        } else if value == u32::from_ne_bytes(*b"ui64").to_be() {
237            return TagTypeDefinition::U64Array;
238        } else if value == u32::from_ne_bytes(*b"ui08").to_be() {
239            return TagTypeDefinition::U8Array;
240        }
241        TagTypeDefinition::NotAllowed
242    }
243}
244
245impl From<TagTypeDefinition> for u32 {
246    fn from(value: TagTypeDefinition) -> Self {
247        match value {
248            TagTypeDefinition::MultiLocalizedUnicode => u32::from_ne_bytes(*b"mluc").to_be(),
249            TagTypeDefinition::Description => u32::from_ne_bytes(*b"desc").to_be(),
250            TagTypeDefinition::Text => u32::from_ne_bytes(*b"text").to_be(),
251            TagTypeDefinition::MabLut => u32::from_ne_bytes(*b"mAB ").to_be(),
252            TagTypeDefinition::MbaLut => u32::from_ne_bytes(*b"mBA ").to_be(),
253            TagTypeDefinition::ParametricToneCurve => u32::from_ne_bytes(*b"para").to_be(),
254            TagTypeDefinition::LutToneCurve => u32::from_ne_bytes(*b"curv").to_be(),
255            TagTypeDefinition::Xyz => u32::from_ne_bytes(*b"XYZ ").to_be(),
256            TagTypeDefinition::MultiProcessElement => u32::from_ne_bytes(*b"mpet").to_be(),
257            TagTypeDefinition::DefViewingConditions => u32::from_ne_bytes(*b"view").to_be(),
258            TagTypeDefinition::Signature => u32::from_ne_bytes(*b"sig ").to_be(),
259            TagTypeDefinition::Cicp => u32::from_ne_bytes(*b"cicp").to_be(),
260            TagTypeDefinition::DateTime => u32::from_ne_bytes(*b"dtim").to_be(),
261            TagTypeDefinition::S15Fixed16Array => u32::from_ne_bytes(*b"sf32").to_be(),
262            TagTypeDefinition::U16Fixed16Array => u32::from_ne_bytes(*b"uf32").to_be(),
263            TagTypeDefinition::U8Array => u32::from_ne_bytes(*b"ui08").to_be(),
264            TagTypeDefinition::U16Array => u32::from_ne_bytes(*b"ui16").to_be(),
265            TagTypeDefinition::U32Array => u32::from_ne_bytes(*b"ui32").to_be(),
266            TagTypeDefinition::U64Array => u32::from_ne_bytes(*b"ui64").to_be(),
267            TagTypeDefinition::Measurement => u32::from_ne_bytes(*b"meas").to_be(),
268            TagTypeDefinition::NotAllowed => 0,
269        }
270    }
271}