Skip to content

Commit

Permalink
XYZ with alpha, unaligned memory fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
awxkee committed Jun 15, 2024
1 parent 95d0c5a commit 2e7364a
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 54 deletions.
10 changes: 5 additions & 5 deletions src/hsv_to_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ fn hsv_u16_to_channels<
let src_ptr = unsafe { (src.as_ptr() as *const u8).add(src_offset) as *const u16 };
let dst_ptr = unsafe { dst.as_mut_ptr().add(dst_offset) };

let src_slice = unsafe { slice::from_raw_parts(src_ptr, width as usize * channels) };
let dst_slice = unsafe { slice::from_raw_parts_mut(dst_ptr, width as usize * channels) };

for x in _cx..width as usize {
let px = x * channels;
let h = unsafe { *src_slice.get_unchecked(px) };
let s = unsafe { *src_slice.get_unchecked(px + 1) };
let v = unsafe { *src_slice.get_unchecked(px + 2) };
let src = unsafe { src_ptr.add(px) };
let h = unsafe { src.read_unaligned() };
let s = unsafe { src.add(1).read_unaligned() };
let v = unsafe { src.add(2).read_unaligned() };

let s_f = s as f32 * scale;
let v_f = v as f32 * scale;
Expand Down Expand Up @@ -133,7 +133,7 @@ fn hsv_u16_to_channels<
}

if image_configuration.has_alpha() {
let a = unsafe { *src_slice.get_unchecked(hx + 3) };
let a = unsafe { src.add(3).read_unaligned() };
unsafe {
*dst_slice.get_unchecked_mut(hx + image_configuration.get_a_channel_offset()) =
a as u8;
Expand Down
16 changes: 8 additions & 8 deletions src/image_to_hsv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ fn channels_to_hsv_u16<
let dst_ptr = unsafe { (dst.as_mut_ptr() as *mut u8).add(dst_offset) as *mut u16 };

let src_slice = unsafe { slice::from_raw_parts(src_ptr, width as usize * channels) };
let dst_slice = unsafe { slice::from_raw_parts_mut(dst_ptr, width as usize * channels) };

for x in cx..width as usize {
let px = x * channels;
Expand All @@ -113,21 +112,22 @@ fn channels_to_hsv_u16<

let rgb = Rgb::<u8>::new(r, g, b);
let hx = x * channels;
let dst = unsafe { dst_ptr.add(hx) };
match target {
HsvTarget::HSV => {
let hsv = rgb.to_hsv();
unsafe {
*dst_slice.get_unchecked_mut(hx) = hsv.h as u16;
*dst_slice.get_unchecked_mut(hx + 1) = (hsv.s * scale).round() as u16;
*dst_slice.get_unchecked_mut(hx + 2) = (hsv.v * scale).round() as u16;
dst.write_unaligned(hsv.h as u16);
dst.add(1).write_unaligned((hsv.s * scale).round() as u16);
dst.add(2).write_unaligned((hsv.v * scale).round() as u16);
}
}
HsvTarget::HSL => {
let hsl = rgb.to_hsl();
unsafe {
*dst_slice.get_unchecked_mut(hx) = hsl.h as u16;
*dst_slice.get_unchecked_mut(hx + 1) = (hsl.s * scale).round() as u16;
*dst_slice.get_unchecked_mut(hx + 2) = (hsl.l * scale).round() as u16;
dst.write_unaligned(hsl.h as u16);
dst.add(1).write_unaligned((hsl.s * scale).round() as u16);
dst.add(2).write_unaligned((hsl.l * scale).round() as u16);
}
}
}
Expand All @@ -137,7 +137,7 @@ fn channels_to_hsv_u16<
*src_slice.get_unchecked(hx + image_configuration.get_a_channel_offset())
};
unsafe {
*dst_slice.get_unchecked_mut(hx + 3) = a as u16;
dst.add(3).write_unaligned(a as u16);
}
}
}
Expand Down
25 changes: 13 additions & 12 deletions src/image_to_xyz_lab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ fn channels_to_xyz<const CHANNELS_CONFIGURATION: u8, const USE_ALPHA: bool, cons
let dst_ptr = unsafe { (dst.as_mut_ptr() as *mut u8).add(dst_offset) as *mut f32 };

let src_slice = unsafe { slice::from_raw_parts(src_ptr, width as usize * channels) };
let dst_slice = unsafe { slice::from_raw_parts_mut(dst_ptr, width as usize * 3) };

for x in cx..width as usize {
let px = x * channels;
Expand All @@ -225,25 +224,28 @@ fn channels_to_xyz<const CHANNELS_CONFIGURATION: u8, const USE_ALPHA: bool, cons
LAB => {
let lab = rgb.to_lab();
unsafe {
*dst_slice.get_unchecked_mut(x * 3) = lab.l;
*dst_slice.get_unchecked_mut(x * 3 + 1) = lab.a;
*dst_slice.get_unchecked_mut(x * 3 + 2) = lab.b;
let ptr = dst_ptr.add(x * 3);
ptr.write_unaligned(lab.l);
ptr.add(1).write_unaligned(lab.a);
ptr.add(2).write_unaligned(lab.b);
}
}
XYZ => {
let xyz = Xyz::from_rgb(&rgb, &matrix, transfer_function);
unsafe {
*dst_slice.get_unchecked_mut(x * 3) = xyz.x;
*dst_slice.get_unchecked_mut(x * 3 + 1) = xyz.y;
*dst_slice.get_unchecked_mut(x * 3 + 2) = xyz.z;
let ptr = dst_ptr.add(x * 3);
ptr.write_unaligned(xyz.x);
ptr.add(1).write_unaligned(xyz.y);
ptr.add(2).write_unaligned(xyz.z);
}
}
XyzTarget::LUV => {
let luv = rgb.to_luv();
unsafe {
*dst_slice.get_unchecked_mut(x * 3) = luv.l;
*dst_slice.get_unchecked_mut(x * 3 + 1) = luv.u;
*dst_slice.get_unchecked_mut(x * 3 + 2) = luv.v;
let ptr = dst_ptr.add(x * 3);
ptr.write_unaligned(luv.l);
ptr.add(1).write_unaligned(luv.u);
ptr.add(2).write_unaligned(luv.v);
}
}
}
Expand All @@ -255,9 +257,8 @@ fn channels_to_xyz<const CHANNELS_CONFIGURATION: u8, const USE_ALPHA: bool, cons
let a_lin = a as f32 * (1f32 / 255f32);
let a_ptr =
unsafe { (a_channel.as_mut_ptr() as *mut u8).add(a_offset) as *mut f32 };
let a_slice = unsafe { slice::from_raw_parts_mut(a_ptr, width as usize) };
unsafe {
*a_slice.get_unchecked_mut(x) = a_lin;
a_ptr.add(x).write_unaligned(a_lin);
}
}
}
Expand Down
23 changes: 11 additions & 12 deletions src/image_xyza_laba.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ fn channels_to_xyz_with_alpha<const CHANNELS_CONFIGURATION: u8, const TARGET: u8
let dst_ptr = unsafe { (dst.as_mut_ptr() as *mut u8).add(dst_offset) as *mut f32 };

let src_slice = unsafe { slice::from_raw_parts(src_ptr, width as usize * channels) };
let dst_slice = unsafe { slice::from_raw_parts_mut(dst_ptr, width as usize * 4) };

for x in cx..width as usize {
let px = x * channels;
Expand All @@ -114,29 +113,30 @@ fn channels_to_xyz_with_alpha<const CHANNELS_CONFIGURATION: u8, const TARGET: u8

let rgb = Rgb::<u8>::new(r, g, b);
let px = x * CHANNELS;
let dst_store = unsafe { dst_ptr.add(px) };
match target {
LAB => {
let lab = rgb.to_lab();
unsafe {
*dst_slice.get_unchecked_mut(px) = lab.l;
*dst_slice.get_unchecked_mut(px + 1) = lab.a;
*dst_slice.get_unchecked_mut(px + 2) = lab.b;
dst_store.write_unaligned(lab.l);
dst_store.add(1).write_unaligned(lab.a);
dst_store.add(2).write_unaligned(lab.b);
}
}
XYZ => {
let xyz = Xyz::from_rgb(&rgb, &matrix, transfer_function);
unsafe {
*dst_slice.get_unchecked_mut(px) = xyz.x;
*dst_slice.get_unchecked_mut(px + 1) = xyz.y;
*dst_slice.get_unchecked_mut(px + 2) = xyz.z;
dst_store.write_unaligned(xyz.x);
dst_store.add(1).write_unaligned(xyz.y);
dst_store.add(2).write_unaligned(xyz.z);
}
}
XyzTarget::LUV => {
let luv = rgb.to_luv();
unsafe {
*dst_slice.get_unchecked_mut(px) = luv.l;
*dst_slice.get_unchecked_mut(px + 1) = luv.u;
*dst_slice.get_unchecked_mut(px + 2) = luv.v;
dst_store.write_unaligned(luv.l);
dst_store.add(1).write_unaligned(luv.u);
dst_store.add(2).write_unaligned(luv.v);
}
}
}
Expand All @@ -146,7 +146,7 @@ fn channels_to_xyz_with_alpha<const CHANNELS_CONFIGURATION: u8, const TARGET: u8
};
let a_lin = a as f32 * (1f32 / 255f32);
unsafe {
*dst_slice.get_unchecked_mut(x * CHANNELS + 3) = a_lin;
dst_store.add(3).write_unaligned(a_lin);
}
}

Expand Down Expand Up @@ -273,7 +273,6 @@ pub fn bgra_to_luv_with_alpha(
);
}


/// This function converts RGBA to CIE XYZ against D65 white point and preserving and normalizing alpha channels keeping it at last positions. This is much more effective than naive direct transformation
///
/// # Arguments
Expand Down
33 changes: 22 additions & 11 deletions src/xyz_lab_to_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,13 @@ fn xyz_to_channels<const CHANNELS_CONFIGURATION: u8, const USE_ALPHA: bool, cons
let src_ptr = unsafe { (src.as_ptr() as *const u8).add(src_offset) as *mut f32 };
let dst_ptr = unsafe { dst.as_mut_ptr().add(dst_offset) };

let src_slice = unsafe { slice::from_raw_parts(src_ptr, width as usize * channels) };
let dst_slice = unsafe { slice::from_raw_parts_mut(dst_ptr, width as usize * channels) };

for x in cx..width as usize {
let l_x = src_slice[x * 3];
let l_y = src_slice[x * 3 + 1];
let l_z = src_slice[x * 3 + 2];
let src_slice = unsafe { src_ptr.add(x * 3) };
let l_x = unsafe { src_slice.read_unaligned() };
let l_y = unsafe { src_slice.add(1).read_unaligned() };
let l_z = unsafe { src_slice.add(2).read_unaligned() };
let rgb;
match source {
LAB => {
Expand All @@ -211,16 +211,27 @@ fn xyz_to_channels<const CHANNELS_CONFIGURATION: u8, const USE_ALPHA: bool, cons
}
}

dst_slice[x * channels + image_configuration.get_r_channel_offset()] = rgb.r;
dst_slice[x * channels + image_configuration.get_g_channel_offset()] = rgb.g;
dst_slice[x * channels + image_configuration.get_b_channel_offset()] = rgb.b;
unsafe {
*dst_slice
.get_unchecked_mut(x * channels + image_configuration.get_r_channel_offset()) =
rgb.r;
*dst_slice
.get_unchecked_mut(x * channels + image_configuration.get_g_channel_offset()) =
rgb.g;
*dst_slice
.get_unchecked_mut(x * channels + image_configuration.get_b_channel_offset()) =
rgb.b;
}
if image_configuration.has_alpha() {
let a_ptr =
unsafe { (a_channel.as_ptr() as *const u8).add(a_offset) as *const f32 };
let a_slice = unsafe { slice::from_raw_parts(a_ptr, width as usize) };
let a_value = ((a_slice[x]) * 255f32).max(0f32);
dst_slice[x * channels + image_configuration.get_a_channel_offset()] =
a_value as u8;
let a_f = unsafe { a_ptr.add(x).read_unaligned() };
let a_value = (a_f * 255f32).max(0f32);
unsafe {
*dst_slice.get_unchecked_mut(
x * channels + image_configuration.get_a_channel_offset(),
) = a_value as u8;
}
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/xyza_laba_to_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,13 @@ fn xyz_with_alpha_to_channels<const CHANNELS_CONFIGURATION: u8, const TARGET: u8
let src_ptr = unsafe { (src.as_ptr() as *const u8).add(src_offset) as *mut f32 };
let dst_ptr = unsafe { dst.as_mut_ptr().add(dst_offset) };

let src_slice = unsafe { slice::from_raw_parts(src_ptr, width as usize * channels) };
let dst_slice = unsafe { slice::from_raw_parts_mut(dst_ptr, width as usize * channels) };

for x in cx..width as usize {
let px = x * 4;
let l_x = unsafe { *src_slice.get_unchecked(px) };
let l_y = unsafe { *src_slice.get_unchecked(px + 1) };
let l_z = unsafe { *src_slice.get_unchecked(px + 2) };
let l_x = unsafe { src_ptr.add(px).read_unaligned() };
let l_y = unsafe { src_ptr.add(px + 1).read_unaligned() };
let l_z = unsafe { src_ptr.add(px + 2).read_unaligned() };
let rgb;
match source {
LAB => {
Expand All @@ -156,7 +155,7 @@ fn xyz_with_alpha_to_channels<const CHANNELS_CONFIGURATION: u8, const TARGET: u8
}
}

let l_a = unsafe { *src_slice.get_unchecked(px + 3) };
let l_a = unsafe { src_ptr.add(px + 3).read_unaligned() };
let a_value = (l_a * 255f32).max(0f32);
unsafe {
*dst_slice
Expand All @@ -168,7 +167,8 @@ fn xyz_with_alpha_to_channels<const CHANNELS_CONFIGURATION: u8, const TARGET: u8
*dst_slice
.get_unchecked_mut(x * channels + image_configuration.get_b_channel_offset()) =
rgb.b;
dst_slice[x * channels + image_configuration.get_a_channel_offset()] =
*dst_slice
.get_unchecked_mut(x * channels + image_configuration.get_a_channel_offset()) =
a_value as u8;
}
}
Expand Down

0 comments on commit 2e7364a

Please sign in to comment.