1 #![allow(clippy::upper_case_acronyms)]
2
3 //! RExif is a native Rust create, written to extract EXIF data from JPEG and TIFF images.
4 //!
5 //! Note that it is in very early stages of development. Any sort of feedback is welcome!
6 //!
7 //! The crate contains a
8 //! sample binary called 'rexiftool' that accepts files as arguments and prints the EXIF data. It gives
9 //! a rough idea on how to use the crate. Get some sample images and run
10 //!
11 //!
12 //! `cargo run [image file 1] [image file 2] ...`
13 //!
14 //!
15 //! To learn to use this crate, start by the documentation of function `parse_file()`,
16 //! and the struct `ExifData` that is returned by the parser. The rest falls more or less into place.
17 //!
18 //! Code sample lightly edited from src/bin.rs:
19 //!
20 //! ```
21 //! use std::error::Error;
22 //!
23 //! let file_name = "foo.jpg";
24 //! match rexif::parse_file(&file_name) {
25 //! Ok(exif) => {
26 //! println!("{} {} exif entries: {}", file_name, exif.mime, exif.entries.len());
27 //! for entry in &exif.entries {
28 //! println!("\t{}: {}", entry.tag, entry.value_more_readable);
29 //! }
30 //! },
31 //! Err(e) => {
32 //! print!("Error in {}: {}", &file_name, e)
33 //! }
34 //! }
35 //! ```
36
37 use std::fs::File;
38 use std::io::{Read, Seek, SeekFrom};
39 use std::path::Path;
40
41 mod lowlevel;
42 mod rational;
43 pub use self::rational::*;
44 mod types;
45 pub use self::types::*;
46 mod types_impl;
47 pub use self::types_impl::*;
48 mod image;
49 use self::image::*;
50 mod ifdformat;
51 mod tiff;
52 use self::tiff::*;
53 mod exif;
54 mod exifpost;
55 mod exifreadable;
56
57 /// Parse a byte buffer that should contain a TIFF or JPEG image.
58 /// Tries to detect format and parse EXIF data.
59 ///
60 /// Prints warnings to stderr.
parse_buffer(contents: &[u8]) -> ExifResult61 pub fn parse_buffer(contents: &[u8]) -> ExifResult {
62 let (res, warnings) = parse_buffer_quiet(contents);
63 warnings.into_iter().for_each(|w| eprintln!("{}", w));
64 res
65 }
66
67 /// Parse a byte buffer that should contain a TIFF or JPEG image.
68 /// Tries to detect format and parse EXIF data.
69 ///
70 /// Returns warnings alongside result.
parse_buffer_quiet(contents: &[u8]) -> (ExifResult, Vec<String>)71 pub fn parse_buffer_quiet(contents: &[u8]) -> (ExifResult, Vec<String>) {
72 let mime = detect_type(contents);
73 let mut warnings = vec![];
74 let (entries, le) = match mime {
75 FileType::Unknown => return (Err(ExifError::FileTypeUnknown), warnings),
76 FileType::TIFF => parse_tiff(contents, &mut warnings),
77 FileType::JPEG => {
78 match find_embedded_tiff_in_jpeg(contents).and_then(|(offset, size)| {
79 Ok(parse_tiff(&contents[offset..offset + size], &mut warnings))
80 }) {
81 Ok(r) => r,
82 Err(e) => return (Err(e), warnings)
83 }
84 }
85 };
86
87 (
88 entries.map(|entries| ExifData {
89 mime: mime.as_str(),
90 entries,
91 le
92 }),
93 warnings,
94 )
95 }
96
97 /// Try to read and parse an open file that is expected to contain an image
read_file(f: &mut File) -> ExifResult98 pub fn read_file(f: &mut File) -> ExifResult {
99 f.seek(SeekFrom::Start(0))?;
100
101 // TODO: should read only the relevant parts of a file,
102 // and pass a StringIO-like object instead of a Vec buffer
103
104 let mut contents: Vec<u8> = Vec::new();
105 f.read_to_end(&mut contents)?;
106 parse_buffer(&contents)
107 }
108
109 /// Opens an image (passed as a file name), tries to read and parse it.
parse_file<P: AsRef<Path>>(fname: P) -> ExifResult110 pub fn parse_file<P: AsRef<Path>>(fname: P) -> ExifResult {
111 read_file(&mut File::open(fname)?)
112 }
113