pub use parser::{MediaKind, MediaParser, MediaSource};
pub use video::{TrackInfo, TrackInfoTag};
#[cfg(feature = "tokio")]
pub use parser_async::AsyncMediaSource;
pub use exif::gps::{Altitude, LatRef, LonRef, Speed, SpeedUnit};
pub use exif::{
Exif, ExifEntry, ExifIter, ExifIterEntry, ExifTag, GPSInfo, IfdIndex, LatLng, TagOrCode,
};
pub use values::{EntryValue, ExifDateTime, IRational, Rational, URational};
pub use error::{ConvertError, EntryError, Error, MalformedKind};
pub mod prelude {
pub use crate::{read_exif, read_metadata, read_track};
pub use crate::{
EntryValue, Error, Exif, ExifIter, ExifTag, GPSInfo, IfdIndex, MalformedKind, MediaKind,
MediaParser, MediaSource, Metadata, Result, TrackInfo, TrackInfoTag,
};
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub enum Metadata {
Exif(Exif),
Track(TrackInfo),
}
use std::path::Path;
pub fn read_exif(path: impl AsRef<Path>) -> Result<Exif> {
let iter = read_exif_iter(path)?;
Ok(iter.into())
}
pub fn read_exif_iter(path: impl AsRef<Path>) -> Result<ExifIter> {
let file = std::fs::File::open(path)?;
let ms = MediaSource::seekable(file)?;
let mut parser = MediaParser::new();
parser.parse_exif(ms)
}
pub fn read_track(path: impl AsRef<Path>) -> Result<TrackInfo> {
let file = std::fs::File::open(path)?;
let ms = MediaSource::seekable(file)?;
let mut parser = MediaParser::new();
parser.parse_track(ms)
}
pub fn read_metadata(path: impl AsRef<Path>) -> Result<Metadata> {
let file = std::fs::File::open(path)?;
let ms = MediaSource::seekable(file)?;
let mut parser = MediaParser::new();
match ms.kind() {
MediaKind::Image => parser.parse_exif(ms).map(|i| Metadata::Exif(i.into())),
MediaKind::Track => parser.parse_track(ms).map(Metadata::Track),
}
}
pub fn read_exif_from_bytes(bytes: impl Into<bytes::Bytes>) -> Result<Exif> {
let iter = read_exif_iter_from_bytes(bytes)?;
Ok(iter.into())
}
pub fn read_exif_iter_from_bytes(bytes: impl Into<bytes::Bytes>) -> Result<ExifIter> {
let ms = MediaSource::from_bytes(bytes)?;
let mut parser = MediaParser::new();
parser.parse_exif_from_bytes(ms)
}
pub fn read_track_from_bytes(bytes: impl Into<bytes::Bytes>) -> Result<TrackInfo> {
let ms = MediaSource::from_bytes(bytes)?;
let mut parser = MediaParser::new();
parser.parse_track_from_bytes(ms)
}
pub fn read_metadata_from_bytes(bytes: impl Into<bytes::Bytes>) -> Result<Metadata> {
let ms = MediaSource::from_bytes(bytes)?;
let mut parser = MediaParser::new();
match ms.kind() {
MediaKind::Image => parser
.parse_exif_from_bytes(ms)
.map(|i| Metadata::Exif(i.into())),
MediaKind::Track => parser.parse_track_from_bytes(ms).map(Metadata::Track),
}
}
#[cfg(feature = "tokio")]
mod tokio_top_level {
use super::*;
pub async fn read_exif_async(path: impl AsRef<std::path::Path>) -> Result<Exif> {
let iter = read_exif_iter_async(path).await?;
Ok(iter.into())
}
pub async fn read_exif_iter_async(path: impl AsRef<std::path::Path>) -> Result<ExifIter> {
let file = tokio::fs::File::open(path).await?;
let ms = parser_async::AsyncMediaSource::seekable(file).await?;
let mut parser = MediaParser::new();
parser.parse_exif_async(ms).await
}
pub async fn read_track_async(path: impl AsRef<std::path::Path>) -> Result<TrackInfo> {
let file = tokio::fs::File::open(path).await?;
let ms = parser_async::AsyncMediaSource::seekable(file).await?;
let mut parser = MediaParser::new();
parser.parse_track_async(ms).await
}
pub async fn read_metadata_async(path: impl AsRef<std::path::Path>) -> Result<Metadata> {
let file = tokio::fs::File::open(path).await?;
let ms = parser_async::AsyncMediaSource::seekable(file).await?;
let mut parser = MediaParser::new();
match ms.kind() {
MediaKind::Image => parser
.parse_exif_async(ms)
.await
.map(|i| Metadata::Exif(i.into())),
MediaKind::Track => parser.parse_track_async(ms).await.map(Metadata::Track),
}
}
}
#[cfg(feature = "tokio")]
pub use tokio_top_level::{
read_exif_async, read_exif_iter_async, read_metadata_async, read_track_async,
};
mod bbox;
mod cr3;
mod ebml;
mod error;
mod exif;
mod file;
mod heif;
mod jpeg;
mod mov;
mod parser;
#[cfg(feature = "tokio")]
mod parser_async;
mod raf;
mod slice;
mod utils;
mod values;
mod video;
#[cfg(test)]
mod testkit;
#[cfg(test)]
mod v3_top_level_tests {
use super::*;
#[test]
fn read_exif_jpg() {
let exif = read_exif("testdata/exif.jpg").unwrap();
assert!(exif.get(ExifTag::Make).is_some());
}
#[test]
fn read_track_mov() {
let info = read_track("testdata/meta.mov").unwrap();
assert!(info.get(TrackInfoTag::Make).is_some());
}
#[test]
fn read_metadata_dispatches_image() {
match read_metadata("testdata/exif.jpg").unwrap() {
Metadata::Exif(_) => {}
Metadata::Track(_) => panic!("expected Exif variant"),
}
}
#[test]
fn read_metadata_dispatches_track() {
match read_metadata("testdata/meta.mov").unwrap() {
Metadata::Track(_) => {}
Metadata::Exif(_) => panic!("expected Track variant"),
}
}
#[cfg(feature = "tokio")]
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn read_exif_async_jpg() {
let exif = read_exif_async("testdata/exif.jpg").await.unwrap();
assert!(exif.get(ExifTag::Make).is_some());
}
#[cfg(feature = "tokio")]
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn read_track_async_mov() {
let info = read_track_async("testdata/meta.mov").await.unwrap();
assert!(info.get(TrackInfoTag::Make).is_some());
}
#[test]
fn read_exif_from_bytes_jpg() {
let raw = std::fs::read("testdata/exif.jpg").unwrap();
let exif = read_exif_from_bytes(raw).unwrap();
assert!(exif.get(ExifTag::Make).is_some());
}
#[test]
fn read_exif_iter_from_bytes_jpg() {
let raw = std::fs::read("testdata/exif.jpg").unwrap();
let iter = read_exif_iter_from_bytes(raw).unwrap();
assert!(iter.into_iter().count() > 0);
}
#[test]
fn read_track_from_bytes_mov() {
let raw = std::fs::read("testdata/meta.mov").unwrap();
let info = read_track_from_bytes(raw).unwrap();
assert!(info.get(TrackInfoTag::Make).is_some());
}
#[test]
fn read_metadata_from_bytes_dispatches_image() {
let raw = std::fs::read("testdata/exif.jpg").unwrap();
match read_metadata_from_bytes(raw).unwrap() {
Metadata::Exif(_) => {}
Metadata::Track(_) => panic!("expected Exif variant"),
}
}
#[test]
fn read_metadata_from_bytes_dispatches_track() {
let raw = std::fs::read("testdata/meta.mov").unwrap();
match read_metadata_from_bytes(raw).unwrap() {
Metadata::Track(_) => {}
Metadata::Exif(_) => panic!("expected Track variant"),
}
}
#[test]
fn read_exif_from_bytes_static_slice() {
let raw: &'static [u8] = include_bytes!("../testdata/exif.jpg");
let exif = read_exif_from_bytes(raw).unwrap();
assert!(exif.get(ExifTag::Make).is_some());
}
#[test]
fn prelude_imports_compile() {
use crate::prelude::*;
fn _consume(_: Option<Exif>, _: Option<TrackInfo>, _: Option<MediaParser>) {}
let _e = read_exif("testdata/exif.jpg");
let _t = read_track("testdata/meta.mov");
let _m = read_metadata("testdata/exif.jpg");
}
}