use alloc::vec::Vec;
use rgb::{AsPixels, ComponentBytes, Rgb, Rgba};
use crate::decoder::DecodeResult;
use crate::encoder::{EncodeRequest, EncodeResult, EncoderConfig, PixelLayout};
mod private {
pub trait Sealed {}
}
pub trait DecodePixel: Copy + 'static + private::Sealed {
const CHANNELS: usize;
const HAS_ALPHA: bool;
const IS_BGR: bool;
}
pub trait EncodePixel: Copy + 'static + private::Sealed {
const CHANNELS: usize;
fn color_type() -> PixelLayout;
}
impl private::Sealed for Rgb<u8> {}
impl private::Sealed for Rgba<u8> {}
impl private::Sealed for rgb::Bgr<u8> {}
impl private::Sealed for rgb::Bgra<u8> {}
impl private::Sealed for rgb::Argb<u8> {}
impl private::Sealed for rgb::Gray<u8> {}
impl private::Sealed for rgb::GrayAlpha<u8> {}
impl DecodePixel for Rgb<u8> {
const CHANNELS: usize = 3;
const HAS_ALPHA: bool = false;
const IS_BGR: bool = false;
}
impl DecodePixel for Rgba<u8> {
const CHANNELS: usize = 4;
const HAS_ALPHA: bool = true;
const IS_BGR: bool = false;
}
impl DecodePixel for rgb::Bgr<u8> {
const CHANNELS: usize = 3;
const HAS_ALPHA: bool = false;
const IS_BGR: bool = true;
}
impl DecodePixel for rgb::Bgra<u8> {
const CHANNELS: usize = 4;
const HAS_ALPHA: bool = true;
const IS_BGR: bool = true;
}
impl EncodePixel for Rgb<u8> {
const CHANNELS: usize = 3;
fn color_type() -> PixelLayout {
PixelLayout::Rgb8
}
}
impl EncodePixel for Rgba<u8> {
const CHANNELS: usize = 4;
fn color_type() -> PixelLayout {
PixelLayout::Rgba8
}
}
impl EncodePixel for rgb::Bgr<u8> {
const CHANNELS: usize = 3;
fn color_type() -> PixelLayout {
PixelLayout::Bgr8
}
}
impl EncodePixel for rgb::Bgra<u8> {
const CHANNELS: usize = 4;
fn color_type() -> PixelLayout {
PixelLayout::Bgra8
}
}
impl EncodePixel for rgb::Argb<u8> {
const CHANNELS: usize = 4;
fn color_type() -> PixelLayout {
PixelLayout::Argb8
}
}
impl EncodePixel for rgb::Gray<u8> {
const CHANNELS: usize = 1;
fn color_type() -> PixelLayout {
PixelLayout::L8
}
}
impl EncodePixel for rgb::GrayAlpha<u8> {
const CHANNELS: usize = 2;
fn color_type() -> PixelLayout {
PixelLayout::La8
}
}
pub fn decode<P: DecodePixel>(data: &[u8]) -> DecodeResult<(Vec<P>, u32, u32)>
where
[u8]: AsPixels<P>,
{
let (bytes, w, h) = match (P::IS_BGR, P::HAS_ALPHA) {
(false, false) => crate::oneshot::decode_rgb(data)?,
(false, true) => crate::oneshot::decode_rgba(data)?,
(true, false) => crate::oneshot::decode_bgr(data)?,
(true, true) => crate::oneshot::decode_bgra(data)?,
};
let pixels: &[P] = bytes.as_pixels();
Ok((pixels.to_vec(), w, h))
}
pub fn decode_into<P: DecodePixel>(
data: &[u8],
output: &mut [P],
stride_pixels: u32,
) -> DecodeResult<(u32, u32)>
where
[P]: ComponentBytes<u8>,
{
let buf: &mut [u8] = output.as_bytes_mut();
match (P::IS_BGR, P::HAS_ALPHA) {
(false, false) => crate::oneshot::decode_rgb_into(data, buf, stride_pixels),
(false, true) => crate::oneshot::decode_rgba_into(data, buf, stride_pixels),
(true, false) => crate::oneshot::decode_bgr_into(data, buf, stride_pixels),
(true, true) => crate::oneshot::decode_bgra_into(data, buf, stride_pixels),
}
}
pub fn decode_append<P: DecodePixel>(data: &[u8], output: &mut Vec<P>) -> DecodeResult<(u32, u32)>
where
[u8]: AsPixels<P>,
{
let (bytes, w, h) = match (P::IS_BGR, P::HAS_ALPHA) {
(false, false) => crate::oneshot::decode_rgb(data)?,
(false, true) => crate::oneshot::decode_rgba(data)?,
(true, false) => crate::oneshot::decode_bgr(data)?,
(true, true) => crate::oneshot::decode_bgra(data)?,
};
let pixels: &[P] = bytes.as_pixels();
output.extend_from_slice(pixels);
Ok((w, h))
}
#[cfg(feature = "imgref")]
pub fn decode_to_img<P: DecodePixel>(data: &[u8]) -> DecodeResult<imgref::ImgVec<P>>
where
[u8]: AsPixels<P>,
{
let (pixels, w, h) = decode::<P>(data)?;
Ok(imgref::ImgVec::new(pixels, w as usize, h as usize))
}
#[cfg(feature = "imgref")]
pub fn encode_img<P: EncodePixel>(img: imgref::ImgRef<'_, P>) -> EncodeResult<Vec<u8>>
where
[P]: ComponentBytes<u8>,
{
let width = img.width() as u32;
let height = img.height() as u32;
let buf: &[u8] = img.buf().as_bytes();
let config = EncoderConfig::new_lossy();
EncodeRequest::new(&config, buf, P::color_type(), width, height)
.with_stride(img.stride())
.encode()
}
pub fn encode<P: EncodePixel>(pixels: &[P], width: u32, height: u32) -> EncodeResult<Vec<u8>>
where
[P]: ComponentBytes<u8>,
{
EncoderConfig::new_lossy().encode_pixels(pixels, width, height)
}
impl EncoderConfig {
pub fn encode_pixels<P: EncodePixel>(
&self,
pixels: &[P],
width: u32,
height: u32,
) -> EncodeResult<Vec<u8>>
where
[P]: ComponentBytes<u8>,
{
let bytes: &[u8] = pixels.as_bytes();
let color = P::color_type();
EncodeRequest::new(self, bytes, color, width, height).encode()
}
#[cfg(feature = "imgref")]
pub fn encode_img<P: EncodePixel>(&self, img: imgref::ImgRef<'_, P>) -> EncodeResult<Vec<u8>>
where
[P]: ComponentBytes<u8>,
{
let width = img.width() as u32;
let height = img.height() as u32;
let buf: &[u8] = img.buf().as_bytes();
EncodeRequest::new(self, buf, P::color_type(), width, height)
.with_stride(img.stride())
.encode()
}
}