@@ -841,7 +841,7 @@ fn compute_image_parallel(components: &[Component],
841
841
. enumerate ( )
842
842
. for_each ( |( row, line) | {
843
843
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) ;
845
845
} ) ;
846
846
847
847
Ok ( image)
@@ -861,7 +861,7 @@ fn compute_image_parallel(components: &[Component],
861
861
for ( row, line) in image. chunks_mut ( line_size)
862
862
. enumerate ( ) {
863
863
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) ;
865
865
}
866
866
867
867
Ok ( image)
@@ -870,7 +870,7 @@ fn compute_image_parallel(components: &[Component],
870
870
fn choose_color_convert_func ( component_count : usize ,
871
871
_is_jfif : bool ,
872
872
color_transform : Option < AdobeColorTransform > )
873
- -> Result < fn ( & mut [ u8 ] , usize ) > {
873
+ -> Result < fn ( & mut [ u8 ] ) > {
874
874
match component_count {
875
875
3 => {
876
876
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
@@ -894,37 +894,36 @@ fn choose_color_convert_func(component_count: usize,
894
894
}
895
895
}
896
896
897
- fn color_convert_line_null ( _data : & mut [ u8 ] , _width : usize ) {
897
+ fn color_convert_line_null ( _data : & mut [ u8 ] ) {
898
898
}
899
899
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;
907
906
}
908
907
}
909
908
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;
914
917
915
- data[ i * 4 ] = r;
916
- data[ i * 4 + 1 ] = g;
917
- data[ i * 4 + 2 ] = b;
918
- data[ i * 4 + 3 ] = 255 - k;
919
918
}
920
919
}
921
920
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 ] ;
928
927
}
929
928
}
930
929
@@ -938,13 +937,19 @@ fn ycbcr_to_rgb(y: u8, cb: u8, cr: u8) -> (u8, u8, u8) {
938
937
let g = y - 0.34414 * cb - 0.71414 * cr;
939
938
let b = y + 1.77200 * cb;
940
939
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 )
944
949
}
945
950
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 ) ;
949
954
value
950
955
}
0 commit comments