Skip to content

Commit 7495e4b

Browse files
authored
Merge pull request #2387 from awxkee/jpeg_yuv_fixed_point
YUV in JPEG in fixed point
2 parents 5080752 + 7b8f79a commit 7495e4b

File tree

2 files changed

+33
-16
lines changed

2 files changed

+33
-16
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,4 @@ harness = false
114114
[[bench]]
115115
path = "benches/blur.rs"
116116
name = "blur"
117-
harness = false
117+
harness = false

src/codecs/jpeg/encoder.rs

+32-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#![allow(clippy::too_many_arguments)]
22

3-
use std::borrow::Cow;
4-
use std::io::{self, Write};
5-
63
use crate::error::{
74
ImageError, ImageResult, ParameterError, ParameterErrorKind, UnsupportedError,
85
UnsupportedErrorKind,
96
};
107
use crate::image::{ImageEncoder, ImageFormat};
118
use crate::utils::clamp;
129
use crate::{ExtendedColorType, GenericImageView, ImageBuffer, Luma, Pixel, Rgb};
10+
use num_traits::ToPrimitive;
11+
use std::borrow::Cow;
12+
use std::io::{self, Write};
1313

1414
use super::entropy::build_huff_lut_const;
1515
use super::transform;
@@ -771,19 +771,36 @@ fn encode_coefficient(coefficient: i32) -> (u8, u16) {
771771

772772
#[inline]
773773
fn rgb_to_ycbcr<P: Pixel>(pixel: P) -> (u8, u8, u8) {
774-
use crate::traits::Primitive;
775-
use num_traits::cast::ToPrimitive;
776-
777774
let [r, g, b] = pixel.to_rgb().0;
778-
let max: f32 = P::Subpixel::DEFAULT_MAX_VALUE.to_f32().unwrap();
779-
let r: f32 = r.to_f32().unwrap();
780-
let g: f32 = g.to_f32().unwrap();
781-
let b: f32 = b.to_f32().unwrap();
782-
783-
// Coefficients from JPEG File Interchange Format (Version 1.02), multiplied for 255 maximum.
784-
let y = 76.245 / max * r + 149.685 / max * g + 29.07 / max * b;
785-
let cb = -43.0185 / max * r - 84.4815 / max * g + 127.5 / max * b + 128.;
786-
let cr = 127.5 / max * r - 106.7685 / max * g - 20.7315 / max * b + 128.;
775+
let r: i32 = r.to_u8().unwrap() as i32;
776+
let g: i32 = g.to_u8().unwrap() as i32;
777+
let b: i32 = b.to_u8().unwrap() as i32;
778+
779+
/*
780+
JPEG RGB -> YCbCr is defined as following equations using Bt.601 Full Range matrix:
781+
Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
782+
Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + 128
783+
Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + 128
784+
785+
To avoid using slow floating point conversion is done in fixed point,
786+
using following coefficients with rounding to nearest integer mode:
787+
*/
788+
789+
const C_YR: i32 = 19595; // 0.29900 = 19595 * 2^-16
790+
const C_YG: i32 = 38469; // 0.58700 = 38469 * 2^-16
791+
const C_YB: i32 = 7471; // 0.11400 = 7471 * 2^-16
792+
const Y_ROUNDING: i32 = (1 << 15) - 1; // + 0.5 to perform rounding shift right in-place
793+
const C_UR: i32 = 11059; // 0.16874 = 11059 * 2^-16
794+
const C_UG: i32 = 21709; // 0.33126 = 21709 * 2^-16
795+
const C_UB: i32 = 32768; // 0.5 = 32768 * 2^-16
796+
const UV_BIAS_ROUNDING: i32 = (128 * (1 << 16)) + ((1 << 15) - 1); // 128 + 0.5 = ((128 * (1 << 16)) + ((1 << 15) - 1)) * 2^-16 ; + 0.5 to perform rounding shift right in-place
797+
const C_VR: i32 = C_UB; // 0.5 = 32768 * 2^-16
798+
const C_VG: i32 = 27439; // 0.41869 = 27439 * 2^-16
799+
const C_VB: i32 = 5329; // 0.08131409 = 5329 * 2^-16
800+
801+
let y = (C_YR * r + C_YG * g + C_YB * b + Y_ROUNDING) >> 16;
802+
let cb = (-C_UR * r - C_UG * g + C_UB * b + UV_BIAS_ROUNDING) >> 16;
803+
let cr = (C_VR * r - C_VG * g - C_VB * b + UV_BIAS_ROUNDING) >> 16;
787804

788805
(y as u8, cb as u8, cr as u8)
789806
}

0 commit comments

Comments
 (0)