Skip to main content

fuji/recipe/
mod.rs

1use serde::{Deserialize, Serialize, Serializer};
2use strum_macros::{Display, EnumString};
3
4pub mod builder;
5pub mod from_exif;
6pub mod read;
7pub mod str;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct FujifilmRecipe {
11    pub details: FujifilmRecipeDetails,
12}
13
14impl FujifilmRecipe {
15    pub fn new(details: FujifilmRecipeDetails) -> Self {
16        FujifilmRecipe { details }
17    }
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
21pub struct FujifilmRecipeDetails {
22    pub film_simulation: FilmSimulation,
23    pub sensor: TransSensor,
24    pub settings: Settings,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize, Display, PartialEq)]
28#[serde(untagged)]
29pub enum Settings {
30    TransI(TransISettings),
31    TransII(TransIISettings),
32    TransIII(TransIIISettings),
33    TransIV(TransIVSettings),
34    TransV(TransVSettings),
35}
36
37#[derive(Debug, Deserialize, PartialEq, Display, EnumString, Clone)]
38pub enum TransSensor {
39    #[strum(serialize = "Trans Sensor I", to_string = "TransI")]
40    TransI,
41    #[strum(serialize = "Trans Sensor II", to_string = "TransII")]
42    TransII,
43    #[strum(serialize = "Trans Sensor III", to_string = "TransIII")]
44    TransIII,
45    #[strum(serialize = "Trans Sensor IV", to_string = "TransIV")]
46    TransIV,
47    #[strum(serialize = "Trans Sensor V", to_string = "TransV")]
48    TransV,
49}
50
51impl Serialize for TransSensor {
52    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
53    where
54        S: Serializer,
55    {
56        serializer.serialize_str(&self.to_string())
57    }
58}
59
60#[derive(Debug, Clone, Deserialize, PartialEq, Display)]
61pub enum FilmSimulation {
62    #[strum(serialize = "Provia", to_string = "Provia")]
63    ProviaStandard,
64    #[strum(serialize = "Velvia", to_string = "Velvia")]
65    VelviaVivid,
66    #[strum(serialize = "Astia", to_string = "Astia")]
67    AstiaSoft,
68    #[strum(serialize = "Classic Chrome", to_string = "Classic Chrome")]
69    ClassicChrome,
70    #[strum(serialize = "Reala Ace", to_string = "Reala Ace")]
71    RealaAce,
72    #[strum(serialize = "Pro Neg. Hi", to_string = "Pro Neg. Hi")]
73    ProNegHi,
74    #[strum(serialize = "Pro Neg. Std", to_string = "Pro Neg. Std")]
75    ProNegStd,
76    #[strum(serialize = "Classic Negative", to_string = "Classic Negative")]
77    ClassicNeg,
78    #[strum(serialize = "Nostalgic Negative", to_string = "Nostalgic Negative")]
79    NostalgicNeg,
80    #[strum(serialize = "Eterna", to_string = "Eterna")]
81    EternaCinema,
82    #[strum(serialize = "Eterna Bleach Bypass", to_string = "Eterna Bleach Bypass")]
83    BleachBypass,
84    #[strum(serialize = "Acros{filter}", to_string = "Acros{filter}")]
85    Acros { filter: MonochromaticFilter },
86    #[strum(serialize = "Monochrome{filter}")]
87    Monochrome { filter: MonochromaticFilter },
88    #[strum(serialize = "Sepia", to_string = "Sepia")]
89    Sepia,
90}
91
92impl Serialize for FilmSimulation {
93    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94    where
95        S: Serializer,
96    {
97        serializer.serialize_str(&self.to_string())
98    }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Display, EnumString, Default)]
102pub enum MonochromaticFilter {
103    #[strum(serialize = "Standard", to_string = "")]
104    #[default]
105    Std,
106    #[strum(serialize = "Yellow", to_string = " +Ye")]
107    Yellow,
108    #[strum(serialize = "Red", to_string = " +R")]
109    Red,
110    #[strum(serialize = "Green", to_string = " +G")]
111    Green,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Display, EnumString, Default)]
115pub enum GrainStrength {
116    #[default]
117    #[strum(to_string = "Weak")]
118    Weak,
119    #[strum(to_string = "Strong")]
120    Strong,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Display, EnumString, Default)]
124pub enum GrainSize {
125    #[default]
126    #[strum(to_string = "Small")]
127    Small,
128    #[strum(to_string = "Large")]
129    Large,
130}
131
132#[derive(Debug, Clone, Deserialize, Display, PartialEq, Default)]
133pub enum GrainEffect {
134    #[default]
135    #[strum(to_string = "Off")]
136    Off,
137    #[strum(to_string = "{strength}")]
138    OnlyStrength { strength: GrainStrength },
139    #[strum(to_string = "{strength}, {size}")]
140    StrengthAndSize {
141        strength: GrainStrength,
142        size: GrainSize,
143    },
144}
145
146impl Serialize for GrainEffect {
147    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
148    where
149        S: Serializer,
150    {
151        serializer.serialize_str(&self.to_string())
152    }
153}
154
155#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Display, EnumString, Default)]
156pub enum SettingStrength {
157    #[default]
158    #[strum(serialize = "Off")]
159    Off,
160    #[strum(serialize = "Weak")]
161    Weak,
162    #[strum(serialize = "Strong")]
163    Strong,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
167#[serde(tag = "type")]
168pub enum WhiteBalance {
169    Auto { shift: WBShift },
170    AutoWhitePriority { shift: WBShift },
171    AutoAmbiencePriority { shift: WBShift },
172    Custom1 { shift: WBShift },
173    Custom2 { shift: WBShift },
174    Custom3 { shift: WBShift },
175    Kelvin { temperature: i32, shift: WBShift },
176    Daylight { shift: WBShift },
177    Cloudy { shift: WBShift },
178    FluorescentLight1 { shift: WBShift },
179    FluorescentLight2 { shift: WBShift },
180    FluorescentLight3 { shift: WBShift },
181    Incandescent { shift: WBShift },
182    Underwater { shift: WBShift },
183}
184
185impl WhiteBalance {
186    pub fn get_shift(&self) -> &WBShift {
187        match self {
188            WhiteBalance::Auto { shift }
189            | WhiteBalance::AutoWhitePriority { shift }
190            | WhiteBalance::AutoAmbiencePriority { shift }
191            | WhiteBalance::Custom1 { shift }
192            | WhiteBalance::Custom2 { shift }
193            | WhiteBalance::Custom3 { shift }
194            | WhiteBalance::Daylight { shift }
195            | WhiteBalance::Cloudy { shift }
196            | WhiteBalance::FluorescentLight1 { shift }
197            | WhiteBalance::FluorescentLight2 { shift }
198            | WhiteBalance::FluorescentLight3 { shift }
199            | WhiteBalance::Incandescent { shift }
200            | WhiteBalance::Underwater { shift } => shift,
201            WhiteBalance::Kelvin { shift, .. } => shift,
202        }
203    }
204
205    pub fn set_shift(&mut self, s: WBShift) {
206        match self {
207            WhiteBalance::Auto { shift }
208            | WhiteBalance::AutoWhitePriority { shift }
209            | WhiteBalance::AutoAmbiencePriority { shift }
210            | WhiteBalance::Custom1 { shift }
211            | WhiteBalance::Custom2 { shift }
212            | WhiteBalance::Custom3 { shift }
213            | WhiteBalance::Daylight { shift }
214            | WhiteBalance::Cloudy { shift }
215            | WhiteBalance::FluorescentLight1 { shift }
216            | WhiteBalance::FluorescentLight2 { shift }
217            | WhiteBalance::FluorescentLight3 { shift }
218            | WhiteBalance::Incandescent { shift }
219            | WhiteBalance::Underwater { shift } => *shift = s,
220            WhiteBalance::Kelvin { shift, .. } => {
221                *shift = WBShift {
222                    blue: s.blue,
223                    red: s.red,
224                }
225            }
226        }
227    }
228}
229
230impl Default for WhiteBalance {
231    fn default() -> Self {
232        WhiteBalance::Auto {
233            shift: WBShift::default(),
234        }
235    }
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
239pub struct WBShift {
240    pub red: i32,
241    pub blue: i32,
242}
243
244#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Display, EnumString, Default)]
245pub enum DynamicRange {
246    #[default]
247    #[strum(serialize = "Auto")]
248    Auto,
249    #[strum(serialize = "DR100")]
250    DR100,
251    #[strum(serialize = "DR200")]
252    DR200,
253    #[strum(serialize = "DR400")]
254    DR400,
255}
256
257#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Display, EnumString, Default)]
258pub enum DRangePriority {
259    #[default]
260    #[strum(serialize = "Off")]
261    Off,
262    #[strum(serialize = "Auto")]
263    Auto,
264    #[strum(serialize = "Weak")]
265    Weak,
266    #[strum(serialize = "Strong")]
267    Strong,
268}
269
270#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
271#[serde(tag = "type")]
272pub enum MonochromaticColor {
273    ColorShift { shift: MonochromaticColorShift },
274    Strength { value: i64 },
275}
276
277impl Default for MonochromaticColor {
278    fn default() -> Self {
279        MonochromaticColor::ColorShift {
280            shift: MonochromaticColorShift { mg: 0, wc: 0 },
281        }
282    }
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
286pub struct MonochromaticColorShift {
287    pub wc: i64,
288    pub mg: i64,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
292pub struct ColorChromeEffect {
293    pub strength: SettingStrength,
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
297pub struct ColorChromeEffectFxBlue {
298    pub strength: SettingStrength,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
302pub struct ToneCurve {
303    pub highlights: f64,
304    pub shadows: f64,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
308pub struct Color {
309    pub value: i64,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
313pub struct Sharpness {
314    pub value: i64,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
318pub struct HighISONoiseReduction {
319    pub value: i64,
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
323pub struct Clarity {
324    pub value: i64,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
328pub struct TransVSettings {
329    pub white_balance: WhiteBalance,
330    pub dynamic_range: DynamicRange,
331    pub d_range_priority: DRangePriority,
332    pub grain_effect: GrainEffect,
333    pub color_chrome_effect: ColorChromeEffect,
334    pub color_chrome_fx_blue: ColorChromeEffectFxBlue,
335    pub tone_curve: ToneCurve,
336    pub color: Color,
337    pub monochromatic_color: MonochromaticColor,
338    pub sharpness: Sharpness,
339    pub high_iso_noise_reduction: HighISONoiseReduction,
340    pub clarity: Clarity,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
344pub struct TransIVSettings {
345    pub white_balance: WhiteBalance,
346    pub dynamic_range: DynamicRange,
347    pub d_range_priority: DRangePriority,
348    pub grain_effect: GrainEffect,
349    pub color_chrome_fx_blue: ColorChromeEffectFxBlue,
350    pub color_chrome_effect: ColorChromeEffect,
351    pub tone_curve: ToneCurve,
352    pub color: Color,
353    pub monochromatic_color: MonochromaticColor,
354    pub sharpness: Sharpness,
355    pub high_iso_noise_reduction: HighISONoiseReduction,
356    pub clarity: Clarity,
357}
358
359#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
360pub struct TransIIISettings {
361    pub white_balance: WhiteBalance,
362    pub dynamic_range: DynamicRange,
363    pub grain_effect: GrainEffect,
364    pub tone_curve: ToneCurve,
365    pub color: Color,
366    pub monochromatic_color: MonochromaticColor,
367    pub sharpness: Sharpness,
368    pub high_iso_noise_reduction: HighISONoiseReduction,
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
372pub struct TransIISettings {
373    pub white_balance: WhiteBalance,
374    pub dynamic_range: DynamicRange,
375    pub tone_curve: ToneCurve,
376    pub color: Color,
377    pub sharpness: Sharpness,
378    pub high_iso_noise_reduction: HighISONoiseReduction,
379}
380
381#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
382pub struct TransISettings {
383    pub white_balance: WhiteBalance,
384    pub dynamic_range: DynamicRange,
385    pub tone_curve: ToneCurve,
386    pub color: Color,
387    pub sharpness: Sharpness,
388    pub high_iso_noise_reduction: HighISONoiseReduction,
389}
390
391impl Settings {
392    pub fn get_values(&self) -> SettingsTuple {
393        match self.clone() {
394            Settings::TransI(settings) => (
395                settings.white_balance,
396                settings.dynamic_range,
397                None,
398                settings.tone_curve,
399                settings.color,
400                settings.sharpness,
401                None,
402                settings.high_iso_noise_reduction,
403                None,
404                None,
405                None,
406                None,
407            ),
408            Settings::TransII(settings) => (
409                settings.white_balance,
410                settings.dynamic_range,
411                None,
412                settings.tone_curve,
413                settings.color,
414                settings.sharpness,
415                None,
416                settings.high_iso_noise_reduction,
417                None,
418                None,
419                None,
420                None,
421            ),
422            Settings::TransIII(settings) => (
423                settings.white_balance,
424                settings.dynamic_range,
425                None,
426                settings.tone_curve,
427                settings.color,
428                settings.sharpness,
429                None,
430                settings.high_iso_noise_reduction,
431                Some(settings.grain_effect),
432                None,
433                None,
434                Some(settings.monochromatic_color),
435            ),
436            Settings::TransIV(settings) => (
437                settings.white_balance,
438                settings.dynamic_range,
439                Some(settings.d_range_priority),
440                settings.tone_curve,
441                settings.color,
442                settings.sharpness,
443                Some(settings.clarity),
444                settings.high_iso_noise_reduction,
445                Some(settings.grain_effect),
446                Some(settings.color_chrome_effect),
447                Some(settings.color_chrome_fx_blue),
448                Some(settings.monochromatic_color),
449            ),
450            Settings::TransV(settings) => (
451                settings.white_balance,
452                settings.dynamic_range,
453                Some(settings.d_range_priority),
454                settings.tone_curve,
455                settings.color,
456                settings.sharpness,
457                Some(settings.clarity),
458                settings.high_iso_noise_reduction,
459                Some(settings.grain_effect),
460                Some(settings.color_chrome_effect),
461                Some(settings.color_chrome_fx_blue),
462                Some(settings.monochromatic_color),
463            ),
464        }
465    }
466}
467
468pub type SettingsTuple = (
469    WhiteBalance,
470    DynamicRange,
471    Option<DRangePriority>,
472    ToneCurve,
473    Color,
474    Sharpness,
475    Option<Clarity>,
476    HighISONoiseReduction,
477    Option<GrainEffect>,
478    Option<ColorChromeEffect>,
479    Option<ColorChromeEffectFxBlue>,
480    Option<MonochromaticColor>,
481);