      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()),
            }
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g., `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g., `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g., `str,u8` or `String,struct:Vec,test`)