pub fn gray8_to_rgb24(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let v = src[i];
dst[i * 3] = v;
dst[i * 3 + 1] = v;
dst[i * 3 + 2] = v;
}
}
pub fn gray8_to_rgba(src: &[u8], dst: &mut [u8], pixels: usize) {
if crate::simd_dispatch::has_avx2() {
#[cfg(target_arch = "x86_64")]
unsafe {
gray8_to_rgba_avx2(src, dst, pixels);
return;
}
}
for i in 0..pixels {
let v = src[i];
dst[i * 4] = v;
dst[i * 4 + 1] = v;
dst[i * 4 + 2] = v;
dst[i * 4 + 3] = 255;
}
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
unsafe fn gray8_to_rgba_avx2(src: &[u8], dst: &mut [u8], pixels: usize) {
use core::arch::x86_64::*;
const SHUF: [u8; 16] = [0, 0, 0, 0x80, 1, 1, 1, 0x80, 2, 2, 2, 0x80, 3, 3, 3, 0x80];
let shuf = _mm_loadu_si128(SHUF.as_ptr() as *const __m128i);
let alpha = _mm_set1_epi32(0xFF00_0000u32 as i32);
let chunks = pixels / 4;
for c in 0..chunks {
let s = _mm_cvtsi32_si128(core::ptr::read_unaligned(
src.as_ptr().add(c * 4) as *const i32
));
let broadcast = _mm_shuffle_epi8(s, shuf);
let with_alpha = _mm_or_si128(broadcast, alpha);
_mm_storeu_si128(dst.as_mut_ptr().add(c * 16) as *mut __m128i, with_alpha);
}
let tail = chunks * 4;
for i in tail..pixels {
let v = src[i];
dst[i * 4] = v;
dst[i * 4 + 1] = v;
dst[i * 4 + 2] = v;
dst[i * 4 + 3] = 255;
}
}
pub fn gray16le_to_gray8(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
dst[i] = src[i * 2 + 1];
}
}
pub fn gray8_to_gray16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let b = src[i];
dst[i * 2] = b;
dst[i * 2 + 1] = b;
}
}
pub fn mono_to_gray8(src: &[u8], dst: &mut [u8], w: usize, h: usize, black_is_zero: bool) {
let stride = w.div_ceil(8);
for row in 0..h {
for col in 0..w {
let byte = src[row * stride + col / 8];
let bit = (byte >> (7 - (col & 7))) & 1;
let g = if bit == 1 { 255u8 } else { 0u8 };
dst[row * w + col] = if black_is_zero { g } else { 255 - g };
}
}
}
pub fn ya8_to_gray8(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
dst[i] = src[i * 2];
}
}
pub fn ya8_to_alpha8(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
dst[i] = src[i * 2 + 1];
}
}
pub fn gray8_to_ya8(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
dst[i * 2] = src[i];
dst[i * 2 + 1] = 255;
}
}
pub fn ya8_to_rgb24(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let y = src[i * 2];
dst[i * 3] = y;
dst[i * 3 + 1] = y;
dst[i * 3 + 2] = y;
}
}
pub fn ya8_to_rgba(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let y = src[i * 2];
let a = src[i * 2 + 1];
dst[i * 4] = y;
dst[i * 4 + 1] = y;
dst[i * 4 + 2] = y;
dst[i * 4 + 3] = a;
}
}
pub fn rgba_to_ya8(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let r = src[i * 4] as u32;
let g = src[i * 4 + 1] as u32;
let b = src[i * 4 + 2] as u32;
let a = src[i * 4 + 3];
let y = ((r + g + b + 1) / 3) as u8;
dst[i * 2] = y;
dst[i * 2 + 1] = a;
}
}
pub fn rgb24_to_ya8(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let r = src[i * 3] as u32;
let g = src[i * 3 + 1] as u32;
let b = src[i * 3 + 2] as u32;
let y = ((r + g + b + 1) / 3) as u8;
dst[i * 2] = y;
dst[i * 2 + 1] = 255;
}
}
#[inline]
fn ld16(src: &[u8], off: usize) -> u16 {
u16::from_le_bytes([src[off], src[off + 1]])
}
#[inline]
fn st16(dst: &mut [u8], off: usize, v: u16) {
dst[off..off + 2].copy_from_slice(&v.to_le_bytes());
}
pub fn ya16le_to_ya8(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
dst[i * 2] = (ld16(src, i * 4) >> 8) as u8;
dst[i * 2 + 1] = (ld16(src, i * 4 + 2) >> 8) as u8;
}
}
pub fn ya8_to_ya16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
st16(dst, i * 4, src[i * 2] as u16 * 257);
st16(dst, i * 4 + 2, src[i * 2 + 1] as u16 * 257);
}
}
pub fn ya16le_to_gray16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
dst[i * 2..i * 2 + 2].copy_from_slice(&src[i * 4..i * 4 + 2]);
}
}
pub fn gray16le_to_ya16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
dst[i * 4..i * 4 + 2].copy_from_slice(&src[i * 2..i * 2 + 2]);
st16(dst, i * 4 + 2, 0xFFFF);
}
}
pub fn ya16le_to_gray8(src: &[u8], dst: &mut [u8], pixels: usize) {
for (i, d) in dst.iter_mut().enumerate().take(pixels) {
*d = (ld16(src, i * 4) >> 8) as u8;
}
}
pub fn gray8_to_ya16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for (i, &s) in src.iter().enumerate().take(pixels) {
st16(dst, i * 4, s as u16 * 257);
st16(dst, i * 4 + 2, 0xFFFF);
}
}
pub fn ya16le_to_rgba64le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let y = ld16(src, i * 4);
let a = ld16(src, i * 4 + 2);
st16(dst, i * 8, y);
st16(dst, i * 8 + 2, y);
st16(dst, i * 8 + 4, y);
st16(dst, i * 8 + 6, a);
}
}
pub fn rgba64le_to_ya16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let r = ld16(src, i * 8) as u32;
let g = ld16(src, i * 8 + 2) as u32;
let b = ld16(src, i * 8 + 4) as u32;
let a = ld16(src, i * 8 + 6);
st16(dst, i * 4, ((r + g + b + 1) / 3) as u16);
st16(dst, i * 4 + 2, a);
}
}
pub fn ya16le_to_rgba(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let y = (ld16(src, i * 4) >> 8) as u8;
dst[i * 4] = y;
dst[i * 4 + 1] = y;
dst[i * 4 + 2] = y;
dst[i * 4 + 3] = (ld16(src, i * 4 + 2) >> 8) as u8;
}
}
pub fn ya16le_to_rgb24(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let y = (ld16(src, i * 4) >> 8) as u8;
dst[i * 3] = y;
dst[i * 3 + 1] = y;
dst[i * 3 + 2] = y;
}
}
pub fn rgba_to_ya16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let r = src[i * 4] as u32;
let g = src[i * 4 + 1] as u32;
let b = src[i * 4 + 2] as u32;
let y = ((r + g + b + 1) / 3) as u16;
st16(dst, i * 4, y * 257);
st16(dst, i * 4 + 2, src[i * 4 + 3] as u16 * 257);
}
}
pub fn rgb24_to_ya16le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let r = src[i * 3] as u32;
let g = src[i * 3 + 1] as u32;
let b = src[i * 3 + 2] as u32;
let y = ((r + g + b + 1) / 3) as u16;
st16(dst, i * 4, y * 257);
st16(dst, i * 4 + 2, 0xFFFF);
}
}
pub fn gray8_to_rgb48le(src: &[u8], dst: &mut [u8], pixels: usize) {
for (i, &v) in src.iter().enumerate().take(pixels) {
let word = (v as u16 * 257).to_le_bytes();
for c in 0..3 {
dst[i * 6 + c * 2..i * 6 + c * 2 + 2].copy_from_slice(&word);
}
}
}
pub fn gray8_to_rgba64le(src: &[u8], dst: &mut [u8], pixels: usize) {
for (i, &v) in src.iter().enumerate().take(pixels) {
let word = (v as u16 * 257).to_le_bytes();
for c in 0..3 {
dst[i * 8 + c * 2..i * 8 + c * 2 + 2].copy_from_slice(&word);
}
dst[i * 8 + 6] = 0xFF;
dst[i * 8 + 7] = 0xFF;
}
}
pub fn gray16le_to_rgb48le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let word = &src[i * 2..i * 2 + 2];
for c in 0..3 {
dst[i * 6 + c * 2..i * 6 + c * 2 + 2].copy_from_slice(word);
}
}
}
pub fn gray16le_to_rgba64le(src: &[u8], dst: &mut [u8], pixels: usize) {
for i in 0..pixels {
let word = &src[i * 2..i * 2 + 2];
for c in 0..3 {
dst[i * 8 + c * 2..i * 8 + c * 2 + 2].copy_from_slice(word);
}
dst[i * 8 + 6] = 0xFF;
dst[i * 8 + 7] = 0xFF;
}
}
pub fn gray8_to_mono(src: &[u8], dst: &mut [u8], w: usize, h: usize, black_is_zero: bool) {
let stride = w.div_ceil(8);
for b in dst.iter_mut() {
*b = 0;
}
for row in 0..h {
for col in 0..w {
let g = src[row * w + col];
let bit_on = if black_is_zero { g >= 128 } else { g < 128 };
if bit_on {
let shift = 7 - (col & 7);
dst[row * stride + col / 8] |= 1u8 << shift;
}
}
}
}