#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
extern crate alloc;
#[cfg(feature = "rgb")]
use rgb::{AsPixels as _, ComponentBytes as _};
mod decode;
mod error;
mod limits;
mod pixel;
mod pnm;
mod farbfeld;
#[cfg(feature = "hdr")]
mod hdr;
#[cfg(feature = "tga")]
mod tga;
#[cfg(feature = "qoi")]
mod qoi;
#[cfg(feature = "bmp")]
mod bmp;
#[cfg(feature = "rgb")]
mod pixel_traits;
#[cfg(feature = "zencodec")]
mod codec;
pub use decode::DecodeOutput;
pub use enough::{Stop, Unstoppable};
pub use error::BitmapError;
pub use limits::Limits;
pub use pixel::{ImageFormat, PixelLayout};
#[cfg(feature = "bmp")]
pub use bmp::{BmpMetadata, BmpPermissiveness};
#[cfg(feature = "rgb")]
pub use pixel_traits::{DecodePixel, EncodePixel};
#[cfg(feature = "zencodec")]
pub use codec::{
PnmDecodeJob, PnmDecoder, PnmDecoderConfig, PnmEncodeJob, PnmEncoder, PnmEncoderConfig,
};
#[cfg(all(feature = "zencodec", feature = "bmp"))]
pub use codec::{
BmpDecodeJob, BmpDecoder, BmpDecoderConfig, BmpEncodeJob, BmpEncoder, BmpEncoderConfig,
};
#[cfg(feature = "zencodec")]
pub use codec::{
FarbfeldDecodeJob, FarbfeldDecoder, FarbfeldDecoderConfig, FarbfeldEncodeJob, FarbfeldEncoder,
FarbfeldEncoderConfig,
};
#[cfg(all(feature = "zencodec", feature = "qoi"))]
pub use codec::{
QoiDecodeJob, QoiDecoder, QoiDecoderConfig, QoiEncodeJob, QoiEncoder, QoiEncoderConfig,
};
#[cfg(all(feature = "zencodec", feature = "hdr"))]
pub use codec::{
HdrDecodeJob, HdrDecoder, HdrDecoderConfig, HdrEncodeJob, HdrEncoder, HdrEncoderConfig,
};
#[cfg(all(feature = "zencodec", feature = "tga"))]
pub use codec::{
TgaDecodeJob, TgaDecoder, TgaDecoderConfig, TgaEncodeJob, TgaEncoder, TgaEncoderConfig,
};
#[cfg(feature = "rgb")]
pub use rgb::RGB as Rgb;
#[cfg(feature = "rgb")]
pub use rgb::RGBA as Rgba;
#[cfg(feature = "rgb")]
pub use rgb::alt::BGR as Bgr;
#[cfg(feature = "rgb")]
pub use rgb::alt::BGRA as Bgra;
#[cfg(feature = "rgb")]
pub type RGB8 = rgb::RGB<u8>;
#[cfg(feature = "rgb")]
pub type RGBA8 = rgb::RGBA<u8>;
#[cfg(feature = "rgb")]
pub type BGR8 = rgb::alt::BGR<u8>;
#[cfg(feature = "rgb")]
pub type BGRA8 = rgb::alt::BGRA<u8>;
pub fn detect_format(data: &[u8]) -> Option<ImageFormat> {
if data.len() >= 2 && data[0] == b'B' && data[1] == b'M' {
return Some(ImageFormat::Bmp);
}
if data.len() >= 8 && &data[0..8] == b"farbfeld" {
return Some(ImageFormat::Farbfeld);
}
if data.len() >= 4 && &data[0..4] == b"qoif" {
return Some(ImageFormat::Qoi);
}
if data.len() >= 10 && data.starts_with(b"#?RADIANCE") {
return Some(ImageFormat::Hdr);
}
if data.len() >= 6 && data.starts_with(b"#?RGBE") {
return Some(ImageFormat::Hdr);
}
if data.len() >= 2 && data[0] == b'P' {
match data[1] {
b'1'..=b'7' | b'f' | b'F' => return Some(ImageFormat::Pnm),
_ => {}
}
}
if data.len() >= 18 {
if data.len() >= 44 {
let footer = &data[data.len() - 18..];
if footer == b"TRUEVISION-XFILE.\0" {
return Some(ImageFormat::Tga);
}
}
let color_map_type = data[1];
let image_type = data[2];
let pixel_depth = data[16];
let descriptor = data[17];
let width = u16::from_le_bytes([data[12], data[13]]);
let height = u16::from_le_bytes([data[14], data[15]]);
let alpha_bits = descriptor & 0x0F;
let reserved_ok = descriptor & 0xC0 == 0;
let id_length_ok = data[0] < 128;
if reserved_ok
&& id_length_ok
&& matches!(image_type, 1 | 2 | 3 | 9 | 10 | 11)
&& color_map_type <= 1
&& width > 0
&& height > 0
{
let depth_ok = match image_type {
1 | 9 => pixel_depth == 8 && color_map_type == 1,
2 | 10 => matches!(pixel_depth, 15 | 16 | 24 | 32),
3 | 11 => pixel_depth == 8,
_ => false,
};
let alpha_ok = match pixel_depth {
32 => alpha_bits <= 8,
16 => alpha_bits <= 1,
_ => alpha_bits == 0,
};
let cmap_ok = if color_map_type == 1 {
let cmap_depth = data[7];
matches!(cmap_depth, 15 | 16 | 24 | 32)
} else {
true
};
if depth_ok && alpha_ok && cmap_ok {
return Some(ImageFormat::Tga);
}
}
}
None
}
pub fn decode(data: &[u8], stop: impl Stop) -> Result<DecodeOutput<'_>, BitmapError> {
decode_dispatch(data, None, &stop)
}
pub fn decode_with_limits<'a>(
data: &'a [u8],
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
decode_dispatch(data, Some(limits), &stop)
}
fn decode_dispatch<'a>(
data: &'a [u8],
limits: Option<&Limits>,
stop: &dyn enough::Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
match detect_format(data) {
Some(ImageFormat::Bmp) => {
#[cfg(feature = "bmp")]
return bmp::decode(data, limits, stop);
#[cfg(not(feature = "bmp"))]
return Err(BitmapError::UnsupportedVariant(
"BMP support requires the 'bmp' feature".into(),
));
}
Some(ImageFormat::Farbfeld) => farbfeld::decode(data, limits, stop),
Some(ImageFormat::Qoi) => {
#[cfg(feature = "qoi")]
return qoi::decode(data, limits, stop);
#[cfg(not(feature = "qoi"))]
return Err(BitmapError::UnsupportedVariant(
"QOI support requires the 'qoi' feature".into(),
));
}
Some(ImageFormat::Pnm) => pnm::decode(data, limits, stop),
Some(ImageFormat::Hdr) => {
#[cfg(feature = "hdr")]
return hdr::decode(data, limits, stop);
#[cfg(not(feature = "hdr"))]
return Err(BitmapError::UnsupportedVariant(
"HDR support requires the 'hdr' feature".into(),
));
}
Some(ImageFormat::Tga) => {
#[cfg(feature = "tga")]
return tga::decode(data, limits, stop);
#[cfg(not(feature = "tga"))]
return Err(BitmapError::UnsupportedVariant(
"TGA support requires the 'tga' feature".into(),
));
}
None => Err(BitmapError::UnrecognizedFormat),
}
}
pub fn encode_ppm(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
pnm::encode(pixels, width, height, layout, pnm::PnmFormat::Ppm, &stop)
}
pub fn encode_pgm(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
pnm::encode(pixels, width, height, layout, pnm::PnmFormat::Pgm, &stop)
}
pub fn encode_pam(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
pnm::encode(pixels, width, height, layout, pnm::PnmFormat::Pam, &stop)
}
pub fn encode_pfm(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
pnm::encode(pixels, width, height, layout, pnm::PnmFormat::Pfm, &stop)
}
pub fn decode_farbfeld(data: &[u8], stop: impl Stop) -> Result<DecodeOutput<'_>, BitmapError> {
farbfeld::decode(data, None, &stop)
}
pub fn decode_farbfeld_with_limits<'a>(
data: &'a [u8],
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
farbfeld::decode(data, Some(limits), &stop)
}
pub fn encode_farbfeld(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
farbfeld::encode(pixels, width, height, layout, &stop)
}
#[cfg(feature = "tga")]
pub fn decode_tga(data: &[u8], stop: impl Stop) -> Result<DecodeOutput<'_>, BitmapError> {
tga::decode(data, None, &stop)
}
#[cfg(feature = "tga")]
pub fn decode_tga_with_limits<'a>(
data: &'a [u8],
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
tga::decode(data, Some(limits), &stop)
}
#[cfg(feature = "tga")]
pub fn encode_tga(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
tga::encode(pixels, width, height, layout, &stop)
}
#[cfg(feature = "hdr")]
pub fn decode_hdr(data: &[u8], stop: impl Stop) -> Result<DecodeOutput<'_>, BitmapError> {
hdr::decode(data, None, &stop)
}
#[cfg(feature = "hdr")]
pub fn decode_hdr_with_limits<'a>(
data: &'a [u8],
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
hdr::decode(data, Some(limits), &stop)
}
#[cfg(feature = "hdr")]
pub fn encode_hdr(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
hdr::encode(pixels, width, height, layout, &stop)
}
#[cfg(feature = "qoi")]
pub fn decode_qoi(data: &[u8], stop: impl Stop) -> Result<DecodeOutput<'_>, BitmapError> {
qoi::decode(data, None, &stop)
}
#[cfg(feature = "qoi")]
pub fn decode_qoi_with_limits<'a>(
data: &'a [u8],
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
qoi::decode(data, Some(limits), &stop)
}
#[cfg(feature = "qoi")]
pub fn encode_qoi(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
qoi::encode(pixels, width, height, layout, &stop)
}
#[cfg(feature = "bmp")]
pub fn probe_bmp(data: &[u8]) -> Result<BmpMetadata, BitmapError> {
bmp::probe(data)
}
#[cfg(feature = "bmp")]
pub fn decode_bmp(data: &[u8], stop: impl Stop) -> Result<DecodeOutput<'_>, BitmapError> {
bmp::decode(data, None, &stop)
}
#[cfg(feature = "bmp")]
pub fn decode_bmp_with_limits<'a>(
data: &'a [u8],
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
bmp::decode(data, Some(limits), &stop)
}
#[cfg(feature = "bmp")]
pub fn decode_bmp_native(data: &[u8], stop: impl Stop) -> Result<DecodeOutput<'_>, BitmapError> {
bmp::decode_native(data, None, &stop)
}
#[cfg(feature = "bmp")]
pub fn decode_bmp_native_with_limits<'a>(
data: &'a [u8],
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
bmp::decode_native(data, Some(limits), &stop)
}
#[cfg(feature = "bmp")]
pub fn decode_bmp_permissive(
data: &[u8],
permissiveness: BmpPermissiveness,
stop: impl Stop,
) -> Result<DecodeOutput<'_>, BitmapError> {
bmp::decode_with_permissiveness(data, None, permissiveness, &stop)
}
#[cfg(feature = "bmp")]
pub fn decode_bmp_permissive_with_limits<'a>(
data: &'a [u8],
permissiveness: BmpPermissiveness,
limits: &'a Limits,
stop: impl Stop,
) -> Result<DecodeOutput<'a>, BitmapError> {
bmp::decode_with_permissiveness(data, Some(limits), permissiveness, &stop)
}
#[cfg(feature = "bmp")]
pub fn encode_bmp(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
bmp::encode(pixels, width, height, layout, false, &stop)
}
#[cfg(feature = "bmp")]
pub fn encode_bmp_rgba(
pixels: &[u8],
width: u32,
height: u32,
layout: PixelLayout,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError> {
bmp::encode(pixels, width, height, layout, true, &stop)
}
#[cfg(feature = "rgb")]
pub fn decode_pixels<P: DecodePixel>(
data: &[u8],
stop: impl Stop,
) -> Result<(alloc::vec::Vec<P>, u32, u32), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let decoded = decode(data, stop)?;
decoded_to_pixels(decoded)
}
#[cfg(feature = "rgb")]
pub fn decode_pixels_with_limits<P: DecodePixel>(
data: &[u8],
limits: &Limits,
stop: impl Stop,
) -> Result<(alloc::vec::Vec<P>, u32, u32), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let decoded = decode_with_limits(data, limits, stop)?;
decoded_to_pixels(decoded)
}
#[cfg(all(feature = "bmp", feature = "rgb"))]
pub fn decode_bmp_pixels<P: DecodePixel>(
data: &[u8],
stop: impl Stop,
) -> Result<(alloc::vec::Vec<P>, u32, u32), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let decoded = decode_bmp(data, stop)?;
decoded_to_pixels(decoded)
}
#[cfg(all(feature = "bmp", feature = "rgb"))]
pub fn decode_bmp_pixels_with_limits<P: DecodePixel>(
data: &[u8],
limits: &Limits,
stop: impl Stop,
) -> Result<(alloc::vec::Vec<P>, u32, u32), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let decoded = decode_bmp_with_limits(data, limits, stop)?;
decoded_to_pixels(decoded)
}
#[cfg(feature = "rgb")]
fn decoded_to_pixels<P: DecodePixel>(
decoded: DecodeOutput<'_>,
) -> Result<(alloc::vec::Vec<P>, u32, u32), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
if !decoded.layout.is_memory_compatible(P::layout()) {
return Err(BitmapError::LayoutMismatch {
expected: P::layout(),
actual: decoded.layout,
});
}
let pixels: &[P] = decoded.pixels().as_pixels();
Ok((pixels.to_vec(), decoded.width, decoded.height))
}
#[cfg(feature = "rgb")]
pub fn encode_ppm_pixels<P: EncodePixel>(
pixels: &[P],
width: u32,
height: u32,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
encode_ppm(pixels.as_bytes(), width, height, P::layout(), stop)
}
#[cfg(feature = "rgb")]
pub fn encode_pgm_pixels<P: EncodePixel>(
pixels: &[P],
width: u32,
height: u32,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
encode_pgm(pixels.as_bytes(), width, height, P::layout(), stop)
}
#[cfg(feature = "rgb")]
pub fn encode_pam_pixels<P: EncodePixel>(
pixels: &[P],
width: u32,
height: u32,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
encode_pam(pixels.as_bytes(), width, height, P::layout(), stop)
}
#[cfg(feature = "rgb")]
pub fn encode_pfm_pixels<P: EncodePixel>(
pixels: &[P],
width: u32,
height: u32,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
encode_pfm(pixels.as_bytes(), width, height, P::layout(), stop)
}
#[cfg(all(feature = "bmp", feature = "rgb"))]
pub fn encode_bmp_pixels<P: EncodePixel>(
pixels: &[P],
width: u32,
height: u32,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
encode_bmp(pixels.as_bytes(), width, height, P::layout(), stop)
}
#[cfg(all(feature = "bmp", feature = "rgb"))]
pub fn encode_bmp_rgba_pixels<P: EncodePixel>(
pixels: &[P],
width: u32,
height: u32,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
encode_bmp_rgba(pixels.as_bytes(), width, height, P::layout(), stop)
}
#[cfg(feature = "imgref")]
pub fn decode_img<P: DecodePixel>(
data: &[u8],
stop: impl Stop,
) -> Result<imgref::ImgVec<P>, BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let (pixels, w, h) = decode_pixels::<P>(data, stop)?;
Ok(imgref::ImgVec::new(pixels, w as usize, h as usize))
}
#[cfg(feature = "imgref")]
pub fn decode_img_with_limits<P: DecodePixel>(
data: &[u8],
limits: &Limits,
stop: impl Stop,
) -> Result<imgref::ImgVec<P>, BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let (pixels, w, h) = decode_pixels_with_limits::<P>(data, limits, stop)?;
Ok(imgref::ImgVec::new(pixels, w as usize, h as usize))
}
#[cfg(all(feature = "bmp", feature = "imgref"))]
pub fn decode_bmp_img<P: DecodePixel>(
data: &[u8],
stop: impl Stop,
) -> Result<imgref::ImgVec<P>, BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let (pixels, w, h) = decode_bmp_pixels::<P>(data, stop)?;
Ok(imgref::ImgVec::new(pixels, w as usize, h as usize))
}
#[cfg(all(feature = "bmp", feature = "imgref"))]
pub fn decode_bmp_img_with_limits<P: DecodePixel>(
data: &[u8],
limits: &Limits,
stop: impl Stop,
) -> Result<imgref::ImgVec<P>, BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let (pixels, w, h) = decode_bmp_pixels_with_limits::<P>(data, limits, stop)?;
Ok(imgref::ImgVec::new(pixels, w as usize, h as usize))
}
#[cfg(feature = "imgref")]
pub fn decode_into<P: DecodePixel>(
data: &[u8],
output: imgref::ImgRefMut<'_, P>,
stop: impl Stop,
) -> Result<(), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let decoded = decode(data, stop)?;
copy_decoded_into(decoded, output)
}
#[cfg(all(feature = "bmp", feature = "imgref"))]
pub fn decode_bmp_into<P: DecodePixel>(
data: &[u8],
output: imgref::ImgRefMut<'_, P>,
stop: impl Stop,
) -> Result<(), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
let decoded = decode_bmp(data, stop)?;
copy_decoded_into(decoded, output)
}
#[cfg(feature = "imgref")]
fn copy_decoded_into<P: DecodePixel>(
decoded: DecodeOutput<'_>,
mut output: imgref::ImgRefMut<'_, P>,
) -> Result<(), BitmapError>
where
[u8]: rgb::AsPixels<P>,
{
if !decoded.layout.is_memory_compatible(P::layout()) {
return Err(BitmapError::LayoutMismatch {
expected: P::layout(),
actual: decoded.layout,
});
}
let out_w = output.width();
let out_h = output.height();
if decoded.width as usize != out_w || decoded.height as usize != out_h {
return Err(BitmapError::InvalidData(alloc::format!(
"dimension mismatch: decoded {}x{}, output buffer {}x{}",
decoded.width,
decoded.height,
out_w,
out_h
)));
}
let src_pixels: &[P] = decoded.pixels().as_pixels();
for (src_row, dst_row) in src_pixels.chunks_exact(out_w).zip(output.rows_mut()) {
<[P]>::copy_from_slice(dst_row, src_row);
}
Ok(())
}
#[cfg(feature = "imgref")]
pub fn encode_ppm_img<P: EncodePixel>(
img: imgref::ImgRef<'_, P>,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
let (bytes, w, h) = collect_img_bytes(img);
encode_ppm(&bytes, w, h, P::layout(), stop)
}
#[cfg(feature = "imgref")]
pub fn encode_pgm_img<P: EncodePixel>(
img: imgref::ImgRef<'_, P>,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
let (bytes, w, h) = collect_img_bytes(img);
encode_pgm(&bytes, w, h, P::layout(), stop)
}
#[cfg(feature = "imgref")]
pub fn encode_pam_img<P: EncodePixel>(
img: imgref::ImgRef<'_, P>,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
let (bytes, w, h) = collect_img_bytes(img);
encode_pam(&bytes, w, h, P::layout(), stop)
}
#[cfg(feature = "imgref")]
pub fn encode_pfm_img<P: EncodePixel>(
img: imgref::ImgRef<'_, P>,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
let (bytes, w, h) = collect_img_bytes(img);
encode_pfm(&bytes, w, h, P::layout(), stop)
}
#[cfg(all(feature = "bmp", feature = "imgref"))]
pub fn encode_bmp_img<P: EncodePixel>(
img: imgref::ImgRef<'_, P>,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
let (bytes, w, h) = collect_img_bytes(img);
encode_bmp(&bytes, w, h, P::layout(), stop)
}
#[cfg(all(feature = "bmp", feature = "imgref"))]
pub fn encode_bmp_rgba_img<P: EncodePixel>(
img: imgref::ImgRef<'_, P>,
stop: impl Stop,
) -> Result<alloc::vec::Vec<u8>, BitmapError>
where
[P]: rgb::ComponentBytes<u8>,
{
let (bytes, w, h) = collect_img_bytes(img);
encode_bmp_rgba(&bytes, w, h, P::layout(), stop)
}
#[cfg(feature = "imgref")]
fn collect_img_bytes<P: EncodePixel>(img: imgref::ImgRef<'_, P>) -> (alloc::vec::Vec<u8>, u32, u32)
where
[P]: rgb::ComponentBytes<u8>,
{
let w = img.width();
let h = img.height();
if img.stride() == w {
let pixels = &img.buf()[..w * h];
(pixels.as_bytes().to_vec(), w as u32, h as u32)
} else {
let bpp = core::mem::size_of::<P>();
let mut bytes = alloc::vec::Vec::with_capacity(w * h * bpp);
for row in img.rows() {
bytes.extend_from_slice(row.as_bytes());
}
(bytes, w as u32, h as u32)
}
}