use std::fs::File;
use std::io::{self, BufRead, BufReader, Cursor, Read, Seek, SeekFrom};
use std::path::Path;
use dynimage::DynamicImage;
use image::ImageFormat;
use {ImageError, ImageResult};
use super::free_functions;
#[cfg_attr(feature = "pnm", doc = "```")]
#[cfg_attr(not(feature = "pnm"), doc = "```no_run")]
pub struct Reader<R: Read> {
inner: R,
format: Option<ImageFormat>,
}
impl<R: Read> Reader<R> {
pub fn new(reader: R) -> Self {
Reader {
inner: reader,
format: None,
}
}
pub fn with_format(reader: R, format: ImageFormat) -> Self {
Reader {
inner: reader,
format: Some(format),
}
}
pub fn format(&self) -> Option<ImageFormat> {
self.format
}
pub fn set_format(&mut self, format: ImageFormat) {
self.format = Some(format);
}
pub fn clear_format(&mut self) {
self.format = None;
}
pub fn into_inner(self) -> R {
self.inner
}
}
impl Reader<BufReader<File>> {
pub fn open<P>(path: P) -> io::Result<Self> where P: AsRef<Path> {
Self::open_impl(path.as_ref())
}
fn open_impl(path: &Path) -> io::Result<Self> {
let file = File::open(path)?;
Ok(Reader {
inner: BufReader::new(file),
format: ImageFormat::from_path(path).ok(),
})
}
}
impl<R: BufRead + Seek> Reader<R> {
pub fn with_guessed_format(mut self) -> io::Result<Self> {
let format = self.guess_format()?;
self.format = format.or(self.format);
Ok(self)
}
fn guess_format(&mut self) -> io::Result<Option<ImageFormat>> {
let mut start = [0; 16];
let cur = self.inner.seek(SeekFrom::Current(0))?;
let len = io::copy(
&mut self.inner.by_ref().take(16),
&mut Cursor::new(&mut start[..]))?;
self.inner.seek(SeekFrom::Start(cur))?;
Ok(free_functions::guess_format_impl(&start[..len as usize]))
}
pub fn into_dimensions(mut self) -> ImageResult<(u32, u32)> {
let format = self.require_format()?;
free_functions::image_dimensions_with_format_impl(self.inner, format)
}
pub fn decode(mut self) -> ImageResult<DynamicImage> {
let format = self.require_format()?;
free_functions::load(self.inner, format)
}
fn require_format(&mut self) -> ImageResult<ImageFormat> {
self.format.ok_or_else(||
ImageError::UnsupportedError("Unable to determine image format".into()))
}
}