kamadak / exif-rs

Exif parsing library written in pure Rust
BSD 2-Clause "Simplified" License
198 stars 44 forks source link

Request for example usages #2

Closed tungel closed 7 years ago

tungel commented 7 years ago

Hi, thank you so much for making this library.

I'm new to Rust and find that it's quite hard to use this library. Basically I would like to get some basic info from an JPG image like: width, height, datetime taken, resolution, ...

Could you please include a simple code snippet that demonstrate how to get those data from an image's exif?

Ortham commented 7 years ago

Not a maintainer, but if you just want an example, my utility Yore uses this library. You can see how I get timestamps and GPS metadata here.

I agree though, examples would be good. Maybe I can contribute my code as one, if I make some time too.

tungel commented 7 years ago

@WrinklyNinja Thank you very much for the link to your code. I came up with a simple snippet that gets the datetime when the photo was created:

let file = std::fs::File::open("photo.jpg").expect("Error opening pic file");
let mut reader = exif::Reader::new(&mut std::io::BufReader::new(&file)).unwrap();

// Created date time
if let Some(field) = reader.get_field(exif::tag::DateTimeOriginal, false) {
    if let exif::Value::Ascii(_) = field.value {
        println!("Created datetime = {}", field.value.display_as(field.tag))
    }
}

That works fine, and I can get a few more exif fields too. However, I can't find a way to get the image resolution (width, height) with this library. Is there anything that I'm missing?

kamadak commented 7 years ago

I have added an example in the repository, which includes how to get the image width and the image resolution. When printing values, Value::display_as can be used without matching against Value variants. So, if @tungel's question is about printing the value, the following code would do it.

if let Some(field) = reader.get_field(exif::tag::ImageWidth, false) {
    println!("Image width = {}", field.value.display_as(field.tag))
}

I can imagine the difficulty @tungel is feeling. Using exif-rs requires some knowledge on Exif for now: DateTime is encoded in ASCII, ImageWidth in SHORT or LONG, XResolution in RATIONAL, and so on.

I guess adding high-level APIs (see an example below) to exif-rs may be a good idea. However, I also feel that such APIs should support other formats than Exif, so they should reside in a separate high-level library that is built on top of exif-rs and other format-specific libraries.

struct EasyToUseWrapperForReader {
    inner: Reader,
}

impl EasyToUseWrapperForReader {
    fn image_width(&self, thumbnail: bool) -> Option<u32> {
        self.inner.get_field(tag::ImageWidth, thumbnail)
            .and_then(|f| f.value.get_uint(0))
    }

    fn date_time(&self, thumbnail: bool) -> Option<DateTime> {
        self.inner.get_field(tag::DateTime, thumbnail)
            .and_then(|f| match f.value {
                Value::Ascii(ref vec) if !vec.is_empty() => DateTime::from_ascii(vec[0]).ok(),
                _ => None,
            })
    }

    // Many dedicated methods for popular fields follow...
}
tungel commented 7 years ago

Cool. Thank you very much for the detail info. I guess this issue can now be closed.