1use std::io;
2
3use io::BufWriter;
4use io::Write;
5
6use io::BufRead;
7use io::Cursor;
8use io::Read;
9use io::Seek;
10
11use exif::Exif;
12use exif::Field;
13use exif::Reader;
14use exif::Tag;
15
16#[derive(serde::Serialize)]
17#[non_exhaustive]
18pub enum ExifCtx {
19 Unspecified,
20 Tiff,
21 Exif,
22 Gps,
23 Interop,
24}
25
26impl From<exif::Context> for ExifCtx {
27 fn from(ctx: exif::Context) -> Self {
28 match ctx {
29 exif::Context::Tiff => Self::Tiff,
30 exif::Context::Exif => Self::Exif,
31 exif::Context::Gps => Self::Gps,
32 exif::Context::Interop => Self::Interop,
33 _ => Self::Unspecified,
34 }
35 }
36}
37
38#[derive(serde::Serialize)]
39pub struct ExifTag {
40 pub ctx: ExifCtx,
41 pub eno: u16,
42}
43
44impl From<Tag> for ExifTag {
45 fn from(tag: Tag) -> Self {
46 Self {
47 ctx: tag.0.into(),
48 eno: tag.1,
49 }
50 }
51}
52
53#[derive(serde::Serialize)]
54pub struct ExifField {
55 pub tag: String,
56 pub val: String,
57}
58
59impl From<&Field> for ExifField {
60 fn from(field: &Field) -> Self {
61 Self {
62 tag: format!("{}", field.tag),
63 val: field.display_value().to_string(),
64 }
65 }
66}
67
68pub fn exif2writer<W>(ex: &Exif, mut wtr: W) -> Result<(), io::Error>
69where
70 W: Write,
71{
72 let fields = ex.fields();
73 for field in fields {
74 let ef: ExifField = field.into();
75 serde_json::to_writer(&mut wtr, &ef)?;
76 writeln!(&mut wtr)?;
77 }
78 wtr.flush()
79}
80
81pub fn exif2stdout(ex: &Exif) -> Result<(), io::Error> {
82 let o = io::stdout();
83 let mut ol = o.lock();
84 exif2writer(ex, BufWriter::new(&mut ol))?;
85 ol.flush()
86}
87
88pub fn exif_bytes2exif(rdr: &Reader, dat: Vec<u8>) -> Result<Exif, io::Error> {
89 rdr.read_raw(dat).map_err(io::Error::other)
90}
91
92pub fn exif_container2exif<C>(rdr: &Reader, container: &mut C) -> Result<Option<Exif>, io::Error>
93where
94 C: BufRead + Seek,
95{
96 match rdr.read_from_container(container) {
97 Ok(ex) => Ok(Some(ex)),
98 Err(e) => match e {
99 exif::Error::NotFound(_) => Ok(None),
100 _ => Err(io::Error::other(e)),
101 },
102 }
103}
104
105pub fn img_bytes2exif(rdr: &Reader, img: &[u8]) -> Result<Option<Exif>, io::Error> {
106 let mut cursor = Cursor::new(img);
107 exif_container2exif(rdr, &mut cursor)
108}
109
110pub fn reader2exif<R>(max_input_bytes: u64, rdr: R) -> Result<Option<Exif>, io::Error>
111where
112 R: BufRead,
113{
114 let mut taken = rdr.take(max_input_bytes);
115 let mut buf: Vec<u8> = vec![];
116 taken.read_to_end(&mut buf)?;
117 let erdr = Reader::new();
118 img_bytes2exif(&erdr, &buf)
119}
120
121pub fn stdin2exif(max_input_bytes: u64) -> Result<Option<Exif>, io::Error> {
122 reader2exif(max_input_bytes, io::stdin().lock())
123}
124
125pub const MAX_INPUT_BYTES_DEFAULT: u64 = 16777216;
126
127pub fn stdin2exif2json2stdout(max_input_bytes: u64) -> Result<(), io::Error> {
128 let oex: Option<Exif> = stdin2exif(max_input_bytes)?;
129 match oex {
130 None => Ok(()),
131 Some(ex) => exif2stdout(&ex),
132 }
133}