#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
use crate::transform_neon::{
qcms_transform_data_bgra_out_lut_neon, qcms_transform_data_rgb_out_lut_neon,
qcms_transform_data_rgba_out_lut_neon,
};
use crate::{
chain::qcms_chain_transform,
double_to_s15Fixed16Number,
iccread::qcms_supports_iccv4,
matrix::*,
transform_util::{
build_colorant_matrix, build_input_gamma_table, build_output_lut, compute_precache,
lut_interp_linear,
},
};
use crate::{
iccread::{curveType, qcms_CIE_xyY, qcms_CIE_xyYTRIPLE, qcms_profile},
qcms_intent, s15Fixed16Number,
transform_util::clamp_float,
};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use crate::{
transform_avx::{
qcms_transform_data_bgra_out_lut_avx, qcms_transform_data_rgb_out_lut_avx,
qcms_transform_data_rgba_out_lut_avx,
},
transform_sse2::{
qcms_transform_data_bgra_out_lut_sse2, qcms_transform_data_rgb_out_lut_sse2,
qcms_transform_data_rgba_out_lut_sse2,
},
};
use ::libc::{self, free, malloc};
use std::sync::Arc;
use std::{ptr::null_mut, sync::atomic::Ordering};
pub const PRECACHE_OUTPUT_SIZE: usize = 8192;
pub const PRECACHE_OUTPUT_MAX: usize = PRECACHE_OUTPUT_SIZE - 1;
pub const FLOATSCALE: f32 = PRECACHE_OUTPUT_SIZE as f32;
pub const CLAMPMAXVAL: f32 = ((PRECACHE_OUTPUT_SIZE - 1) as f32) / PRECACHE_OUTPUT_SIZE as f32;
#[repr(C)]
pub struct precache_output {
pub data: [u8; PRECACHE_OUTPUT_SIZE],
}
impl Default for precache_output {
fn default() -> precache_output {
precache_output {
data: [0; PRECACHE_OUTPUT_SIZE],
}
}
}
#[repr(C)]
#[repr(align(16))]
#[derive(Clone)]
pub struct qcms_transform {
pub matrix: [[f32; 4]; 3],
pub input_gamma_table_r: Option<Vec<f32>>,
pub input_gamma_table_g: Option<Vec<f32>>,
pub input_gamma_table_b: Option<Vec<f32>>,
pub input_clut_table_r: *mut f32,
pub input_clut_table_g: *mut f32,
pub input_clut_table_b: *mut f32,
pub input_clut_table_length: u16,
pub r_clut: *mut f32,
pub g_clut: *mut f32,
pub b_clut: *mut f32,
pub grid_size: u16,
pub output_clut_table_r: *mut f32,
pub output_clut_table_g: *mut f32,
pub output_clut_table_b: *mut f32,
pub output_clut_table_length: u16,
pub input_gamma_table_gray: Option<Vec<f32>>,
pub out_gamma_r: f32,
pub out_gamma_g: f32,
pub out_gamma_b: f32,
pub out_gamma_gray: f32,
pub output_gamma_lut_r: Option<Vec<u16>>,
pub output_gamma_lut_g: Option<Vec<u16>>,
pub output_gamma_lut_b: Option<Vec<u16>>,
pub output_gamma_lut_gray: Option<Vec<u16>>,
pub output_gamma_lut_r_length: usize,
pub output_gamma_lut_g_length: usize,
pub output_gamma_lut_b_length: usize,
pub output_gamma_lut_gray_length: usize,
pub output_table_r: Option<Arc<precache_output>>,
pub output_table_g: Option<Arc<precache_output>>,
pub output_table_b: Option<Arc<precache_output>>,
pub transform_fn: transform_fn_t,
}
impl Default for qcms_transform {
fn default() -> qcms_transform {
qcms_transform {
matrix: Default::default(),
input_gamma_table_r: Default::default(),
input_gamma_table_b: Default::default(),
input_gamma_table_g: Default::default(),
input_clut_table_r: null_mut(),
input_clut_table_g: null_mut(),
input_clut_table_b: null_mut(),
input_clut_table_length: Default::default(),
r_clut: null_mut(),
g_clut: null_mut(),
b_clut: null_mut(),
grid_size: Default::default(),
output_clut_table_r: null_mut(),
output_clut_table_g: null_mut(),
output_clut_table_b: null_mut(),
output_clut_table_length: Default::default(),
input_gamma_table_gray: Default::default(),
out_gamma_r: Default::default(),
out_gamma_g: Default::default(),
out_gamma_b: Default::default(),
out_gamma_gray: Default::default(),
output_gamma_lut_r: Default::default(),
output_gamma_lut_g: Default::default(),
output_gamma_lut_b: Default::default(),
output_gamma_lut_gray: Default::default(),
output_gamma_lut_r_length: Default::default(),
output_gamma_lut_g_length: Default::default(),
output_gamma_lut_b_length: Default::default(),
output_gamma_lut_gray_length: Default::default(),
output_table_r: Default::default(),
output_table_g: Default::default(),
output_table_b: Default::default(),
transform_fn: Default::default(),
}
}
}
pub type transform_fn_t = Option<
unsafe extern "C" fn(
_: *const qcms_transform,
_: *const libc::c_uchar,
_: *mut libc::c_uchar,
_: usize,
) -> (),
>;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct lutmABType {
pub num_in_channels: u8,
pub num_out_channels: u8,
pub num_grid_points: [u8; 16],
pub e00: s15Fixed16Number,
pub e01: s15Fixed16Number,
pub e02: s15Fixed16Number,
pub e03: s15Fixed16Number,
pub e10: s15Fixed16Number,
pub e11: s15Fixed16Number,
pub e12: s15Fixed16Number,
pub e13: s15Fixed16Number,
pub e20: s15Fixed16Number,
pub e21: s15Fixed16Number,
pub e22: s15Fixed16Number,
pub e23: s15Fixed16Number,
pub reversed: bool,
pub clut_table: *mut f32,
pub a_curves: [*mut curveType; 10],
pub b_curves: [*mut curveType; 10],
pub m_curves: [*mut curveType; 10],
pub clut_table_data: [f32; 0],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct lutType {
pub num_input_channels: u8,
pub num_output_channels: u8,
pub num_clut_grid_points: u8,
pub e00: s15Fixed16Number,
pub e01: s15Fixed16Number,
pub e02: s15Fixed16Number,
pub e10: s15Fixed16Number,
pub e11: s15Fixed16Number,
pub e12: s15Fixed16Number,
pub e20: s15Fixed16Number,
pub e21: s15Fixed16Number,
pub e22: s15Fixed16Number,
pub num_input_table_entries: u16,
pub num_output_table_entries: u16,
pub input_table: *mut f32,
pub clut_table: *mut f32,
pub output_table: *mut f32,
pub table_data: [f32; 0],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct XYZNumber {
pub X: s15Fixed16Number,
pub Y: s15Fixed16Number,
pub Z: s15Fixed16Number,
}
pub type qcms_data_type = libc::c_uint;
pub const QCMS_DATA_GRAYA_8: qcms_data_type = 4;
pub const QCMS_DATA_GRAY_8: qcms_data_type = 3;
pub const QCMS_DATA_BGRA_8: qcms_data_type = 2;
pub const QCMS_DATA_RGBA_8: qcms_data_type = 1;
pub const QCMS_DATA_RGB_8: qcms_data_type = 0;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CIE_XYZ {
pub X: f64,
pub Y: f64,
pub Z: f64,
}
pub trait Format {
const kRIndex: usize;
const kGIndex: usize;
const kBIndex: usize;
const kAIndex: usize;
}
pub struct BGRA;
impl Format for BGRA {
const kBIndex: usize = 0;
const kGIndex: usize = 1;
const kRIndex: usize = 2;
const kAIndex: usize = 3;
}
pub struct RGBA;
impl Format for RGBA {
const kRIndex: usize = 0;
const kGIndex: usize = 1;
const kBIndex: usize = 2;
const kAIndex: usize = 3;
}
pub struct RGB;
impl Format for RGB {
const kRIndex: usize = 0;
const kGIndex: usize = 1;
const kBIndex: usize = 2;
const kAIndex: usize = 0xFF;
}
pub trait GrayFormat {
const has_alpha: bool;
}
pub struct Gray;
impl GrayFormat for Gray {
const has_alpha: bool = false;
}
pub struct GrayAlpha;
impl GrayFormat for GrayAlpha {
const has_alpha: bool = true;
}
#[inline]
fn clamp_u8(mut v: f32) -> u8 {
if v > 255. {
return 255;
} else if v < 0. {
return 0;
} else {
return (v + 0.5).floor() as u8;
};
}
fn build_RGB_to_XYZ_transfer_matrix(
mut white: qcms_CIE_xyY,
mut primrs: qcms_CIE_xyYTRIPLE,
) -> matrix {
let mut primaries: matrix = matrix {
m: [[0.; 3]; 3],
invalid: false,
};
let mut result: matrix = matrix {
m: [[0.; 3]; 3],
invalid: false,
};
let mut white_point: vector = vector { v: [0.; 3] };
let mut xn: f64 = white.x;
let mut yn: f64 = white.y;
if yn == 0.0f64 {
return matrix_invalid();
}
let mut xr: f64 = primrs.red.x;
let mut yr: f64 = primrs.red.y;
let mut xg: f64 = primrs.green.x;
let mut yg: f64 = primrs.green.y;
let mut xb: f64 = primrs.blue.x;
let mut yb: f64 = primrs.blue.y;
primaries.m[0][0] = xr as f32;
primaries.m[0][1] = xg as f32;
primaries.m[0][2] = xb as f32;
primaries.m[1][0] = yr as f32;
primaries.m[1][1] = yg as f32;
primaries.m[1][2] = yb as f32;
primaries.m[2][0] = (1f64 - xr - yr) as f32;
primaries.m[2][1] = (1f64 - xg - yg) as f32;
primaries.m[2][2] = (1f64 - xb - yb) as f32;
primaries.invalid = false;
white_point.v[0] = (xn / yn) as f32;
white_point.v[1] = 1.;
white_point.v[2] = ((1.0f64 - xn - yn) / yn) as f32;
let mut primaries_invert: matrix = matrix_invert(primaries);
if primaries_invert.invalid {
return matrix_invalid();
}
let mut coefs: vector = matrix_eval(primaries_invert, white_point);
result.m[0][0] = (coefs.v[0] as f64 * xr) as f32;
result.m[0][1] = (coefs.v[1] as f64 * xg) as f32;
result.m[0][2] = (coefs.v[2] as f64 * xb) as f32;
result.m[1][0] = (coefs.v[0] as f64 * yr) as f32;
result.m[1][1] = (coefs.v[1] as f64 * yg) as f32;
result.m[1][2] = (coefs.v[2] as f64 * yb) as f32;
result.m[2][0] = (coefs.v[0] as f64 * (1.0f64 - xr - yr)) as f32;
result.m[2][1] = (coefs.v[1] as f64 * (1.0f64 - xg - yg)) as f32;
result.m[2][2] = (coefs.v[2] as f64 * (1.0f64 - xb - yb)) as f32;
result.invalid = primaries_invert.invalid;
return result;
}
const D50_XYZ: CIE_XYZ = CIE_XYZ {
X: 0.9642f64,
Y: 1.0000f64,
Z: 0.8249f64,
};
fn xyY2XYZ(mut source: qcms_CIE_xyY) -> CIE_XYZ {
let mut dest: CIE_XYZ = CIE_XYZ {
X: 0.,
Y: 0.,
Z: 0.,
};
dest.X = source.x / source.y * source.Y;
dest.Y = source.Y;
dest.Z = (1f64 - source.x - source.y) / source.y * source.Y;
return dest;
}
fn compute_chromatic_adaption(
mut source_white_point: CIE_XYZ,
mut dest_white_point: CIE_XYZ,
mut chad: matrix,
) -> matrix {
let mut cone_source_XYZ: vector = vector { v: [0.; 3] };
let mut cone_dest_XYZ: vector = vector { v: [0.; 3] };
let mut cone: matrix = matrix {
m: [[0.; 3]; 3],
invalid: false,
};
let mut tmp: matrix = chad;
let mut chad_inv: matrix = matrix_invert(tmp);
if chad_inv.invalid {
return matrix_invalid();
}
cone_source_XYZ.v[0] = source_white_point.X as f32;
cone_source_XYZ.v[1] = source_white_point.Y as f32;
cone_source_XYZ.v[2] = source_white_point.Z as f32;
cone_dest_XYZ.v[0] = dest_white_point.X as f32;
cone_dest_XYZ.v[1] = dest_white_point.Y as f32;
cone_dest_XYZ.v[2] = dest_white_point.Z as f32;
let mut cone_source_rgb: vector = matrix_eval(chad, cone_source_XYZ);
let mut cone_dest_rgb: vector = matrix_eval(chad, cone_dest_XYZ);
cone.m[0][0] = cone_dest_rgb.v[0] / cone_source_rgb.v[0];
cone.m[0][1] = 0.;
cone.m[0][2] = 0.;
cone.m[1][0] = 0.;
cone.m[1][1] = cone_dest_rgb.v[1] / cone_source_rgb.v[1];
cone.m[1][2] = 0.;
cone.m[2][0] = 0.;
cone.m[2][1] = 0.;
cone.m[2][2] = cone_dest_rgb.v[2] / cone_source_rgb.v[2];
cone.invalid = false;
return matrix_multiply(chad_inv, matrix_multiply(cone, chad));
}
fn adaption_matrix(mut source_illumination: CIE_XYZ, mut target_illumination: CIE_XYZ) -> matrix {
let mut lam_rigg: matrix = {
let mut init = matrix {
m: [
[0.8951, 0.2664, -0.1614],
[-0.7502, 1.7135, 0.0367],
[0.0389, -0.0685, 1.0296],
],
invalid: false,
};
init
};
return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg);
}
fn adapt_matrix_to_D50(mut r: matrix, mut source_white_pt: qcms_CIE_xyY) -> matrix {
if source_white_pt.y == 0.0f64 {
return matrix_invalid();
}
let mut Dn: CIE_XYZ = xyY2XYZ(source_white_pt);
let mut Bradford: matrix = adaption_matrix(Dn, D50_XYZ);
if Bradford.invalid {
return matrix_invalid();
}
return matrix_multiply(Bradford, r);
}
pub fn set_rgb_colorants(
mut profile: &mut qcms_profile,
mut white_point: qcms_CIE_xyY,
mut primaries: qcms_CIE_xyYTRIPLE,
) -> bool {
let mut colorants: matrix = build_RGB_to_XYZ_transfer_matrix(white_point, primaries);
colorants = adapt_matrix_to_D50(colorants, white_point);
if colorants.invalid {
return false;
}
(*profile).redColorant.X = double_to_s15Fixed16Number(colorants.m[0][0] as f64);
(*profile).redColorant.Y = double_to_s15Fixed16Number(colorants.m[1][0] as f64);
(*profile).redColorant.Z = double_to_s15Fixed16Number(colorants.m[2][0] as f64);
(*profile).greenColorant.X = double_to_s15Fixed16Number(colorants.m[0][1] as f64);
(*profile).greenColorant.Y = double_to_s15Fixed16Number(colorants.m[1][1] as f64);
(*profile).greenColorant.Z = double_to_s15Fixed16Number(colorants.m[2][1] as f64);
(*profile).blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2] as f64);
(*profile).blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2] as f64);
(*profile).blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2] as f64);
return true;
}
pub fn get_rgb_colorants(
mut colorants: &mut matrix,
mut white_point: qcms_CIE_xyY,
mut primaries: qcms_CIE_xyYTRIPLE,
) -> bool {
*colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries);
*colorants = adapt_matrix_to_D50(*colorants, white_point);
return if (*colorants).invalid as i32 != 0 {
1
} else {
0
} != 0;
}
unsafe extern "C" fn qcms_transform_data_gray_template_lut<I: GrayFormat, F: Format>(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
let components: libc::c_uint = if F::kAIndex == 0xff { 3 } else { 4 } as libc::c_uint;
let input_gamma_table_gray = (*transform)
.input_gamma_table_gray
.as_ref()
.unwrap()
.as_ptr();
let mut i: libc::c_uint = 0;
while (i as usize) < length {
let fresh0 = src;
src = src.offset(1);
let mut device: libc::c_uchar = *fresh0;
let mut alpha: libc::c_uchar = 0xffu8;
if I::has_alpha {
let fresh1 = src;
src = src.offset(1);
alpha = *fresh1
}
let mut linear: f32 = *input_gamma_table_gray.offset(device as isize);
let mut out_device_r: f32 = lut_interp_linear(
linear as f64,
&(*transform).output_gamma_lut_r.as_ref().unwrap(),
);
let mut out_device_g: f32 = lut_interp_linear(
linear as f64,
&(*transform).output_gamma_lut_g.as_ref().unwrap(),
);
let mut out_device_b: f32 = lut_interp_linear(
linear as f64,
&(*transform).output_gamma_lut_b.as_ref().unwrap(),
);
*dest.offset(F::kRIndex as isize) = clamp_u8(out_device_r * 255f32);
*dest.offset(F::kGIndex as isize) = clamp_u8(out_device_g * 255f32);
*dest.offset(F::kBIndex as isize) = clamp_u8(out_device_b * 255f32);
if F::kAIndex != 0xff {
*dest.offset(F::kAIndex as isize) = alpha
}
dest = dest.offset(components as isize);
i = i + 1
}
}
unsafe extern "C" fn qcms_transform_data_gray_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_lut::<Gray, RGB>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_gray_rgba_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_lut::<Gray, RGBA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_gray_bgra_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_lut::<Gray, BGRA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_graya_rgba_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_lut::<GrayAlpha, RGBA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_graya_bgra_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_lut::<GrayAlpha, BGRA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_gray_template_precache<I: GrayFormat, F: Format>(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
let components: libc::c_uint = if F::kAIndex == 0xff { 3 } else { 4 } as libc::c_uint;
let output_table_r = ((*transform).output_table_r).as_deref().unwrap();
let output_table_g = ((*transform).output_table_g).as_deref().unwrap();
let output_table_b = ((*transform).output_table_b).as_deref().unwrap();
let input_gamma_table_gray = (*transform)
.input_gamma_table_gray
.as_ref()
.unwrap()
.as_ptr();
let mut i: libc::c_uint = 0;
while (i as usize) < length {
let fresh2 = src;
src = src.offset(1);
let mut device: libc::c_uchar = *fresh2;
let mut alpha: libc::c_uchar = 0xffu8;
if I::has_alpha {
let fresh3 = src;
src = src.offset(1);
alpha = *fresh3
}
let mut linear: f32 = *input_gamma_table_gray.offset(device as isize);
let mut gray: u16 = (linear * (8192 - 1) as f32) as u16;
*dest.offset(F::kRIndex as isize) = (output_table_r).data[gray as usize];
*dest.offset(F::kGIndex as isize) = (output_table_g).data[gray as usize];
*dest.offset(F::kBIndex as isize) = (output_table_b).data[gray as usize];
if F::kAIndex != 0xff {
*dest.offset(F::kAIndex as isize) = alpha
}
dest = dest.offset(components as isize);
i = i + 1
}
}
unsafe extern "C" fn qcms_transform_data_gray_out_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_precache::<Gray, RGB>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_gray_rgba_out_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_precache::<Gray, RGBA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_gray_bgra_out_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_precache::<Gray, BGRA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_graya_rgba_out_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_precache::<GrayAlpha, RGBA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_graya_bgra_out_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_gray_template_precache::<GrayAlpha, BGRA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_template_lut_precache<F: Format>(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
let components: libc::c_uint = if F::kAIndex == 0xff { 3 } else { 4 } as libc::c_uint;
let output_table_r = ((*transform).output_table_r).as_deref().unwrap();
let output_table_g = ((*transform).output_table_g).as_deref().unwrap();
let output_table_b = ((*transform).output_table_b).as_deref().unwrap();
let input_gamma_table_r = (*transform).input_gamma_table_r.as_ref().unwrap().as_ptr();
let input_gamma_table_g = (*transform).input_gamma_table_g.as_ref().unwrap().as_ptr();
let input_gamma_table_b = (*transform).input_gamma_table_b.as_ref().unwrap().as_ptr();
let mut mat: *const [f32; 4] = (*transform).matrix.as_ptr();
let mut i: libc::c_uint = 0;
while (i as usize) < length {
let mut device_r: libc::c_uchar = *src.offset(F::kRIndex as isize);
let mut device_g: libc::c_uchar = *src.offset(F::kGIndex as isize);
let mut device_b: libc::c_uchar = *src.offset(F::kBIndex as isize);
let mut alpha: libc::c_uchar = 0;
if F::kAIndex != 0xff {
alpha = *src.offset(F::kAIndex as isize)
}
src = src.offset(components as isize);
let mut linear_r: f32 = *input_gamma_table_r.offset(device_r as isize);
let mut linear_g: f32 = *input_gamma_table_g.offset(device_g as isize);
let mut linear_b: f32 = *input_gamma_table_b.offset(device_b as isize);
let mut out_linear_r: f32 = (*mat.offset(0isize))[0] * linear_r
+ (*mat.offset(1isize))[0] * linear_g
+ (*mat.offset(2isize))[0] * linear_b;
let mut out_linear_g: f32 = (*mat.offset(0isize))[1] * linear_r
+ (*mat.offset(1isize))[1] * linear_g
+ (*mat.offset(2isize))[1] * linear_b;
let mut out_linear_b: f32 = (*mat.offset(0isize))[2] * linear_r
+ (*mat.offset(1isize))[2] * linear_g
+ (*mat.offset(2isize))[2] * linear_b;
out_linear_r = clamp_float(out_linear_r);
out_linear_g = clamp_float(out_linear_g);
out_linear_b = clamp_float(out_linear_b);
let mut r: u16 = (out_linear_r * (8192 - 1) as f32) as u16;
let mut g: u16 = (out_linear_g * (8192 - 1) as f32) as u16;
let mut b: u16 = (out_linear_b * (8192 - 1) as f32) as u16;
*dest.offset(F::kRIndex as isize) = (output_table_r).data[r as usize];
*dest.offset(F::kGIndex as isize) = (output_table_g).data[g as usize];
*dest.offset(F::kBIndex as isize) = (output_table_b).data[b as usize];
if F::kAIndex != 0xff {
*dest.offset(F::kAIndex as isize) = alpha
}
dest = dest.offset(components as isize);
i = i + 1
}
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_data_rgb_out_lut_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_template_lut_precache::<RGB>(transform, src, dest, length);
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_data_rgba_out_lut_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_template_lut_precache::<RGBA>(transform, src, dest, length);
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_data_bgra_out_lut_precache(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_template_lut_precache::<BGRA>(transform, src, dest, length);
}
fn int_div_ceil(mut value: i32, mut div: i32) -> i32 {
return (value + div - 1) / div;
}
unsafe extern "C" fn qcms_transform_data_tetra_clut_template<F: Format>(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
let components: libc::c_uint = if F::kAIndex == 0xff { 3 } else { 4 } as libc::c_uint;
let mut xy_len: i32 = 1;
let mut x_len: i32 = (*transform).grid_size as i32;
let mut len: i32 = x_len * x_len;
let mut r_table: *mut f32 = (*transform).r_clut;
let mut g_table: *mut f32 = (*transform).g_clut;
let mut b_table: *mut f32 = (*transform).b_clut;
let mut c0_r: f32;
let mut c1_r: f32;
let mut c2_r: f32;
let mut c3_r: f32;
let mut c0_g: f32;
let mut c1_g: f32;
let mut c2_g: f32;
let mut c3_g: f32;
let mut c0_b: f32;
let mut c1_b: f32;
let mut c2_b: f32;
let mut c3_b: f32;
let mut clut_r: f32;
let mut clut_g: f32;
let mut clut_b: f32;
let mut i: libc::c_uint = 0;
while (i as usize) < length {
let mut in_r: libc::c_uchar = *src.offset(F::kRIndex as isize);
let mut in_g: libc::c_uchar = *src.offset(F::kGIndex as isize);
let mut in_b: libc::c_uchar = *src.offset(F::kBIndex as isize);
let mut in_a: libc::c_uchar = 0;
if F::kAIndex != 0xff {
in_a = *src.offset(F::kAIndex as isize)
}
src = src.offset(components as isize);
let mut linear_r: f32 = in_r as i32 as f32 / 255.0;
let mut linear_g: f32 = in_g as i32 as f32 / 255.0;
let mut linear_b: f32 = in_b as i32 as f32 / 255.0;
let mut x: i32 = in_r as i32 * ((*transform).grid_size as i32 - 1) / 255;
let mut y: i32 = in_g as i32 * ((*transform).grid_size as i32 - 1) / 255;
let mut z: i32 = in_b as i32 * ((*transform).grid_size as i32 - 1) / 255;
let mut x_n: i32 = int_div_ceil(in_r as i32 * ((*transform).grid_size as i32 - 1), 255);
let mut y_n: i32 = int_div_ceil(in_g as i32 * ((*transform).grid_size as i32 - 1), 255);
let mut z_n: i32 = int_div_ceil(in_b as i32 * ((*transform).grid_size as i32 - 1), 255);
let mut rx: f32 = linear_r * ((*transform).grid_size as i32 - 1) as f32 - x as f32;
let mut ry: f32 = linear_g * ((*transform).grid_size as i32 - 1) as f32 - y as f32;
let mut rz: f32 = linear_b * ((*transform).grid_size as i32 - 1) as f32 - z as f32;
c0_r = *r_table.offset(((x * len + y * x_len + z * xy_len) * 3) as isize);
c0_g = *g_table.offset(((x * len + y * x_len + z * xy_len) * 3) as isize);
c0_b = *b_table.offset(((x * len + y * x_len + z * xy_len) * 3) as isize);
if rx >= ry {
if ry >= rz {
c1_r = *r_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize) - c0_r; c2_r = *r_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
- *r_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize);
c3_r = *r_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize);
c1_g = *g_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize) - c0_g;
c2_g = *g_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
- *g_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize);
c3_g = *g_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize);
c1_b = *b_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize) - c0_b;
c2_b = *b_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
- *b_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize);
c3_b = *b_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
} else if rx >= rz {
c1_r = *r_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize) - c0_r;
c2_r = *r_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_r = *r_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize);
c1_g = *g_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize) - c0_g;
c2_g = *g_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_g = *g_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize);
c1_b = *b_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize) - c0_b;
c2_b = *b_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_b = *b_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x_n * len + y * x_len + z * xy_len) * 3) as isize)
} else {
c1_r = *r_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize);
c2_r = *r_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_r = *r_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize) - c0_r;
c1_g = *g_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize);
c2_g = *g_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_g = *g_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize) - c0_g;
c1_b = *b_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize);
c2_b = *b_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x_n * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_b = *b_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize) - c0_b
}
} else if rx >= rz {
c1_r = *r_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
- *r_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize); c2_r = *r_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize) - c0_r;
c3_r = *r_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize);
c1_g = *g_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
- *g_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize);
c2_g = *g_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize) - c0_g;
c3_g = *g_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize);
c1_b = *b_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
- *b_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize);
c2_b = *b_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize) - c0_b;
c3_b = *b_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x_n * len + y_n * x_len + z * xy_len) * 3) as isize)
} else if ry >= rz {
c1_r = *r_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize);
c2_r = *r_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize) - c0_r;
c3_r = *r_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize);
c1_g = *g_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize);
c2_g = *g_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize) - c0_g;
c3_g = *g_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize);
c1_b = *b_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize);
c2_b = *b_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize) - c0_b;
c3_b = *b_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x * len + y_n * x_len + z * xy_len) * 3) as isize)
} else {
c1_r = *r_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize);
c2_r = *r_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *r_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_r = *r_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize) - c0_r;
c1_g = *g_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize);
c2_g = *g_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *g_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_g = *g_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize) - c0_g;
c1_b = *b_table.offset(((x_n * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize);
c2_b = *b_table.offset(((x * len + y_n * x_len + z_n * xy_len) * 3) as isize)
- *b_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize);
c3_b = *b_table.offset(((x * len + y * x_len + z_n * xy_len) * 3) as isize) - c0_b
}
clut_r = c0_r + c1_r * rx + c2_r * ry + c3_r * rz;
clut_g = c0_g + c1_g * rx + c2_g * ry + c3_g * rz;
clut_b = c0_b + c1_b * rx + c2_b * ry + c3_b * rz;
*dest.offset(F::kRIndex as isize) = clamp_u8(clut_r * 255.0);
*dest.offset(F::kGIndex as isize) = clamp_u8(clut_g * 255.0);
*dest.offset(F::kBIndex as isize) = clamp_u8(clut_b * 255.0);
if F::kAIndex != 0xff {
*dest.offset(F::kAIndex as isize) = in_a
}
dest = dest.offset(components as isize);
i = i + 1
}
}
unsafe extern "C" fn qcms_transform_data_tetra_clut_rgb(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_tetra_clut_template::<RGB>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_tetra_clut_rgba(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_tetra_clut_template::<RGBA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_tetra_clut_bgra(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_tetra_clut_template::<BGRA>(transform, src, dest, length);
}
unsafe extern "C" fn qcms_transform_data_template_lut<F: Format>(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
let components: libc::c_uint = if F::kAIndex == 0xff { 3 } else { 4 } as libc::c_uint;
let mut mat: *const [f32; 4] = (*transform).matrix.as_ptr();
let mut i: libc::c_uint = 0;
let input_gamma_table_r = (*transform).input_gamma_table_r.as_ref().unwrap().as_ptr();
let input_gamma_table_g = (*transform).input_gamma_table_g.as_ref().unwrap().as_ptr();
let input_gamma_table_b = (*transform).input_gamma_table_b.as_ref().unwrap().as_ptr();
while (i as usize) < length {
let mut device_r: libc::c_uchar = *src.offset(F::kRIndex as isize);
let mut device_g: libc::c_uchar = *src.offset(F::kGIndex as isize);
let mut device_b: libc::c_uchar = *src.offset(F::kBIndex as isize);
let mut alpha: libc::c_uchar = 0;
if F::kAIndex != 0xff {
alpha = *src.offset(F::kAIndex as isize)
}
src = src.offset(components as isize);
let mut linear_r: f32 = *input_gamma_table_r.offset(device_r as isize);
let mut linear_g: f32 = *input_gamma_table_g.offset(device_g as isize);
let mut linear_b: f32 = *input_gamma_table_b.offset(device_b as isize);
let mut out_linear_r: f32 = (*mat.offset(0isize))[0] * linear_r
+ (*mat.offset(1isize))[0] * linear_g
+ (*mat.offset(2isize))[0] * linear_b;
let mut out_linear_g: f32 = (*mat.offset(0isize))[1] * linear_r
+ (*mat.offset(1isize))[1] * linear_g
+ (*mat.offset(2isize))[1] * linear_b;
let mut out_linear_b: f32 = (*mat.offset(0isize))[2] * linear_r
+ (*mat.offset(1isize))[2] * linear_g
+ (*mat.offset(2isize))[2] * linear_b;
out_linear_r = clamp_float(out_linear_r);
out_linear_g = clamp_float(out_linear_g);
out_linear_b = clamp_float(out_linear_b);
let mut out_device_r: f32 = lut_interp_linear(
out_linear_r as f64,
&(*transform).output_gamma_lut_r.as_ref().unwrap(),
);
let mut out_device_g: f32 = lut_interp_linear(
out_linear_g as f64,
(*transform).output_gamma_lut_g.as_ref().unwrap(),
);
let mut out_device_b: f32 = lut_interp_linear(
out_linear_b as f64,
(*transform).output_gamma_lut_b.as_ref().unwrap(),
);
*dest.offset(F::kRIndex as isize) = clamp_u8(out_device_r * 255f32);
*dest.offset(F::kGIndex as isize) = clamp_u8(out_device_g * 255f32);
*dest.offset(F::kBIndex as isize) = clamp_u8(out_device_b * 255f32);
if F::kAIndex != 0xff {
*dest.offset(F::kAIndex as isize) = alpha
}
dest = dest.offset(components as isize);
i = i + 1
}
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_data_rgb_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_template_lut::<RGB>(transform, src, dest, length);
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_data_rgba_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_template_lut::<RGBA>(transform, src, dest, length);
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_data_bgra_out_lut(
mut transform: *const qcms_transform,
mut src: *const libc::c_uchar,
mut dest: *mut libc::c_uchar,
mut length: usize,
) {
qcms_transform_data_template_lut::<BGRA>(transform, src, dest, length);
}
fn precache_create() -> Arc<precache_output> {
Arc::new(precache_output::default())
}
unsafe extern "C" fn transform_alloc() -> *mut qcms_transform {
Box::into_raw(Box::new(Default::default()))
}
unsafe extern "C" fn transform_free(mut t: *mut qcms_transform) {
drop(Box::from_raw(t))
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_release(mut t: *mut qcms_transform) {
(*t).output_table_r = None;
(*t).output_table_g = None;
(*t).output_table_b = None;
(*t).input_gamma_table_r = None;
(*t).input_gamma_table_g = None;
(*t).input_gamma_table_b = None;
(*t).input_gamma_table_gray = None;
(*t).output_gamma_lut_r = None;
(*t).output_gamma_lut_g = None;
(*t).output_gamma_lut_b = None;
if !(*t).r_clut.is_null() {
free((*t).r_clut as *mut libc::c_void);
}
transform_free(t);
}
fn sse_version_available() -> i32 {
return 2;
}
const bradford_matrix: matrix = matrix {
m: [
[0.8951, 0.2664, -0.1614],
[-0.7502, 1.7135, 0.0367],
[0.0389, -0.0685, 1.0296],
],
invalid: false,
};
const bradford_matrix_inv: matrix = matrix {
m: [
[0.9869929, -0.1470543, 0.1599627],
[0.4323053, 0.5183603, 0.0492912],
[-0.0085287, 0.0400428, 0.9684867],
],
invalid: false,
};
fn compute_whitepoint_adaption(mut X: f32, mut Y: f32, mut Z: f32) -> matrix {
let mut p: f32 = (0.96422 * bradford_matrix.m[0][0]
+ 1.000 * bradford_matrix.m[1][0]
+ 0.82521 * bradford_matrix.m[2][0])
/ (X * bradford_matrix.m[0][0] + Y * bradford_matrix.m[1][0] + Z * bradford_matrix.m[2][0]);
let mut y: f32 = (0.96422 * bradford_matrix.m[0][1]
+ 1.000 * bradford_matrix.m[1][1]
+ 0.82521 * bradford_matrix.m[2][1])
/ (X * bradford_matrix.m[0][1] + Y * bradford_matrix.m[1][1] + Z * bradford_matrix.m[2][1]);
let mut b: f32 = (0.96422 * bradford_matrix.m[0][2]
+ 1.000 * bradford_matrix.m[1][2]
+ 0.82521 * bradford_matrix.m[2][2])
/ (X * bradford_matrix.m[0][2] + Y * bradford_matrix.m[1][2] + Z * bradford_matrix.m[2][2]);
let mut white_adaption: matrix = {
let mut init = matrix {
m: [[p, 0., 0.], [0., y, 0.], [0., 0., b]],
invalid: false,
};
init
};
return matrix_multiply(
bradford_matrix_inv,
matrix_multiply(white_adaption, bradford_matrix),
);
}
#[no_mangle]
pub unsafe extern "C" fn qcms_profile_precache_output_transform(mut profile: *mut qcms_profile) {
if (*profile).color_space != 0x52474220 {
return;
}
if qcms_supports_iccv4.load(Ordering::Relaxed) {
if !(*profile).B2A0.is_none() {
return;
}
if !(*profile).mBA.is_none() {
return;
}
}
if (*profile).redTRC.is_none() || (*profile).greenTRC.is_none() || (*profile).blueTRC.is_none()
{
return;
}
if (*profile).output_table_r.is_none() {
let mut output_table_r = precache_create();
if compute_precache(
(*profile).redTRC.as_deref().unwrap(),
Arc::get_mut(&mut output_table_r).unwrap().data.as_mut_ptr(),
) {
(*profile).output_table_r = Some(output_table_r);
}
}
if (*profile).output_table_g.is_none() {
let mut output_table_g = precache_create();
if compute_precache(
(*profile).greenTRC.as_deref().unwrap(),
Arc::get_mut(&mut output_table_g).unwrap().data.as_mut_ptr(),
) {
(*profile).output_table_g = Some(output_table_g);
}
}
if (*profile).output_table_b.is_none() {
let mut output_table_b = precache_create();
if compute_precache(
(*profile).blueTRC.as_deref().unwrap(),
Arc::get_mut(&mut output_table_b).unwrap().data.as_mut_ptr(),
) {
(*profile).output_table_b = Some(output_table_b);
}
};
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_precacheLUT_float(
mut transform: *mut qcms_transform,
mut in_0: &qcms_profile,
mut out: &qcms_profile,
mut samples: i32,
mut in_type: qcms_data_type,
) -> *mut qcms_transform {
let mut x: u16;
let mut y: u16;
let mut z: u16;
let mut l: u32;
let mut lutSize: u32 = (3 * samples * samples * samples) as u32;
let mut lut: *mut f32 = 0 as *mut f32;
let mut src: *mut f32 = malloc(lutSize as usize * ::std::mem::size_of::<f32>()) as *mut f32;
let mut dest: *mut f32 = malloc(lutSize as usize * ::std::mem::size_of::<f32>()) as *mut f32;
if !src.is_null() && !dest.is_null() {
l = 0;
x = 0u16;
while (x as i32) < samples {
y = 0u16;
while (y as i32) < samples {
z = 0u16;
while (z as i32) < samples {
let fresh8 = l;
l = l + 1;
*src.offset(fresh8 as isize) = x as i32 as f32 / (samples - 1) as f32;
let fresh9 = l;
l = l + 1;
*src.offset(fresh9 as isize) = y as i32 as f32 / (samples - 1) as f32;
let fresh10 = l;
l = l + 1;
*src.offset(fresh10 as isize) = z as i32 as f32 / (samples - 1) as f32;
z = z + 1
}
y = y + 1
}
x = x + 1
}
lut = qcms_chain_transform(in_0, out, src, dest, lutSize as usize);
if !lut.is_null() {
(*transform).r_clut = &mut *lut.offset(0isize) as *mut f32;
(*transform).g_clut = &mut *lut.offset(1isize) as *mut f32;
(*transform).b_clut = &mut *lut.offset(2isize) as *mut f32;
(*transform).grid_size = samples as u16;
if in_type == QCMS_DATA_RGBA_8 {
(*transform).transform_fn = Some(qcms_transform_data_tetra_clut_rgba)
} else if in_type == QCMS_DATA_BGRA_8 {
(*transform).transform_fn = Some(qcms_transform_data_tetra_clut_bgra)
} else if in_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_tetra_clut_rgb)
}
debug_assert!((*transform).transform_fn.is_some());
}
}
if !src.is_null() && lut != src {
free(src as *mut libc::c_void);
}
if !dest.is_null() && lut != dest {
free(dest as *mut libc::c_void);
}
if lut.is_null() {
return 0 as *mut qcms_transform;
}
return transform;
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_create(
mut in_0: &qcms_profile,
mut in_type: qcms_data_type,
mut out: &qcms_profile,
mut out_type: qcms_data_type,
mut intent: qcms_intent,
) -> *mut qcms_transform {
let mut match_0: bool = false;
if in_type == QCMS_DATA_RGB_8 {
match_0 = out_type == QCMS_DATA_RGB_8
} else if in_type == QCMS_DATA_RGBA_8 {
match_0 = out_type == QCMS_DATA_RGBA_8
} else if in_type == QCMS_DATA_BGRA_8 {
match_0 = out_type == QCMS_DATA_BGRA_8
} else if in_type == QCMS_DATA_GRAY_8 {
match_0 = out_type == QCMS_DATA_RGB_8
|| out_type == QCMS_DATA_RGBA_8
|| out_type == QCMS_DATA_BGRA_8
} else if in_type == QCMS_DATA_GRAYA_8 {
match_0 = out_type == QCMS_DATA_RGBA_8 || out_type == QCMS_DATA_BGRA_8
}
if !match_0 {
debug_assert!(false, "input/output type");
return 0 as *mut qcms_transform;
}
let mut transform: *mut qcms_transform = transform_alloc();
if transform.is_null() {
return 0 as *mut qcms_transform;
}
let mut precache: bool = false;
if !(*out).output_table_r.is_none()
&& !(*out).output_table_g.is_none()
&& !(*out).output_table_b.is_none()
{
precache = true
}
if qcms_supports_iccv4.load(Ordering::Relaxed) as i32 != 0
&& (in_type == QCMS_DATA_RGB_8
|| in_type == QCMS_DATA_RGBA_8
|| in_type == QCMS_DATA_BGRA_8)
&& (!(*in_0).A2B0.is_none()
|| !(*out).B2A0.is_none()
|| !(*in_0).mAB.is_none()
|| !(*out).mAB.is_none())
{
let mut result: *mut qcms_transform =
qcms_transform_precacheLUT_float(transform, in_0, out, 33, in_type);
if result.is_null() {
debug_assert!(false, "precacheLUT failed");
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
return result;
}
if precache {
(*transform).output_table_r = Some(Arc::clone((*out).output_table_r.as_ref().unwrap()));
(*transform).output_table_g = Some(Arc::clone((*out).output_table_g.as_ref().unwrap()));
(*transform).output_table_b = Some(Arc::clone((*out).output_table_b.as_ref().unwrap()));
} else {
if (*out).redTRC.is_none() || (*out).greenTRC.is_none() || (*out).blueTRC.is_none() {
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
(*transform).output_gamma_lut_r = Some(build_output_lut((*out).redTRC.as_deref().unwrap()));
(*transform).output_gamma_lut_g =
Some(build_output_lut((*out).greenTRC.as_deref().unwrap()));
(*transform).output_gamma_lut_b =
Some(build_output_lut((*out).blueTRC.as_deref().unwrap()));
if (*transform).output_gamma_lut_r.is_none()
|| (*transform).output_gamma_lut_g.is_none()
|| (*transform).output_gamma_lut_b.is_none()
{
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
}
if (*in_0).color_space == 0x52474220 {
if precache {
if cfg!(any(target_arch = "x86", target_arch = "x86_64")) && qcms_supports_avx {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
if in_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgb_out_lut_avx)
} else if in_type == QCMS_DATA_RGBA_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgba_out_lut_avx)
} else if in_type == QCMS_DATA_BGRA_8 {
(*transform).transform_fn = Some(qcms_transform_data_bgra_out_lut_avx)
}
}
} else if cfg!(all(
any(target_arch = "x86", target_arch = "x86_64"),
not(miri)
)) && sse_version_available() >= 2
{
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
if in_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgb_out_lut_sse2)
} else if in_type == QCMS_DATA_RGBA_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgba_out_lut_sse2)
} else if in_type == QCMS_DATA_BGRA_8 {
(*transform).transform_fn = Some(qcms_transform_data_bgra_out_lut_sse2)
}
}
} else if cfg!(any(target_arch = "arm", target_arch = "aarch64")) && qcms_supports_neon
{
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
{
if in_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgb_out_lut_neon)
} else if in_type == QCMS_DATA_RGBA_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgba_out_lut_neon)
} else if in_type == QCMS_DATA_BGRA_8 {
(*transform).transform_fn = Some(qcms_transform_data_bgra_out_lut_neon)
}
}
} else if in_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgb_out_lut_precache)
} else if in_type == QCMS_DATA_RGBA_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgba_out_lut_precache)
} else if in_type == QCMS_DATA_BGRA_8 {
(*transform).transform_fn = Some(qcms_transform_data_bgra_out_lut_precache)
}
} else if in_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgb_out_lut)
} else if in_type == QCMS_DATA_RGBA_8 {
(*transform).transform_fn = Some(qcms_transform_data_rgba_out_lut)
} else if in_type == QCMS_DATA_BGRA_8 {
(*transform).transform_fn = Some(qcms_transform_data_bgra_out_lut)
}
(*transform).input_gamma_table_r = build_input_gamma_table((*in_0).redTRC.as_deref());
(*transform).input_gamma_table_g = build_input_gamma_table((*in_0).greenTRC.as_deref());
(*transform).input_gamma_table_b = build_input_gamma_table((*in_0).blueTRC.as_deref());
if (*transform).input_gamma_table_r.is_none()
|| (*transform).input_gamma_table_g.is_none()
|| (*transform).input_gamma_table_b.is_none()
{
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
let mut in_matrix: matrix = build_colorant_matrix(in_0);
let mut out_matrix: matrix = build_colorant_matrix(out);
out_matrix = matrix_invert(out_matrix);
if out_matrix.invalid {
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
let mut result_0: matrix = matrix_multiply(out_matrix, in_matrix);
let mut i: libc::c_uint = 0;
while i < 3 {
let mut j: libc::c_uint = 0;
while j < 3 {
if result_0.m[i as usize][j as usize] != result_0.m[i as usize][j as usize] {
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
j = j + 1
}
i = i + 1
}
(*transform).matrix[0][0] = result_0.m[0][0];
(*transform).matrix[1][0] = result_0.m[0][1];
(*transform).matrix[2][0] = result_0.m[0][2];
(*transform).matrix[0][1] = result_0.m[1][0];
(*transform).matrix[1][1] = result_0.m[1][1];
(*transform).matrix[2][1] = result_0.m[1][2];
(*transform).matrix[0][2] = result_0.m[2][0];
(*transform).matrix[1][2] = result_0.m[2][1];
(*transform).matrix[2][2] = result_0.m[2][2]
} else if (*in_0).color_space == 0x47524159 {
(*transform).input_gamma_table_gray = build_input_gamma_table((*in_0).grayTRC.as_deref());
if (*transform).input_gamma_table_gray.is_none() {
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
if precache {
if out_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_gray_out_precache)
} else if out_type == QCMS_DATA_RGBA_8 {
if in_type == QCMS_DATA_GRAY_8 {
(*transform).transform_fn = Some(qcms_transform_data_gray_rgba_out_precache)
} else {
(*transform).transform_fn = Some(qcms_transform_data_graya_rgba_out_precache)
}
} else if out_type == QCMS_DATA_BGRA_8 {
if in_type == QCMS_DATA_GRAY_8 {
(*transform).transform_fn = Some(qcms_transform_data_gray_bgra_out_precache)
} else {
(*transform).transform_fn = Some(qcms_transform_data_graya_bgra_out_precache)
}
}
} else if out_type == QCMS_DATA_RGB_8 {
(*transform).transform_fn = Some(qcms_transform_data_gray_out_lut)
} else if out_type == QCMS_DATA_RGBA_8 {
if in_type == QCMS_DATA_GRAY_8 {
(*transform).transform_fn = Some(qcms_transform_data_gray_rgba_out_lut)
} else {
(*transform).transform_fn = Some(qcms_transform_data_graya_rgba_out_lut)
}
} else if out_type == QCMS_DATA_BGRA_8 {
if in_type == QCMS_DATA_GRAY_8 {
(*transform).transform_fn = Some(qcms_transform_data_gray_bgra_out_lut)
} else {
(*transform).transform_fn = Some(qcms_transform_data_graya_bgra_out_lut)
}
}
} else {
debug_assert!(false, "unexpected colorspace");
qcms_transform_release(transform);
return 0 as *mut qcms_transform;
}
debug_assert!((*transform).transform_fn.is_some());
return transform;
}
#[no_mangle]
pub unsafe extern "C" fn qcms_transform_data(
mut transform: *mut qcms_transform,
mut src: *const libc::c_void,
mut dest: *mut libc::c_void,
mut length: usize,
) {
(*transform)
.transform_fn
.expect("non-null function pointer")(
transform,
src as *const libc::c_uchar,
dest as *mut libc::c_uchar,
length,
);
}
#[no_mangle]
pub unsafe extern "C" fn qcms_enable_iccv4() {
qcms_supports_iccv4.store(true, Ordering::Relaxed);
}
#[no_mangle]
pub static mut qcms_supports_avx: bool = false;
#[no_mangle]
pub static mut qcms_supports_neon: bool = false;
#[no_mangle]
pub unsafe extern "C" fn qcms_enable_avx() {
qcms_supports_avx = true;
}
#[no_mangle]
pub unsafe extern "C" fn qcms_enable_neon() {
qcms_supports_neon = true;
}