-
Notifications
You must be signed in to change notification settings - Fork 17
/
reencode.rs
97 lines (79 loc) · 3.19 KB
/
reencode.rs
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
//! All of this can be done easier and better with the higher-level wrapper:
//!
//! https://lib.rs/crates/mozjpeg
//!
//! Don't forget to build it with `--release` flag, otherwise it will be unoptimized
//! and noticeably slow.
use mozjpeg_sys::*;
use std::ffi::CString;
use std::mem;
fn main() {
let file_name = std::env::args().nth(1).expect("Specify a JPEG image path");
unsafe {
let (buffer, width, height) = decode(&file_name);
encode(&buffer, width, height);
}
}
unsafe fn decode(file_name: &str) -> (Vec<u8>, u32, u32) {
let mut err: jpeg_error_mgr = mem::zeroed();
let mut cinfo: jpeg_decompress_struct = mem::zeroed();
cinfo.common.err = jpeg_std_error(&mut err);
jpeg_create_decompress(&mut cinfo);
let c_file_name = CString::new(file_name.as_bytes()).unwrap();
let fh = libc::fopen(c_file_name.as_ptr(), b"rb\0".as_ptr().cast());
if fh.is_null() {
panic!("Can't open {file_name}");
}
jpeg_stdio_src(&mut cinfo, fh);
jpeg_read_header(&mut cinfo, true as boolean);
let width = cinfo.image_width;
let height = cinfo.image_height;
println!("Image size {width}x{height}");
cinfo.out_color_space = J_COLOR_SPACE::JCS_RGB;
jpeg_start_decompress(&mut cinfo);
let row_stride = cinfo.image_width as usize * cinfo.output_components as usize;
let buffer_size = row_stride * cinfo.image_height as usize;
let mut buffer = vec![0u8; buffer_size];
while cinfo.output_scanline < cinfo.output_height {
let offset = cinfo.output_scanline as usize * row_stride;
let mut jsamparray = [buffer[offset..].as_mut_ptr()];
jpeg_read_scanlines(&mut cinfo, jsamparray.as_mut_ptr(), 1);
}
println!("Decoded into {} raw pixel bytes", buffer.len());
jpeg_finish_decompress(&mut cinfo);
jpeg_destroy_decompress(&mut cinfo);
libc::fclose(fh);
(buffer, width, height)
}
unsafe fn encode(buffer: &[u8], width: u32, height: u32) {
let file_name = "example_result.jpg";
println!("Writing {file_name}");
let quality = 98;
let c_file_name = CString::new(file_name).unwrap();
let fh = libc::fopen(c_file_name.as_ptr(), b"wb\0".as_ptr().cast());
if fh.is_null() {
panic!("Can't write {file_name}");
}
let mut err = mem::zeroed();
let mut cinfo: jpeg_compress_struct = mem::zeroed();
cinfo.common.err = jpeg_std_error(&mut err);
jpeg_create_compress(&mut cinfo);
jpeg_stdio_dest(&mut cinfo, fh);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.in_color_space = J_COLOR_SPACE::JCS_RGB;
cinfo.input_components = 3;
jpeg_set_defaults(&mut cinfo);
let row_stride = cinfo.image_width as usize * cinfo.input_components as usize;
cinfo.dct_method = J_DCT_METHOD::JDCT_ISLOW;
jpeg_set_quality(&mut cinfo, quality, true as boolean);
jpeg_start_compress(&mut cinfo, true as boolean);
while cinfo.next_scanline < cinfo.image_height {
let offset = cinfo.next_scanline as usize * row_stride;
let jsamparray = [buffer[offset..].as_ptr()];
jpeg_write_scanlines(&mut cinfo, jsamparray.as_ptr(), 1);
}
jpeg_finish_compress(&mut cinfo);
jpeg_destroy_compress(&mut cinfo);
libc::fclose(fh);
}