diff --git a/src/decoder.rs b/src/decoder.rs index 11de44dd..b9f97cff 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -272,6 +272,7 @@ impl Decoder { )); } + let mut recoverable_error = None; let mut previous_marker = Marker::SOI; let mut pending_marker = None; let mut scans_processed = 0; @@ -291,7 +292,13 @@ impl Decoder { loop { let marker = match pending_marker.take() { Some(m) => m, - None => self.read_marker()?, + None => match self.read_marker() { + Err(e) => { + recoverable_error = Some(e); + break; + }, + Ok(v) => v, + }, }; match marker { @@ -566,10 +573,16 @@ impl Decoder { let frame = self.frame.as_ref().unwrap(); let preference = Self::select_worker(&frame, PreferWorkerKind::Multithreaded); - worker_scope.get_or_init_worker( + let pixels = worker_scope.get_or_init_worker( preference, |worker| self.decode_planes(worker, planes, planes_u16) - ) + )?; + + if let Some(error) = recoverable_error { + Err(Error::Recoverable { err: Box::new(error), pixels: pixels }) + } else { + Ok(pixels) + } } fn decode_planes( diff --git a/src/error.rs b/src/error.rs index aafa62cc..a061ac59 100644 --- a/src/error.rs +++ b/src/error.rs @@ -30,7 +30,6 @@ pub enum UnsupportedFeature { } /// Errors that can occur while decoding a JPEG image. -#[derive(Debug)] pub enum Error { /// The image is not formatted properly. The string contains detailed information about the /// error. @@ -41,6 +40,13 @@ pub enum Error { Io(IoError), /// An internal error occurred while decoding the image. Internal(Box), //TODO: not used, can be removed with the next version bump + /// An error that occurred during the decode, but allows for incomplete image pixel data to be returned with `try_recover()` + Recoverable { + /// Error occurred while decoding the image + err: Box, + /// Incomplete pixel data of the image + pixels: Vec + } } impl fmt::Display for Error { @@ -50,6 +56,19 @@ impl fmt::Display for Error { Error::Unsupported(ref feat) => write!(f, "unsupported JPEG feature: {:?}", feat), Error::Io(ref err) => err.fmt(f), Error::Internal(ref err) => err.fmt(f), + Error::Recoverable { ref err, .. } => err.fmt(f), + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Format(err) => f.debug_tuple("Format").field(err).finish(), + Self::Unsupported(err) => f.debug_tuple("Unsupported").field(err).finish(), + Self::Io(err) => f.debug_tuple("Io").field(err).finish(), + Self::Internal(err) => f.debug_tuple("Internal").field(err).finish(), + Self::Recoverable { ref err, .. } => f.debug_tuple("Recoverable").field(err).finish(), } } } @@ -69,3 +88,20 @@ impl From for Error { Error::Io(err) } } + +/// A trait that, if supported, returns incomplete image pixel data +pub trait TryRecover { + /// Returns incomplete image pixel data if supported. Otherwise, simply passes through the original value. + fn try_recover(self) -> Self; +} + +impl TryRecover for Result> { + fn try_recover(self) -> Self { + self.or_else(|err| match err { + Error::Recoverable { pixels, .. } => { + Ok(pixels) + }, + _ => Err(err), + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index c2f74574..8463472e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ extern crate core; extern crate rayon; pub use decoder::{Decoder, ImageInfo, PixelFormat}; -pub use error::{Error, UnsupportedFeature}; +pub use error::{Error, UnsupportedFeature, TryRecover}; pub use parser::CodingProcess; use std::io;