1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
extern crate jpeg_decoder;

use std::io::{Cursor, Read};

use color::ColorType;
use image::{ImageDecoder, ImageError, ImageResult};

/// JPEG decoder
pub struct JPEGDecoder<R> {
    decoder: jpeg_decoder::Decoder<R>,
    metadata: jpeg_decoder::ImageInfo,
}

impl<R: Read> JPEGDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<JPEGDecoder<R>> {
        let mut decoder = jpeg_decoder::Decoder::new(r);

        decoder.read_info()?;
        let mut metadata = decoder.info().unwrap();

        // We convert CMYK data to RGB before returning it to the user.
        if metadata.pixel_format == jpeg_decoder::PixelFormat::CMYK32 {
            metadata.pixel_format = jpeg_decoder::PixelFormat::RGB24;
        }

        Ok(JPEGDecoder {
            decoder,
            metadata,
        })
    }
}

impl<R: Read> ImageDecoder for JPEGDecoder<R> {
    type Reader = Cursor<Vec<u8>>;

    fn dimensions(&self) -> (u64, u64) {
        (self.metadata.width as u64, self.metadata.height as u64)
    }

    fn colortype(&self) -> ColorType {
        self.metadata.pixel_format.into()
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(Cursor::new(self.read_image()?))
    }

    fn read_image(mut self) -> ImageResult<Vec<u8>> {
        let mut data = self.decoder.decode()?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg_decoder::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        Ok(data)
    }
}

fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
    let size = input.len() - input.len() / 4;
    let mut output = Vec::with_capacity(size);

    for pixel in input.chunks(4) {
        let c = f32::from(pixel[0]) / 255.0;
        let m = f32::from(pixel[1]) / 255.0;
        let y = f32::from(pixel[2]) / 255.0;
        let k = f32::from(pixel[3]) / 255.0;

        // CMYK -> CMY
        let c = c * (1.0 - k) + k;
        let m = m * (1.0 - k) + k;
        let y = y * (1.0 - k) + k;

        // CMY -> RGB
        let r = (1.0 - c) * 255.0;
        let g = (1.0 - m) * 255.0;
        let b = (1.0 - y) * 255.0;

        output.push(r as u8);
        output.push(g as u8);
        output.push(b as u8);
    }

    output
}

impl From<jpeg_decoder::PixelFormat> for ColorType {
    fn from(pixel_format: jpeg_decoder::PixelFormat) -> ColorType {
        use self::jpeg_decoder::PixelFormat::*;
        match pixel_format {
            L8 => ColorType::Gray(8),
            RGB24 => ColorType::RGB(8),
            CMYK32 => panic!(),
        }
    }
}

impl From<jpeg_decoder::Error> for ImageError {
    fn from(err: jpeg_decoder::Error) -> ImageError {
        use self::jpeg_decoder::Error::*;
        match err {
            Format(desc) => ImageError::FormatError(desc),
            Unsupported(desc) => ImageError::UnsupportedError(format!("{:?}", desc)),
            Io(err) => ImageError::IoError(err),
            Internal(err) => ImageError::FormatError(err.description().to_owned()),
        }
    }
}