1 extern crate jpeg_decoder as jpeg;
2 extern crate png;
3 
4 use std::env;
5 use std::fs::File;
6 use std::io::{self, BufReader, Write};
7 use std::process;
8 
usage() -> !9 fn usage() -> ! {
10     write!(io::stderr(), "usage: decode image.jpg image.png").unwrap();
11     process::exit(1)
12 }
13 
main()14 fn main() {
15     let mut args = env::args().skip(1);
16     let input_path = args.next().unwrap_or_else(|| usage());
17     let output_path = args.next().unwrap_or_else(|| usage());
18 
19     let input_file = File::open(input_path).expect("The specified input file could not be opened");
20     let mut decoder = jpeg::Decoder::new(BufReader::new(input_file));
21     let mut data = decoder.decode().expect("Decoding failed. If other software can successfully decode the specified JPEG image, then it's likely that there is a bug in jpeg-decoder");
22     let info = decoder.info().unwrap();
23 
24     let output_file = File::create(output_path).unwrap();
25     let mut encoder = png::Encoder::new(output_file, info.width as u32, info.height as u32);
26     encoder.set_depth(png::BitDepth::Eight);
27 
28     match info.pixel_format {
29         jpeg::PixelFormat::L8     => encoder.set_color(png::ColorType::Grayscale),
30         jpeg::PixelFormat::RGB24  => encoder.set_color(png::ColorType::RGB),
31         jpeg::PixelFormat::CMYK32 => {
32             data = cmyk_to_rgb(&mut data);
33             encoder.set_color(png::ColorType::RGB)
34         },
35     };
36 
37     encoder.write_header()
38            .expect("writing png header failed")
39            .write_image_data(&data)
40            .expect("png encoding failed");
41 }
42 
cmyk_to_rgb(input: &[u8]) -> Vec<u8>43 fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
44     let size = input.len() - input.len() / 4;
45     let mut output = Vec::with_capacity(size);
46 
47     for pixel in input.chunks(4) {
48         let c = pixel[0] as f32 / 255.0;
49         let m = pixel[1] as f32 / 255.0;
50         let y = pixel[2] as f32 / 255.0;
51         let k = pixel[3] as f32 / 255.0;
52 
53         // CMYK -> CMY
54         let c = c * (1.0 - k) + k;
55         let m = m * (1.0 - k) + k;
56         let y = y * (1.0 - k) + k;
57 
58         // CMY -> RGB
59         let r = (1.0 - c) * 255.0;
60         let g = (1.0 - m) * 255.0;
61         let b = (1.0 - y) * 255.0;
62 
63         output.push(r as u8);
64         output.push(g as u8);
65         output.push(b as u8);
66     }
67 
68     output
69 }
70