use std::io;
use thiserror::Error;
use crate::core::BitDepth;
#[cfg(feature = "tiff-parser")]
use crate::tiff::TiffTag;
#[derive(Debug, Error)]
pub enum RawError {
#[error("I/O error: {0}")]
Io(#[from] io::Error),
#[error(transparent)]
Parse(#[from] ParseError),
#[error(transparent)]
Format(#[from] FormatError),
#[error(transparent)]
Processing(#[from] ProcessingError),
#[error(transparent)]
Encode(#[from] EncodeError),
#[error("Unsupported: {0}")]
Unsupported(String),
}
#[derive(Debug, Error)]
pub enum ParseError {
#[error("Invalid TIFF magic number: expected {expected}, found {found}")]
InvalidMagic {
expected: u16,
found: u16,
},
#[error("Invalid byte order marker: 0x{0:04X} (expected 'II' or 'MM')")]
InvalidByteOrder(u16),
#[error("Invalid IFD at offset {offset}: {reason}")]
InvalidIfd {
offset: u64,
reason: String,
},
#[cfg(feature = "tiff-parser")]
#[error("Required tag not found: {0}")]
TagNotFound(TiffTag),
#[error("Offset out of bounds: offset {offset} + size {size} exceeds file size {file_size}")]
OffsetOutOfBounds {
offset: u64,
size: u64,
file_size: u64,
},
#[error("Unknown TIFF data type: {0}")]
UnknownDataType(u16),
#[error("Invalid image dimensions: {width}x{height}")]
InvalidDimensions {
width: u32,
height: u32,
},
#[error("Circular reference detected in IFD chain at offset {0}")]
CircularReference(u64),
#[error("Binary parse error: {0}")]
BinaryParse(String),
}
#[derive(Debug, Error)]
pub enum FormatError {
#[cfg(feature = "cr2-decode")]
#[error("CR2 error: {0}")]
Cr2(String),
#[cfg(feature = "nef-decode")]
#[error("NEF error: {0}")]
Nef(String),
#[cfg(feature = "cr3-decode")]
#[error("CR3 error: {0}")]
Cr3(String),
#[cfg(feature = "raf-decode")]
#[error("RAF error: {0}")]
Raf(String),
#[cfg(feature = "crw-decode")]
#[error("CRW error: {0}")]
Crw(String),
#[error("Image decode error ({format}): {message}")]
ImageDecode {
format: &'static str,
message: String,
},
#[error("Decompression error: {0}")]
Decompression(String),
}
#[derive(Debug, Error)]
pub enum ProcessingError {
#[error("Demosaic error: {0}")]
Demosaic(String),
#[error("Color processing error: {0}")]
Color(String),
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum EncodeError {
#[error("Encoding error ({format}): {message}")]
Encoding {
format: &'static str,
message: String,
},
#[error("{format} encoder does not support {requested:?} output")]
UnsupportedBitDepth {
format: &'static str,
requested: BitDepth,
},
#[cfg(feature = "jpeg-encode")]
#[error("JPEG encoding error: {0}")]
Jpeg(#[from] jpeg_encoder::EncodingError),
#[error("WebP error: {0}")]
WebP(String),
}
#[cfg(feature = "tiff-parser")]
impl From<binrw::Error> for RawError {
fn from(err: binrw::Error) -> Self {
RawError::Parse(ParseError::BinaryParse(err.to_string()))
}
}
#[cfg(feature = "jpeg-encode")]
impl From<jpeg_encoder::EncodingError> for RawError {
fn from(err: jpeg_encoder::EncodingError) -> Self {
RawError::Encode(EncodeError::Jpeg(err))
}
}
pub type RawResult<T> = Result<T, RawError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = RawError::Parse(ParseError::InvalidMagic {
expected: 42,
found: 0,
});
let s = format!("{}", err);
assert!(s.contains("Invalid TIFF magic"));
#[cfg(feature = "tiff-parser")]
{
let err = RawError::Parse(ParseError::TagNotFound(crate::tiff::TiffTag::ImageWidth));
let s = format!("{}", err);
assert!(s.contains("ImageWidth"));
}
}
#[test]
fn test_io_error_conversion() {
let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
let raw_err: RawError = io_err.into();
assert!(matches!(raw_err, RawError::Io(_)));
}
#[test]
fn test_parse_error_conversion() {
let parse_err = ParseError::InvalidByteOrder(0x1234);
let raw_err: RawError = parse_err.into();
assert!(matches!(
raw_err,
RawError::Parse(ParseError::InvalidByteOrder(0x1234))
));
}
#[cfg(feature = "cr2-decode")]
#[test]
fn test_format_error_conversion() {
let fmt_err = FormatError::Cr2("test error".to_string());
let raw_err: RawError = fmt_err.into();
assert!(matches!(raw_err, RawError::Format(FormatError::Cr2(_))));
}
#[test]
fn test_encode_error_conversion() {
let enc_err = EncodeError::Encoding {
format: "PNG",
message: "test".to_string(),
};
let raw_err: RawError = enc_err.into();
assert!(matches!(
raw_err,
RawError::Encode(EncodeError::Encoding { .. })
));
}
}