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);