diff --git a/src/encode.rs b/src/encode.rs index 604620e..1e80cc0 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -4,6 +4,8 @@ use core::convert::TryFrom; #[cfg(feature = "std")] use std::io::Write; +use bytemuck::Pod; + use crate::consts::{QOI_HEADER_SIZE, QOI_OP_INDEX, QOI_OP_RUN, QOI_PADDING, QOI_PADDING_SIZE}; use crate::error::{Error, Result}; use crate::header::Header; @@ -17,6 +19,7 @@ use crate::utils::{unlikely, BytesMut, Writer}; fn encode_impl(mut buf: W, data: &[u8]) -> Result where Pixel: SupportedChannels, + [u8; N]: Pod, { let cap = buf.capacity(); diff --git a/src/pixel.rs b/src/pixel.rs index 90674e4..784726e 100644 --- a/src/pixel.rs +++ b/src/pixel.rs @@ -1,6 +1,7 @@ use crate::consts::{QOI_OP_DIFF, QOI_OP_LUMA, QOI_OP_RGB, QOI_OP_RGBA}; use crate::error::Result; use crate::utils::Writer; +use bytemuck::{cast, Pod}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[repr(transparent)] @@ -107,12 +108,18 @@ impl Pixel { } #[inline] - pub const fn hash_index(self) -> u8 { - let r = self.r().wrapping_mul(3); - let g = self.g().wrapping_mul(5); - let b = self.b().wrapping_mul(7); - let a = self.a_or(0xff).wrapping_mul(11); - r.wrapping_add(g).wrapping_add(b).wrapping_add(a) % 64 + pub fn hash_index(self) -> u8 + where + [u8; N]: Pod, + { + // credits for the initial idea: @zakarumych + let v = if N == 4 { + u32::from_ne_bytes(cast(self.0)) + } else { + u32::from_ne_bytes([self.0[0], self.0[1], self.0[2], 0xff]) + } as u64; + let s = ((v & 0xff00_ff00) << 32) | (v & 0x00ff_00ff); + s.wrapping_mul(0x0300_0700_0005_000b_u64).to_le().swap_bytes() as u8 & 63 } #[inline]