use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;
use image::error::{
DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use image::ColorType;
use image::{ImageDecoder, ImageFormat};
use crate::jpeg::AppMarkerConfig;
pub use decoder::{Decoder, ImageInfo, PixelFormat};
pub use error::{Error, UnsupportedFeature};
mod decoder;
mod error;
mod huffman;
mod idct;
mod marker;
mod parser;
mod upsampler;
mod worker;
fn read_u8<R: std::io::Read>(reader: &mut R) -> std::io::Result<u8> {
let mut buf = [0];
reader.read_exact(&mut buf)?;
Ok(buf[0])
}
fn read_u16_from_be<R: std::io::Read>(reader: &mut R) -> std::io::Result<u16> {
let mut buf = [0, 0];
reader.read_exact(&mut buf)?;
Ok(u16::from_be_bytes(buf))
}
pub struct AppMarkerJpegDecoder<R, W> {
decoder: self::Decoder<R, W>,
metadata: self::ImageInfo,
}
impl<R: Read, W: Write> AppMarkerJpegDecoder<R, W> {
pub fn new(r: R, w: W, config: AppMarkerConfig) -> ImageResult<AppMarkerJpegDecoder<R, W>> {
let mut decoder = self::Decoder::new(r, w, config);
decoder.read_info().map_err(jpeg_error_to_image_error)?;
let mut metadata = decoder.info().ok_or_else(|| {
ImageError::Decoding(DecodingError::from_format_hint(ImageFormat::Jpeg.into()))
})?;
if metadata.pixel_format == self::PixelFormat::CMYK32 {
metadata.pixel_format = self::PixelFormat::RGB24;
}
Ok(AppMarkerJpegDecoder { decoder, metadata })
}
pub fn scale(
&mut self,
requested_width: u16,
requested_height: u16,
) -> ImageResult<(u16, u16)> {
let result = self
.decoder
.scale(requested_width, requested_height)
.map_err(jpeg_error_to_image_error)?;
self.metadata.width = result.0;
self.metadata.height = result.1;
Ok(result)
}
}
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
if self.0.position() == 0 && buf.is_empty() {
mem::swap(buf, self.0.get_mut());
Ok(buf.len())
} else {
self.0.read_to_end(buf)
}
}
}
impl<'a, R: 'a + Read, W: Write> ImageDecoder<'a> for AppMarkerJpegDecoder<R, W> {
type Reader = JpegReader<R>;
fn dimensions(&self) -> (u32, u32) {
(
u32::from(self.metadata.width),
u32::from(self.metadata.height),
)
}
fn color_type(&self) -> ColorType {
pixel_format_to_color_type(self.metadata.pixel_format)
}
fn into_reader(mut self) -> ImageResult<Self::Reader> {
let mut data = self.decoder.decode().map_err(jpeg_error_to_image_error)?;
data = match self.decoder.info().unwrap().pixel_format {
self::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
_ => data,
};
Ok(JpegReader(Cursor::new(data), PhantomData))
}
fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
let mut data = self.decoder.decode().map_err(jpeg_error_to_image_error)?;
data = match self.decoder.info().unwrap().pixel_format {
self::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
_ => data,
};
buf.copy_from_slice(&data);
Ok(())
}
}
fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
let count = input.len() / 4;
let mut output = vec![0; 3 * count];
let in_pixels = input[..4 * count].chunks_exact(4);
let out_pixels = output[..3 * count].chunks_exact_mut(3);
for (pixel, outp) in in_pixels.zip(out_pixels) {
let c = 255 - u16::from(pixel[0]);
let m = 255 - u16::from(pixel[1]);
let y = 255 - u16::from(pixel[2]);
let k = 255 - u16::from(pixel[3]);
let r = (k * c) / 255;
let g = (k * m) / 255;
let b = (k * y) / 255;
outp[0] = r as u8;
outp[1] = g as u8;
outp[2] = b as u8;
}
output
}
fn pixel_format_to_color_type(pixel_format: self::PixelFormat) -> ColorType {
use self::PixelFormat::*;
match pixel_format {
L8 => ColorType::L8,
RGB24 => ColorType::Rgb8,
CMYK32 => panic!(),
}
}
fn jpeg_error_to_image_error(err: self::Error) -> ImageError {
use self::Error::*;
match err {
err @ Format(_) => ImageError::Decoding(DecodingError::new(ImageFormat::Jpeg.into(), err)),
Unsupported(desc) => ImageError::Unsupported(UnsupportedError::from_format_and_kind(
ImageFormat::Jpeg.into(),
UnsupportedErrorKind::GenericFeature(format!("{:?}", desc)),
)),
Io(err) => ImageError::IoError(err),
Internal(err) => ImageError::Decoding(DecodingError::new(ImageFormat::Jpeg.into(), err)),
}
}