-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathjpegify.oc
118 lines (100 loc) · 3.23 KB
/
jpegify.oc
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
110
111
112
113
114
115
116
117
118
import std::fft::{ fft2, ifft2 }
import std::mem
import std::math::{ TAU }
import std::image::{ Image, Color }
import std::complex::Complex
import std::libc::{ free, memcpy }
import std::sort::sort
def get_image_channel(img: &Image, out: &Complex, channel: i32) {
for let i = 0; i < img.height * img.width; i++ {
let col = img.data[i]
let val = match channel {
0 => col.r as f32 / 255.0,
1 => col.g as f32 / 255.0,
2 => col.b as f32 / 255.0,
else => (col.r + col.g + col.b) as f32 / (3.0 * 255.0)
}
out[i] = Complex::new(val, 0.0)
}
}
def save_image_channel(img: &Image, data: &Complex, channel: i32) {
for let i = 0; i < img.height * img.width; i++ {
let val = data[i].real().clamp01()
let val_u8 = (val * 255.0) as u8
match channel {
0 => img.data[i].r = val_u8
1 => img.data[i].g = val_u8
2 => img.data[i].b = val_u8
else => img.data[i] = Color(val_u8, val_u8, val_u8)
}
}
}
def process_channel(img: &Image, channel: i32, discard_pct: f32) {
let num_pixels = img.width * img.height
let data_a = mem::alloc<Complex>(num_pixels)
let data_b = mem::alloc<Complex>(num_pixels)
get_image_channel(img, data_a, channel)
fft2(data_a, img.height, img.width, data_b)
let tmp = mem::alloc<Complex>(num_pixels)
memcpy(tmp, data_b, num_pixels * sizeof(Complex))
sort<Complex>(tmp, num_pixels)
let index = (num_pixels as f32 * discard_pct) as u32
let threshold = tmp[index].abs()
for let i = 0; i < num_pixels; i++ {
if data_b[i].abs() < threshold {
data_b[i] = Complex::new(0.0, 0.0)
}
}
free(tmp)
ifft2(data_b, img.height, img.width, data_a)
save_image_channel(img, data_a, channel)
free(data_a)
free(data_b)
}
def process_image_rgb(img: &Image, discard_pct: f32) {
process_channel(img, channel: 0, discard_pct)
process_channel(img, channel: 1, discard_pct)
process_channel(img, channel: 2, discard_pct)
}
def process_image_grayscale(img: &Image, discard_pct: f32) {
process_channel(img, channel: -1, discard_pct)
}
def main(argc: i32, argv: &str) {
let input = null as str
let output = null as str
let quality = 0.01
let grayscale = false
let pos_count = 0
for let i = 1i32; i < argc; i++ {
let arg = argv[i]
if arg.eq("-q") {
assert i+1 < argc, "Missing argument for -q"
quality = argv[i + 1].to_f32()
assert 0.0 <= quality <= 1.0, "Quality must be between 0 and 1"
i++
} else if arg.eq("-g") {
grayscale = true
} else if pos_count == 0 {
input = arg
pos_count++
} else if pos_count == 1 {
output = arg
pos_count++
} else {
println("Unknown argument: {arg}")
return 1
}
}
if pos_count != 2 {
println("Usage: {argv[0]} [-q quality] [-g] input output")
return 1
}
let img = Image::load(input)
if grayscale {
process_image_grayscale(img, 1.0 - quality)
} else {
process_image_rgb(img, 1.0 - quality)
}
img.save(output)
img.free()
}