| extern crate jpeg_decoder as jpeg; |
| extern crate png; |
| |
| use std::env; |
| use std::fs::File; |
| use std::io::{self, BufReader, Write}; |
| use std::process; |
| |
| fn usage() -> ! { |
| write!(io::stderr(), "usage: decode image.jpg image.png").unwrap(); |
| process::exit(1) |
| } |
| |
| fn main() { |
| let mut args = env::args().skip(1); |
| let input_path = args.next().unwrap_or_else(|| usage()); |
| let output_path = args.next().unwrap_or_else(|| usage()); |
| |
| let input_file = File::open(input_path).expect("The specified input file could not be opened"); |
| let mut decoder = jpeg::Decoder::new(BufReader::new(input_file)); |
| 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"); |
| let info = decoder.info().unwrap(); |
| |
| eprintln!("{:?}", info); |
| eprintln!("Exif: {}", decoder.exif_data().is_some()); |
| eprintln!("XMP: {}", decoder.xmp_data().is_some()); |
| eprintln!("ICC: {}", decoder.icc_profile().is_some()); |
| |
| let output_file = File::create(output_path).unwrap(); |
| let mut encoder = png::Encoder::new(output_file, info.width as u32, info.height as u32); |
| |
| match info.pixel_format { |
| jpeg::PixelFormat::L16 => { |
| encoder.set_depth(png::BitDepth::Sixteen); |
| encoder.set_color(png::ColorType::Grayscale); |
| }, |
| jpeg::PixelFormat::RGB24 => { |
| encoder.set_depth(png::BitDepth::Eight); |
| encoder.set_color(png::ColorType::RGB); |
| }, |
| jpeg::PixelFormat::CMYK32 => { |
| data = cmyk_to_rgb(&mut data); |
| encoder.set_depth(png::BitDepth::Eight); |
| encoder.set_color(png::ColorType::RGB) |
| }, |
| jpeg::PixelFormat::L8 => { |
| encoder.set_depth(png::BitDepth::Eight); |
| encoder.set_color(png::ColorType::Grayscale); |
| }, |
| } |
| |
| encoder.write_header() |
| .expect("writing png header failed") |
| .write_image_data(&data) |
| .expect("png encoding failed"); |
| } |
| |
| 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 = pixel[0] as f32 / 255.0; |
| let m = pixel[1] as f32 / 255.0; |
| let y = pixel[2] as f32 / 255.0; |
| let k = pixel[3] as f32 / 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 |
| } |