use std::io::{BufRead, Cursor, Seek, SeekFrom, BufReader};
use std::fs::File;
use std::path::Path;
use std::result;
use types::{Result, Dimensions};
use traits::LoadableMetadata;
use formats::{jpeg, png, gif, webp};
use generic::markers::MetadataMarker;
pub mod markers {
use std::io::{BufRead, Seek};
use std::path::Path;
use std::result;
use generic::GenericMetadata;
use types::Result;
use formats::{jpeg, png, gif, webp};
pub trait MetadataMarker {
type Metadata;
fn from_generic(gmd: GenericMetadata) -> result::Result<Self::Metadata, GenericMetadata>;
fn from_generic_ref(gmd: &GenericMetadata) -> Option<&Self::Metadata>;
fn load<R: ?Sized + BufRead>(r: &mut R) -> Result<Self::Metadata>;
fn load_from_seek<R: ?Sized + BufRead + Seek>(r: &mut R) -> Result<Self::Metadata>;
fn load_from_file<P: AsRef<Path>>(p: P) -> Result<Self::Metadata>;
fn load_from_buf(b: &[u8]) -> Result<Self::Metadata>;
}
macro_rules! impl_metadata_marker {
($name:ident, $gvar:ident, $mtpe:ty) => {
pub enum $name {}
impl MetadataMarker for $name {
type Metadata = $mtpe;
#[inline]
fn from_generic(gmd: GenericMetadata) -> result::Result<$mtpe, GenericMetadata> {
match gmd {
$crate::generic::GenericMetadata::$gvar(md) => Ok(md),
gmd => Err(gmd)
}
}
#[inline]
fn from_generic_ref(gmd: &GenericMetadata) -> Option<&$mtpe> {
match *gmd {
$crate::generic::GenericMetadata::$gvar(ref md) => Some(md),
_ => None
}
}
#[inline]
fn load<R: ?Sized + BufRead>(r: &mut R) -> Result<$mtpe> {
$crate::traits::LoadableMetadata::load(r)
}
#[inline]
fn load_from_seek<R: ?Sized + BufRead + Seek>(r: &mut R) -> Result<$mtpe> {
$crate::traits::LoadableMetadata::load_from_seek(r)
}
#[inline]
fn load_from_file<P: AsRef<Path>>(p: P) -> Result<$mtpe> {
$crate::traits::LoadableMetadata::load_from_file(p)
}
#[inline]
fn load_from_buf(b: &[u8]) -> Result<$mtpe> {
$crate::traits::LoadableMetadata::load_from_buf(b)
}
}
}
}
impl_metadata_marker! { Jpeg, Jpeg, jpeg::Metadata }
impl_metadata_marker! { Png, Png, png::Metadata }
impl_metadata_marker! { Gif, Gif, gif::Metadata }
impl_metadata_marker! { Webp, Webp, webp::Metadata }
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum GenericMetadata {
Png(png::Metadata),
Gif(gif::Metadata),
Jpeg(jpeg::Metadata),
Webp(webp::Metadata)
}
impl GenericMetadata {
pub fn dimensions(&self) -> Dimensions {
match *self {
GenericMetadata::Png(ref md) => md.dimensions,
GenericMetadata::Gif(ref md) => md.dimensions,
GenericMetadata::Jpeg(ref md) => md.dimensions,
GenericMetadata::Webp(ref md) => md.dimensions()
}
}
pub fn mime_type(&self) -> &'static str {
match *self {
GenericMetadata::Png(_) => "image/png",
GenericMetadata::Gif(_) => "image/gif",
GenericMetadata::Jpeg(_) => "image/jpeg",
GenericMetadata::Webp(_) => "image/webp"
}
}
#[inline]
pub fn into<T: MetadataMarker>(self) -> result::Result<T::Metadata, GenericMetadata> {
<T as MetadataMarker>::from_generic(self)
}
#[inline]
pub fn as_ref<T: MetadataMarker>(&self) -> Option<&T::Metadata> {
<T as MetadataMarker>::from_generic_ref(self)
}
}
pub fn load<R: ?Sized + BufRead + Seek>(r: &mut R) -> Result<GenericMetadata> {
try!(r.seek(SeekFrom::Start(0)));
if let Ok(md) = png::Metadata::load_from_seek(r) {
return Ok(GenericMetadata::Png(md));
}
try!(r.seek(SeekFrom::Start(0)));
if let Ok(md) = gif::Metadata::load_from_seek(r) {
return Ok(GenericMetadata::Gif(md));
}
try!(r.seek(SeekFrom::Start(0)));
if let Ok(md) = webp::Metadata::load_from_seek(r) {
return Ok(GenericMetadata::Webp(md));
}
try!(r.seek(SeekFrom::Start(0)));
if let Ok(md) = jpeg::Metadata::load_from_seek(r) {
return Ok(GenericMetadata::Jpeg(md));
}
Err(invalid_format!("unknown or unsupported image type"))
}
pub fn load_from_file<P: AsRef<Path>>(p: P) -> Result<GenericMetadata> {
let mut f = BufReader::new(try!(File::open(p)));
load(&mut f)
}
pub fn load_from_buf(b: &[u8]) -> Result<GenericMetadata> {
load(&mut Cursor::new(b))
}