use multiversion::multiversion; use crate::bits::{BEf16, BEf24, BEf32, BEu16, LEf16, LEf24, LEf32, LEu16}; use crate::decompressors::LineIteratorMut; use crate::pumps::{BitPump, BitPumpMSB}; use crate::{bits::Endian, decompressors::Decompressor}; /// Decompressor for packed data pub struct PackedDecompressor { bps: u32, endian: Endian, } impl PackedDecompressor { pub fn new(bps: u32, endian: Endian) -> Self { Self { bps, endian } } } impl<'a> Decompressor<'a, u16> for PackedDecompressor { fn decompress(&self, src: &[u8], skip_rows: usize, lines: impl LineIteratorMut<'a, u16>, line_width: usize) -> std::result::Result<(), String> { match (self.endian, self.bps) { // 16 bits, encoding depends on TIFF endianess (Endian::Big, 16) => unpack_16be(lines, src, skip_rows, line_width), (Endian::Little, 16) => unpack_16le(lines, src, skip_rows, line_width), // 12 Bits, DNG spec says it must be always encoded as big-endian (_, 12) => unpack_12be(lines, src, skip_rows, line_width), // 10 Bits, DNG spec says it must be always encoded as big-endian (_, 10) => unpack_10be(lines, src, skip_rows, line_width), // 8 bits (_, 8) => unpack_8bit(lines, src, skip_rows, line_width), // Generic MSB decoder for exotic packed bit sizes (_, bps) if bps > 0 && bps < 16 => unpack_generic_msb(lines, src, skip_rows, line_width, self.bps), // Unhandled bits (_, bps) => return Err(format_args!("DNG: Don't know how to handle DNG with {} bps", bps).to_string()), } Ok(()) } fn strips_optimized(&self) -> bool { true } fn tile_optimized(&self) -> bool { true } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_16be<'a>(lines: impl LineIteratorMut<'a, u16>, src: &[u8], skip_rows: usize, width: usize) { for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * 2)..]; for (out, bytes) in line.iter_mut().zip(inb.chunks_exact(2)) { *out = BEu16(bytes, 0); } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_16le<'a>(lines: impl LineIteratorMut<'a, u16>, src: &[u8], skip_rows: usize, width: usize) { for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * 2)..]; for (i, bytes) in (0..width).zip(inb.chunks_exact(2)) { line[i] = LEu16(bytes, 0); } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_12be<'a>(lines: impl LineIteratorMut<'a, u16>, src: &[u8], skip_rows: usize, width: usize) { for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * 12 / 8)..]; for (o, i) in line.chunks_exact_mut(2).zip(inb.chunks_exact(3)) { let g1: u16 = i[0] as u16; let g2: u16 = i[1] as u16; let g3: u16 = i[2] as u16; o[0] = (g1 << 4) | (g2 >> 4); o[1] = ((g2 & 0x0f) << 8) | g3; } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_10be<'a>(lines: impl LineIteratorMut<'a, u16>, src: &[u8], skip_rows: usize, width: usize) { for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * 10 / 8)..]; for (o, i) in line.chunks_exact_mut(4).zip(inb.chunks_exact(5)) { let g1: u16 = i[0] as u16; let g2: u16 = i[1] as u16; let g3: u16 = i[2] as u16; let g4: u16 = i[3] as u16; let g5: u16 = i[4] as u16; o[0] = (g1 << 2) | (g2 >> 6); o[1] = ((g2 & 0x3f) << 4) | (g3 >> 4); o[2] = ((g3 & 0x0f) << 6) | (g4 >> 2); o[3] = ((g4 & 0x03) << 8) | g5; } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_8bit<'a>(lines: impl LineIteratorMut<'a, u16>, src: &[u8], skip_rows: usize, width: usize) { for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width)..]; for (o, i) in line.iter_mut().zip(inb.iter()) { *o = *i as u16; } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_generic_msb<'a>(lines: impl LineIteratorMut<'a, u16>, src: &[u8], skip_rows: usize, width: usize, bits: u32) { assert!(bits <= 16); let skip_bits = skip_rows * width * bits as usize; let offset = skip_bits / 8; let bias = skip_bits % 8; let mut pump = BitPumpMSB::new(&src[offset..]); pump.consume_bits(bias as u32); for line in lines { for p in line { *p = pump.get_bits(bits) as u16; } } } impl<'a> Decompressor<'a, f32> for PackedDecompressor { fn decompress(&self, src: &[u8], skip_rows: usize, lines: impl LineIteratorMut<'a, f32>, line_width: usize) -> std::result::Result<(), String> { match (self.endian, self.bps) { // 16 bits, encoding depends on TIFF endianess (Endian::Big, 32) => unpack_f32be(lines, src, skip_rows, line_width), (Endian::Little, 32) => unpack_f32le(lines, src, skip_rows, line_width), (Endian::Big, 24) => unpack_f24be(lines, src, skip_rows, line_width), (Endian::Little, 24) => unpack_f24le(lines, src, skip_rows, line_width), (Endian::Big, 16) => unpack_f16be(lines, src, skip_rows, line_width), (Endian::Little, 16) => unpack_f16le(lines, src, skip_rows, line_width), // Unhandled bits (_, bps) => return Err(format_args!("DNG: Don't know how to handle FP DNG with {} bps", bps).to_string()), } Ok(()) } fn strips_optimized(&self) -> bool { true } fn tile_optimized(&self) -> bool { true } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_f32be<'a>(lines: impl LineIteratorMut<'a, f32>, src: &[u8], skip_rows: usize, width: usize) { for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * size_of::())..]; for (i, bytes) in (0..width).zip(inb.chunks_exact(4)) { line[i] = BEf32(bytes, 0); } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_f32le<'a>(lines: impl LineIteratorMut<'a, f32>, src: &[u8], skip_rows: usize, width: usize) { for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * size_of::())..]; for (i, bytes) in (0..width).zip(inb.chunks_exact(4)) { line[i] = LEf32(bytes, 0); } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_f24le<'a>(lines: impl LineIteratorMut<'a, f32>, src: &[u8], skip_rows: usize, width: usize) { const SIZEOF_FP24: usize = 3; for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * SIZEOF_FP24)..]; for (i, bytes) in (0..width).zip(inb.chunks_exact(SIZEOF_FP24)) { line[i] = LEf24(bytes, 0); } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_f24be<'a>(lines: impl LineIteratorMut<'a, f32>, src: &[u8], skip_rows: usize, width: usize) { const SIZEOF_FP24: usize = 3; for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * SIZEOF_FP24)..]; for (i, bytes) in (0..width).zip(inb.chunks_exact(SIZEOF_FP24)) { line[i] = BEf24(bytes, 0); } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_f16le<'a>(lines: impl LineIteratorMut<'a, f32>, src: &[u8], skip_rows: usize, width: usize) { const SIZEOF_FP16: usize = 2; for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * SIZEOF_FP16)..]; for (i, bytes) in (0..width).zip(inb.chunks_exact(SIZEOF_FP16)) { line[i] = LEf16(bytes, 0); } } } #[multiversion(targets("x86_64+avx+avx2", "x86+sse", "aarch64+neon"))] fn unpack_f16be<'a>(lines: impl LineIteratorMut<'a, f32>, src: &[u8], skip_rows: usize, width: usize) { const SIZEOF_FP16: usize = 2; for (row, line) in lines.enumerate() { let inb = &src[((skip_rows + row) * width * SIZEOF_FP16)..]; for (i, bytes) in (0..width).zip(inb.chunks_exact(SIZEOF_FP16)) { line[i] = BEf16(bytes, 0); } } }