Skip to main content

rs_exif2json/
lib.rs

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}