1 use super::ifdformat::*;
2 use super::lowlevel::read_u16_array;
3 use super::types::*;
4 use std::borrow::Cow;
5
6 /// No-op for readable value tag function. Should not be used by any EXIF tag descriptor,
7 /// except for the catch-all match that handles unknown tags
nop(e: &TagValue) -> Option<Cow<'static, str>>8 pub(crate) fn nop(e: &TagValue) -> Option<Cow<'static, str>> {
9 Some(Cow::Owned(e.to_string()))
10 }
11
12 /// No-op for readable value tag function. Used for ASCII string tags, or when the
13 /// default readable representation of value is pretty enough.
strpass(e: &TagValue) -> Option<Cow<'static, str>>14 pub(crate) fn strpass(e: &TagValue) -> Option<Cow<'static, str>> {
15 Some(Cow::Owned(e.to_string()))
16 }
17
18 /// Indicates which one of the parameters of ISO12232 is used for PhotographicSensitivity
sensitivity_type(e: &TagValue) -> Option<Cow<'static, str>>19 pub(crate) fn sensitivity_type(e: &TagValue) -> Option<Cow<'static, str>> {
20 match *e {
21 TagValue::U16(ref v) => Some(match v.get(0)? {
22 0 => "Unknown",
23 1 => "Standard output sensitivity (SOS)",
24 2 => "Recommended exposure index (REI)",
25 3 => "ISO speed",
26 4 => "Standard output sensitivity (SOS) and recommended exposure index (REI)",
27 5 => "Standard output sensitivity (SOS) and ISO speed",
28 6 => "Recommended exposure index (REI) and ISO speed",
29 7 => "Standard output sensitivity (SOS) and recommended exposure index (REI) and ISO speed",
30 n => return Some(format!("Unknown ({})", n).into()),
31 }.into()),
32 _ => None,
33 }
34 }
35
orientation(e: &TagValue) -> Option<Cow<'static, str>>36 pub(crate) fn orientation(e: &TagValue) -> Option<Cow<'static, str>> {
37 match *e {
38 TagValue::U16(ref v) => {
39 Some(match v.get(0)? {
40 1 => "Straight",
41 3 => "Upside down",
42 6 => "Rotated to left",
43 8 => "Rotated to right",
44 9 => "Undefined",
45 n => return Some(format!("Unknown ({})", n).into()),
46 }.into())
47 },
48 _ => None,
49 }
50 }
51
rational_value(e: &TagValue) -> Option<Cow<'static, str>>52 pub(crate) fn rational_value(e: &TagValue) -> Option<Cow<'static, str>> {
53 Some(match e {
54 TagValue::URational(v) => v.get(0)?.value(),
55 TagValue::IRational(v) => v.get(0)?.value(),
56 _ => return None,
57 }.to_string().into())
58 }
59
rational_values(e: &TagValue) -> Option<Cow<'static, str>>60 pub(crate) fn rational_values(e: &TagValue) -> Option<Cow<'static, str>> {
61 match *e {
62 TagValue::URational(ref v) => {
63 Some(NumArray::new(v.iter().map(|&x| x.value())).to_string().into())
64 },
65 _ => None,
66 }
67 }
68
resolution_unit(e: &TagValue) -> Option<Cow<'static, str>>69 pub(crate) fn resolution_unit(e: &TagValue) -> Option<Cow<'static, str>> {
70 match *e {
71 TagValue::U16(ref v) => {
72 Some(match v.get(0)? {
73 1 => "Unitless",
74 2 => "in",
75 3 => "cm",
76 n => return Some(format!("Unknown ({})", n).into()),
77 }.into())
78 },
79 _ => None,
80 }
81 }
82
exposure_time(e: &TagValue) -> Option<Cow<'static, str>>83 pub(crate) fn exposure_time(e: &TagValue) -> Option<Cow<'static, str>> {
84 match *e {
85 TagValue::URational(ref v) => {
86 let r = v.get(0)?;
87 Some(if r.numerator == 1 && r.denominator > 1 {
88 // traditional 1/x exposure time
89 format!("{} s", r)
90 } else if r.value() < 0.1 {
91 format!("1/{:.0} s", 1.0 / r.value())
92 } else if r.value() < 1.0 {
93 format!("1/{:.1} s", 1.0 / r.value())
94 } else {
95 format!("{:.1} s", r.value())
96 }.into())
97 },
98 _ => None,
99 }
100 }
101
f_number(e: &TagValue) -> Option<Cow<'static, str>>102 pub(crate) fn f_number(e: &TagValue) -> Option<Cow<'static, str>> {
103 match *e {
104 TagValue::URational(ref v) => Some(format!("f/{:.1}", v.get(0)?.value()).into()),
105 _ => None,
106 }
107 }
108
exposure_program(e: &TagValue) -> Option<Cow<'static, str>>109 pub(crate) fn exposure_program(e: &TagValue) -> Option<Cow<'static, str>> {
110 match *e {
111 TagValue::U16(ref v) => {
112 Some(match v.get(0)? {
113 1 => "Manual control",
114 2 => "Program control",
115 3 => "Aperture priority",
116 4 => "Shutter priority",
117 5 => "Program creative (slow program)",
118 6 => "Program creative (high-speed program)",
119 7 => "Portrait mode",
120 8 => "Landscape mode",
121 n => return Some(format!("Unknown ({})", n).into()),
122 }.into())
123 },
124 _ => None,
125 }
126 }
127
focal_length(e: &TagValue) -> Option<Cow<'static, str>>128 pub(crate) fn focal_length(e: &TagValue) -> Option<Cow<'static, str>> {
129 match *e {
130 TagValue::URational(ref v) => Some(format!("{} mm", v.get(0)?.value()).into()),
131 _ => None,
132 }
133 }
134
focal_length_35(e: &TagValue) -> Option<Cow<'static, str>>135 pub(crate) fn focal_length_35(e: &TagValue) -> Option<Cow<'static, str>> {
136 match *e {
137 TagValue::U16(ref v) => Some(format!("{} mm", v.get(0)?).into()),
138 _ => None,
139 }
140 }
141
meters(e: &TagValue) -> Option<Cow<'static, str>>142 pub(crate) fn meters(e: &TagValue) -> Option<Cow<'static, str>> {
143 match *e {
144 TagValue::URational(ref v) => Some(format!("{:.1} m", v.get(0)?.value()).into()),
145 _ => None,
146 }
147 }
148
iso_speeds(e: &TagValue) -> Option<Cow<'static, str>>149 pub(crate) fn iso_speeds(e: &TagValue) -> Option<Cow<'static, str>> {
150 match *e {
151 TagValue::U16(ref v) => {
152 Some(if v.len() == 1 {
153 format!("ISO {}", v[0])
154 } else if v.len() == 2 || v.len() == 3 {
155 format!("ISO {} latitude {}", v[0], v[1])
156 } else {
157 format!("Unknown ({})", NumArray::new(v))
158 }.into())
159 },
160 _ => None,
161 }
162 }
163
dms(e: &TagValue) -> Option<Cow<'static, str>>164 pub(crate) fn dms(e: &TagValue) -> Option<Cow<'static, str>> {
165 match *e {
166 TagValue::URational(ref v) if v.len() >= 3 => {
167 let deg = v[0];
168 let min = v[1];
169 let sec = v[2];
170 Some(if deg.denominator == 1 && min.denominator == 1 {
171 format!("{}°{}'{:.2}\"", deg.value(), min.value(), sec.value())
172 } else if deg.denominator == 1 {
173 format!("{}°{:.4}'", deg.value(), min.value() + sec.value() / 60.0)
174 } else {
175 // untypical format
176 format!(
177 "{:.7}°",
178 deg.value() + min.value() / 60.0 + sec.value() / 3600.0
179 )
180 }.into())
181 },
182 _ => None,
183 }
184 }
185
gps_alt_ref(e: &TagValue) -> Option<Cow<'static, str>>186 pub(crate) fn gps_alt_ref(e: &TagValue) -> Option<Cow<'static, str>> {
187 match *e {
188 TagValue::U8(ref v) => {
189 Some(match v.get(0)? {
190 0 => "Above sea level",
191 1 => "Below sea level",
192 n => return Some(format!("Unknown, assumed below sea level ({})", n).into()),
193 }.into())
194 },
195 _ => None,
196 }
197 }
198
gpsdestdistanceref(e: &TagValue) -> Option<Cow<'static, str>>199 pub(crate) fn gpsdestdistanceref(e: &TagValue) -> Option<Cow<'static, str>> {
200 match *e {
201 TagValue::Ascii(ref v) => {
202 Some(if v == "N" {
203 "kn".into()
204 } else if v == "K" {
205 "km".into()
206 } else if v == "M" {
207 "mi".into()
208 } else {
209 format!("Unknown ({})", v).into()
210 })
211 },
212 _ => None,
213 }
214 }
215
gpsdestdistance(e: &TagValue) -> Option<Cow<'static, str>>216 pub(crate) fn gpsdestdistance(e: &TagValue) -> Option<Cow<'static, str>> {
217 match *e {
218 TagValue::URational(ref v) => Some(format!("{:.3}", v.get(0)?.value()).into()),
219 _ => None,
220 }
221 }
222
gpsspeedref(e: &TagValue) -> Option<Cow<'static, str>>223 pub(crate) fn gpsspeedref(e: &TagValue) -> Option<Cow<'static, str>> {
224 match *e {
225 TagValue::Ascii(ref v) => {
226 Some(if v == "N" {
227 "kn".into()
228 } else if v == "K" {
229 "km/h".into()
230 } else if v == "M" {
231 "mi/h".into()
232 } else {
233 format!("Unknown ({})", v).into()
234 })
235 },
236 _ => None,
237 }
238 }
239
gpsspeed(e: &TagValue) -> Option<Cow<'static, str>>240 pub(crate) fn gpsspeed(e: &TagValue) -> Option<Cow<'static, str>> {
241 match *e {
242 TagValue::URational(ref v) => Some(format!("{:.1}", v.get(0)?.value()).into()),
243 _ => None,
244 }
245 }
246
gpsbearingref(e: &TagValue) -> Option<Cow<'static, str>>247 pub(crate) fn gpsbearingref(e: &TagValue) -> Option<Cow<'static, str>> {
248 match *e {
249 TagValue::Ascii(ref v) => {
250 Some(if v == "T" {
251 "True bearing".into()
252 } else if v == "M" {
253 "Magnetic bearing".into()
254 } else {
255 format!("Unknown ({})", v).into()
256 })
257 },
258 _ => None,
259 }
260 }
261
gpsbearing(e: &TagValue) -> Option<Cow<'static, str>>262 pub(crate) fn gpsbearing(e: &TagValue) -> Option<Cow<'static, str>> {
263 match *e {
264 TagValue::URational(ref v) => Some(format!("{:.2}°", v.get(0)?.value()).into()),
265 _ => None,
266 }
267 }
268
gpstimestamp(e: &TagValue) -> Option<Cow<'static, str>>269 pub(crate) fn gpstimestamp(e: &TagValue) -> Option<Cow<'static, str>> {
270 match *e {
271 TagValue::URational(ref v) => {
272 let sec = v.get(2)?;
273 let hour = v.get(0)?;
274 let min = v.get(1)?;
275 Some(format!(
276 "{:02.0}:{:02.0}:{:04.1} UTC",
277 hour.value(),
278 min.value(),
279 sec.value()
280 ).into())
281 },
282 _ => None,
283 }
284 }
285
gpsdiff(e: &TagValue) -> Option<Cow<'static, str>>286 pub(crate) fn gpsdiff(e: &TagValue) -> Option<Cow<'static, str>> {
287 match *e {
288 TagValue::U16(ref v) => {
289 Some(match v.get(0)? {
290 0 => "Measurement without differential correction".into(),
291 1 => "Differential correction applied".into(),
292 n => format!("Unknown ({})", n).into(),
293 })
294 },
295 _ => None,
296 }
297 }
298
gpsstatus(e: &TagValue) -> Option<Cow<'static, str>>299 pub(crate) fn gpsstatus(e: &TagValue) -> Option<Cow<'static, str>> {
300 match *e {
301 TagValue::Ascii(ref v) => {
302 Some(if v == "A" {
303 "Measurement in progress".into()
304 } else if v == "V" {
305 "Measurement is interoperability".into()
306 } else {
307 format!("Unknown ({})", v).into()
308 })
309 },
310 _ => None,
311 }
312 }
313
gpsmeasuremode(e: &TagValue) -> Option<Cow<'static, str>>314 pub(crate) fn gpsmeasuremode(e: &TagValue) -> Option<Cow<'static, str>> {
315 match *e {
316 TagValue::Ascii(ref v) => {
317 Some(if v == "2" {
318 "2-dimension".into()
319 } else if v == "3" {
320 "3-dimension".into()
321 } else {
322 format!("Unknown ({})", v).into()
323 })
324 },
325 _ => None,
326 }
327 }
328
329 /// Interprets an Undefined tag as ASCII, when the contents are guaranteed
330 /// by EXIF standard to be ASCII-compatible. This function accepts UTF-8
331 /// strings, should they be accepted by EXIF standard in the future.
undefined_as_ascii(e: &TagValue) -> Option<Cow<'static, str>>332 pub(crate) fn undefined_as_ascii(e: &TagValue) -> Option<Cow<'static, str>> {
333 match *e {
334 TagValue::Undefined(ref v, _) => Some(String::from_utf8_lossy(&v[..]).into_owned().into()),
335 _ => None,
336 }
337 }
338
339 /// Outputs an Undefined tag as an array of bytes. Appropriate for tags
340 /// that are opaque and small-sized
undefined_as_u8(e: &TagValue) -> Option<Cow<'static, str>>341 pub(crate) fn undefined_as_u8(e: &TagValue) -> Option<Cow<'static, str>> {
342 match *e {
343 TagValue::Undefined(ref v, _) => Some(NumArray::new(v).to_string().into()),
344 _ => None,
345 }
346 }
347
348 /// Tries to parse an Undefined tag as containing a string. For some tags,
349 /// the string encoding /// format can be discovered by looking into the first
350 /// 8 bytes.
undefined_as_encoded_string(e: &TagValue) -> Option<Cow<'static, str>>351 pub(crate) fn undefined_as_encoded_string(e: &TagValue) -> Option<Cow<'static, str>> {
352 // "ASCII\0\0\0"
353 static ASC: [u8; 8] = [0x41, 0x53, 0x43, 0x49, 0x49, 0, 0, 0];
354 // "JIS\0\0\0\0\0"
355 static JIS: [u8; 8] = [0x4a, 0x49, 0x53, 0, 0, 0, 0, 0];
356 // "UNICODE\0"
357 static UNICODE: [u8; 8] = [0x55, 0x4e, 0x49, 0x43, 0x4f, 0x44, 0x45, 0x00];
358
359 match *e {
360 TagValue::Undefined(ref v, le) => {
361 Some(if v.len() < 8 {
362 format!("String w/ truncated preamble {}", NumArray::new(v))
363 } else if v[0..8] == ASC[..] {
364 String::from_utf8_lossy(&v[8..]).into_owned()
365 } else if v[0..8] == JIS[..] {
366 format!("JIS string {}", NumArray::new(&v[8..]))
367 } else if v[0..8] == UNICODE[..] {
368 let v8 = &v[8..];
369 // reinterpret as vector of u16
370 let v16_size = (v8.len() / 2) as u32;
371 let v16 = read_u16_array(le, v16_size, v8)?;
372 String::from_utf16_lossy(&v16)
373 } else {
374 format!("String w/ undefined encoding {}", NumArray::new(v))
375 }.into())
376 },
377 _ => None,
378 }
379 }
380
381 /// Prints an opaque and long Undefined tag simply as as "blob", noting its length
undefined_as_blob(e: &TagValue) -> Option<Cow<'static, str>>382 pub(crate) fn undefined_as_blob(e: &TagValue) -> Option<Cow<'static, str>> {
383 match *e {
384 TagValue::Undefined(ref v, _) => Some(format!("Blob of {} bytes", v.len()).into()),
385 _ => None,
386 }
387 }
388
apex_tv(e: &TagValue) -> Option<Cow<'static, str>>389 pub(crate) fn apex_tv(e: &TagValue) -> Option<Cow<'static, str>> {
390 match *e {
391 TagValue::IRational(ref v) => Some(format!("{:.1} Tv APEX", v.get(0)?.value()).into()),
392 _ => None,
393 }
394 }
395
apex_av(e: &TagValue) -> Option<Cow<'static, str>>396 pub(crate) fn apex_av(e: &TagValue) -> Option<Cow<'static, str>> {
397 match *e {
398 TagValue::URational(ref v) => Some(format!("{:.1} Av APEX", v.get(0)?.value()).into()),
399 _ => None,
400 }
401 }
402
apex_brightness(e: &TagValue) -> Option<Cow<'static, str>>403 pub(crate) fn apex_brightness(e: &TagValue) -> Option<Cow<'static, str>> {
404 match *e {
405 TagValue::IRational(ref v) => {
406 // numerator 0xffffffff = unknown
407 Some(if v.get(0)?.numerator == -1 {
408 "Unknown".into()
409 } else {
410 format!("{:.1} APEX", v.get(0)?.value()).into()
411 })
412 },
413 _ => None,
414 }
415 }
416
apex_ev(e: &TagValue) -> Option<Cow<'static, str>>417 pub(crate) fn apex_ev(e: &TagValue) -> Option<Cow<'static, str>> {
418 match *e {
419 TagValue::IRational(ref v) => Some(format!("{:.2} EV APEX", v.get(0)?.value()).into()),
420 _ => None,
421 }
422 }
423
file_source(e: &TagValue) -> Option<Cow<'static, str>>424 pub(crate) fn file_source(e: &TagValue) -> Option<Cow<'static, str>> {
425 match *e {
426 TagValue::Undefined(ref v, _) => {
427 Some(if !v.is_empty() && v[0] == 3 {
428 "DSC"
429 } else {
430 "Unknown"
431 }.into())
432 },
433 _ => None,
434 }
435 }
436
flash_energy(e: &TagValue) -> Option<Cow<'static, str>>437 pub(crate) fn flash_energy(e: &TagValue) -> Option<Cow<'static, str>> {
438 match *e {
439 TagValue::URational(ref v) => Some(format!("{} BCPS", v.get(0)?.value()).into()),
440 _ => None,
441 }
442 }
443
metering_mode(e: &TagValue) -> Option<Cow<'static, str>>444 pub(crate) fn metering_mode(e: &TagValue) -> Option<Cow<'static, str>> {
445 match *e {
446 TagValue::U16(ref v) => {
447 Some(match v.get(0)? {
448 0 => "Unknown",
449 1 => "Average",
450 2 => "Center-weighted average",
451 3 => "Spot",
452 4 => "Multi-spot",
453 5 => "Pattern",
454 6 => "Partial",
455 255 => "Other",
456 n => return Some(format!("Unknown ({})", n).into()),
457 }.into())
458 },
459 _ => None,
460 }
461 }
462
light_source(e: &TagValue) -> Option<Cow<'static, str>>463 pub(crate) fn light_source(e: &TagValue) -> Option<Cow<'static, str>> {
464 match *e {
465 TagValue::U16(ref v) => {
466 Some(match v.get(0)? {
467 0 => "Unknown",
468 1 => "Daylight",
469 2 => "Fluorescent",
470 3 => "Tungsten",
471 4 => "Flash",
472 9 => "Fine weather",
473 10 => "Cloudy weather",
474 11 => "Shade",
475 12 => "Daylight fluorescent (D)",
476 13 => "Day white fluorescent (N)",
477 14 => "Cool white fluorescent (W)",
478 15 => "White fluorescent (WW)",
479 17 => "Standard light A",
480 18 => "Standard light B",
481 19 => "Standard light C",
482 20 => "D55",
483 21 => "D65",
484 22 => "D75",
485 23 => "D50",
486 24 => "ISO studio tungsten",
487 255 => "Other",
488 n => return Some(format!("Unknown ({})", n).into()),
489 }.into())
490 },
491 _ => None,
492 }
493 }
494
color_space(e: &TagValue) -> Option<Cow<'static, str>>495 pub(crate) fn color_space(e: &TagValue) -> Option<Cow<'static, str>> {
496 match *e {
497 TagValue::U16(ref v) => {
498 Some(match v.get(0)? {
499 1 => "sRGB",
500 65535 => "Uncalibrated",
501 n => return Some(format!("Unknown ({})", n).into()),
502 }.into())
503 },
504 _ => None,
505 }
506 }
507
flash(e: &TagValue) -> Option<Cow<'static, str>>508 pub(crate) fn flash(e: &TagValue) -> Option<Cow<'static, str>> {
509 match *e {
510 TagValue::U16(ref v) => {
511 let n = v.get(0)?;
512 let mut b0 = "Did not fire. ";
513 let mut b12 = "";
514 let mut b34 = "";
515 let mut b6 = "";
516
517 if (n & (1 << 5)) > 0 {
518 return Some("Does not have a flash.".into());
519 }
520
521 if (n & 1) > 0 {
522 b0 = "Fired. ";
523 if (n & (1 << 6)) > 0 {
524 b6 = "Redeye reduction. "
525 } else {
526 b6 = "No redeye reduction. "
527 }
528
529 // bits 1 and 2
530 let m = (n >> 1) & 3;
531 if m == 2 {
532 b12 = "Strobe ret not detected. ";
533 } else if m == 3 {
534 b12 = "Strobe ret detected. ";
535 }
536 }
537
538 // bits 3 and 4
539 let m = (n >> 3) & 3;
540 if m == 1 {
541 b34 = "Forced fire. ";
542 } else if m == 2 {
543 b34 = "Forced suppresion. ";
544 } else if m == 3 {
545 b12 = "Auto mode. ";
546 }
547
548 Some(format!("{}{}{}{}", b0, b12, b34, b6).into())
549 },
550 _ => None,
551 }
552 }
553
subject_area(e: &TagValue) -> Option<Cow<'static, str>>554 pub(crate) fn subject_area(e: &TagValue) -> Option<Cow<'static, str>> {
555 match *e {
556 TagValue::U16(ref v) => Some(match v.len() {
557 2 => format!("at pixel {},{}", v[0], v[1]),
558 3 => format!("at center {},{} radius {}", v[0], v[1], v[2]),
559 4 => format!(
560 "at rectangle {},{} width {} height {}",
561 v[0], v[1], v[2], v[3]
562 ),
563 _ => format!("Unknown ({}) ", NumArray::new(v)),
564 }.into()),
565 _ => None,
566 }
567 }
568
subject_location(e: &TagValue) -> Option<Cow<'static, str>>569 pub(crate) fn subject_location(e: &TagValue) -> Option<Cow<'static, str>> {
570 match *e {
571 TagValue::U16(ref v) if v.len() >= 2 => Some(format!("at pixel {},{}", v[0], v[1]).into()),
572 _ => None,
573 }
574 }
575
sharpness(e: &TagValue) -> Option<Cow<'static, str>>576 pub(crate) fn sharpness(e: &TagValue) -> Option<Cow<'static, str>> {
577 match *e {
578 TagValue::U16(ref v) => {
579 Some(match v.get(0)? {
580 0 => "Normal",
581 1 => "Soft",
582 2 => "Hard",
583 n => return Some(format!("Unknown ({})", n).into()),
584 }.into())
585 },
586 _ => None,
587 }
588 }
589
saturation(e: &TagValue) -> Option<Cow<'static, str>>590 pub(crate) fn saturation(e: &TagValue) -> Option<Cow<'static, str>> {
591 match *e {
592 TagValue::U16(ref v) => {
593 Some(match v.get(0)? {
594 0 => "Normal",
595 1 => "Low",
596 2 => "High",
597 n => return Some(format!("Unknown ({})", n).into()),
598 }.into())
599 },
600 _ => None,
601 }
602 }
603
contrast(e: &TagValue) -> Option<Cow<'static, str>>604 pub(crate) fn contrast(e: &TagValue) -> Option<Cow<'static, str>> {
605 match *e {
606 TagValue::U16(ref v) => {
607 Some(match v.get(0)? {
608 0 => "Normal",
609 1 => "Soft",
610 2 => "Hard",
611 n => return Some(format!("Unknown ({})", n).into()),
612 }.into())
613 },
614 _ => None,
615 }
616 }
617
gain_control(e: &TagValue) -> Option<Cow<'static, str>>618 pub(crate) fn gain_control(e: &TagValue) -> Option<Cow<'static, str>> {
619 match *e {
620 TagValue::U16(ref v) => {
621 Some(match v.get(0)? {
622 0 => "None",
623 1 => "Low gain up",
624 2 => "High gain up",
625 3 => "Low gain down",
626 4 => "High gain down",
627 n => return Some(format!("Unknown ({})", n).into()),
628 }.into())
629 },
630 _ => None,
631 }
632 }
633
exposure_mode(e: &TagValue) -> Option<Cow<'static, str>>634 pub(crate) fn exposure_mode(e: &TagValue) -> Option<Cow<'static, str>> {
635 match *e {
636 TagValue::U16(ref v) => {
637 Some(match v.get(0)? {
638 0 => "Auto exposure",
639 1 => "Manual exposure",
640 2 => "Auto bracket",
641 n => return Some(format!("Unknown ({})", n).into()),
642 }.into())
643 },
644 _ => None,
645 }
646 }
647
scene_capture_type(e: &TagValue) -> Option<Cow<'static, str>>648 pub(crate) fn scene_capture_type(e: &TagValue) -> Option<Cow<'static, str>> {
649 match *e {
650 TagValue::U16(ref v) => {
651 Some(match v.get(0)? {
652 0 => "Standard",
653 1 => "Landscape",
654 2 => "Portrait",
655 3 => "Night scene",
656 n => return Some(format!("Unknown ({})", n).into()),
657 }.into())
658 },
659 _ => None,
660 }
661 }
662
scene_type(e: &TagValue) -> Option<Cow<'static, str>>663 pub(crate) fn scene_type(e: &TagValue) -> Option<Cow<'static, str>> {
664 match *e {
665 TagValue::Undefined(ref v, _) => {
666 Some(match v.get(0)? {
667 1 => "Directly photographed image",
668 n => return Some(format!("Unknown ({})", n).into()),
669 }.into())
670 },
671 _ => None,
672 }
673 }
674
white_balance_mode(e: &TagValue) -> Option<Cow<'static, str>>675 pub(crate) fn white_balance_mode(e: &TagValue) -> Option<Cow<'static, str>> {
676 match *e {
677 TagValue::U16(ref v) => {
678 Some(match v.get(0)? {
679 0 => "Auto",
680 1 => "Manual",
681 n => return Some(format!("Unknown ({})", n).into()),
682 }.into())
683 },
684 _ => None,
685 }
686 }
687
sensing_method(e: &TagValue) -> Option<Cow<'static, str>>688 pub(crate) fn sensing_method(e: &TagValue) -> Option<Cow<'static, str>> {
689 match *e {
690 TagValue::U16(ref v) => {
691 Some(match v.get(0)? {
692 1 => "Not defined",
693 2 => "One-chip color area sensor",
694 3 => "Two-chip color area sensor",
695 4 => "Three-chip color area sensor",
696 5 => "Color sequential area sensor",
697 7 => "Trilinear sensor",
698 8 => "Color sequential linear sensor",
699 n => return Some(format!("Unknown ({})", n).into()),
700 }.into())
701 },
702 _ => None,
703 }
704 }
705
custom_rendered(e: &TagValue) -> Option<Cow<'static, str>>706 pub(crate) fn custom_rendered(e: &TagValue) -> Option<Cow<'static, str>> {
707 match *e {
708 TagValue::U16(ref v) => {
709 Some(match v.get(0)? {
710 0 => "Normal",
711 1 => "Custom",
712 n => return Some(format!("Unknown ({})", n).into()),
713 }.into())
714 },
715 _ => None,
716 }
717 }
718
subject_distance_range(e: &TagValue) -> Option<Cow<'static, str>>719 pub(crate) fn subject_distance_range(e: &TagValue) -> Option<Cow<'static, str>> {
720 match *e {
721 TagValue::U16(ref v) => {
722 Some(match v.get(0)? {
723 0 => "Unknown",
724 1 => "Macro",
725 2 => "Close view",
726 3 => "Distant view",
727 n => return Some(format!("Unknown ({})", n).into()),
728 }.into())
729 },
730 _ => None,
731 }
732 }
733
lens_spec(e: &TagValue) -> Option<Cow<'static, str>>734 pub(crate) fn lens_spec(e: &TagValue) -> Option<Cow<'static, str>> {
735 match *e {
736 TagValue::URational(ref v) if v.len() >= 4 => {
737 let f0 = v[0].value();
738 let f1 = v[1].value();
739 let a0 = v[2].value();
740 let a1 = v[3].value();
741
742 Some(if v[0] == v[1] {
743 if a0.is_finite() {
744 format!("{} mm f/{:.1}", f0, a0)
745 } else {
746 format!("{} mm f/unknown", f0)
747 }
748 } else if a0.is_finite() && a1.is_finite() {
749 format!("{}-{} mm f/{:.1}-{:.1}", f0, f1, a0, a1)
750 } else {
751 format!("{}-{} mm f/unknown", f0, f1)
752 }.into())
753 },
754 _ => None,
755 }
756 }
757