Skip to content

Commit e999d78

Browse files
author
HeroicKatora
authored
Merge pull request #157 from Shnatsel/faster-color-conversions
Faster color conversions
2 parents 2439a90 + 4f98377 commit e999d78

File tree

1 file changed

+36
-31
lines changed

1 file changed

+36
-31
lines changed

src/decoder.rs

+36-31
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ fn compute_image_parallel(components: &[Component],
841841
.enumerate()
842842
.for_each(|(row, line)| {
843843
upsampler.upsample_and_interleave_row(&data, row, output_size.width as usize, line);
844-
color_convert_func(line, output_size.width as usize);
844+
color_convert_func(line);
845845
});
846846

847847
Ok(image)
@@ -861,7 +861,7 @@ fn compute_image_parallel(components: &[Component],
861861
for (row, line) in image.chunks_mut(line_size)
862862
.enumerate() {
863863
upsampler.upsample_and_interleave_row(&data, row, output_size.width as usize, line);
864-
color_convert_func(line, output_size.width as usize);
864+
color_convert_func(line);
865865
}
866866

867867
Ok(image)
@@ -870,7 +870,7 @@ fn compute_image_parallel(components: &[Component],
870870
fn choose_color_convert_func(component_count: usize,
871871
_is_jfif: bool,
872872
color_transform: Option<AdobeColorTransform>)
873-
-> Result<fn(&mut [u8], usize)> {
873+
-> Result<fn(&mut [u8])> {
874874
match component_count {
875875
3 => {
876876
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
@@ -894,37 +894,36 @@ fn choose_color_convert_func(component_count: usize,
894894
}
895895
}
896896

897-
fn color_convert_line_null(_data: &mut [u8], _width: usize) {
897+
fn color_convert_line_null(_data: &mut [u8]) {
898898
}
899899

900-
fn color_convert_line_ycbcr(data: &mut [u8], width: usize) {
901-
for i in 0 .. width {
902-
let (r, g, b) = ycbcr_to_rgb(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);
903-
904-
data[i * 3] = r;
905-
data[i * 3 + 1] = g;
906-
data[i * 3 + 2] = b;
900+
fn color_convert_line_ycbcr(data: &mut [u8]) {
901+
for chunk in data.chunks_exact_mut(3) {
902+
let (r, g, b) = ycbcr_to_rgb(chunk[0], chunk[1], chunk[2]);
903+
chunk[0] = r;
904+
chunk[1] = g;
905+
chunk[2] = b;
907906
}
908907
}
909908

910-
fn color_convert_line_ycck(data: &mut [u8], width: usize) {
911-
for i in 0 .. width {
912-
let (r, g, b) = ycbcr_to_rgb(data[i * 4], data[i * 4 + 1], data[i * 4 + 2]);
913-
let k = data[i * 4 + 3];
909+
fn color_convert_line_ycck(data: &mut [u8]) {
910+
for chunk in data.chunks_exact_mut(4) {
911+
let (r, g, b) = ycbcr_to_rgb(chunk[0], chunk[1], chunk[2]);
912+
let k = chunk[3];
913+
chunk[0] = r;
914+
chunk[1] = g;
915+
chunk[2] = b;
916+
chunk[3] = 255 - k;
914917

915-
data[i * 4] = r;
916-
data[i * 4 + 1] = g;
917-
data[i * 4 + 2] = b;
918-
data[i * 4 + 3] = 255 - k;
919918
}
920919
}
921920

922-
fn color_convert_line_cmyk(data: &mut [u8], width: usize) {
923-
for i in 0 .. width {
924-
data[i * 4] = 255 - data[i * 4];
925-
data[i * 4 + 1] = 255 - data[i * 4 + 1];
926-
data[i * 4 + 2] = 255 - data[i * 4 + 2];
927-
data[i * 4 + 3] = 255 - data[i * 4 + 3];
921+
fn color_convert_line_cmyk(data: &mut [u8]) {
922+
for chunk in data.chunks_exact_mut(4) {
923+
chunk[0] = 255 - chunk[0];
924+
chunk[1] = 255 - chunk[1];
925+
chunk[2] = 255 - chunk[2];
926+
chunk[3] = 255 - chunk[3];
928927
}
929928
}
930929

@@ -938,13 +937,19 @@ fn ycbcr_to_rgb(y: u8, cb: u8, cr: u8) -> (u8, u8, u8) {
938937
let g = y - 0.34414 * cb - 0.71414 * cr;
939938
let b = y + 1.77200 * cb;
940939

941-
(clamp((r + 0.5) as i32, 0, 255) as u8,
942-
clamp((g + 0.5) as i32, 0, 255) as u8,
943-
clamp((b + 0.5) as i32, 0, 255) as u8)
940+
// TODO: Rust has defined float-to-int conversion as saturating,
941+
// which is exactly what we need here. However, as of this writing
942+
// it still hasn't reached the stable channel.
943+
// This can be simplified to `(r + 0.5) as u8` without any clamping
944+
// as soon as our MSRV reaches the version that has saturating casts.
945+
// The version without explicit clamping is also noticeably faster.
946+
(clamp_to_u8((r + 0.5) as i32) as u8,
947+
clamp_to_u8((g + 0.5) as i32) as u8,
948+
clamp_to_u8((b + 0.5) as i32) as u8)
944949
}
945950

946-
fn clamp<T: PartialOrd>(value: T, min: T, max: T) -> T {
947-
if value < min { return min; }
948-
if value > max { return max; }
951+
fn clamp_to_u8(value: i32) -> i32 {
952+
let value = std::cmp::max(value, 0);
953+
let value = std::cmp::min(value, 255);
949954
value
950955
}

0 commit comments

Comments
 (0)