Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/images/dynimage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::images::buffer::{
Rgb16Image, Rgb32FImage, RgbImage, Rgba16Image, Rgba32FImage, RgbaImage,
};
use crate::io::encoder::ImageEncoderBoxed;
use crate::io::free_functions::{self, encoder_for_format};
use crate::io::free_functions;
use crate::math::resize_dimensions;
use crate::metadata::Orientation;
use crate::traits::Pixel;
Expand Down Expand Up @@ -1069,7 +1069,7 @@ impl DynamicImage {
/// convert the image to some color type supported by the encoder. This may result in a loss of
/// precision or the removal of the alpha channel.
pub fn write_to<W: Write + Seek>(&self, mut w: W, format: ImageFormat) -> ImageResult<()> {
let encoder = encoder_for_format(format, &mut w)?;
let encoder = format.encoder(&mut w)?;
self.write_with_encoder_impl(encoder)
}

Expand Down Expand Up @@ -1111,7 +1111,7 @@ impl DynamicImage {
Q: AsRef<Path>,
{
let file = &mut BufWriter::new(File::create(path)?);
let encoder = encoder_for_format(format, file)?;
let encoder = format.encoder(file)?;
self.write_with_encoder_impl(encoder)
}
}
Expand Down Expand Up @@ -1357,7 +1357,7 @@ pub fn write_buffer_with_format<W: Write + Seek>(
color: impl Into<ExtendedColorType>,
format: ImageFormat,
) -> ImageResult<()> {
let encoder = encoder_for_format(format, buffered_writer)?;
let encoder = format.encoder(buffered_writer)?;
encoder.write_image(buf, width, height, color.into())
}

Expand Down
50 changes: 49 additions & 1 deletion src/io/format.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::ffi::OsStr;
use std::path::Path;

use crate::error::{ImageError, ImageFormatHint, ImageResult};
use crate::error::{
ImageError, ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind,
};

/// An enumeration of supported image formats.
/// Not all formats support both encoding and decoding.
Expand Down Expand Up @@ -375,6 +377,52 @@ impl ImageFormat {
.iter()
.copied()
}

/// Returns an encoder for this format, or an error if encoding in this format is not supported.
pub fn encoder<'a, W: std::io::Write + std::io::Seek>(
&self,
buffered_write: &'a mut W,
) -> ImageResult<Box<dyn crate::io::encoder::ImageEncoderBoxed + 'a>> {
use crate::codecs::*;
Ok(match self {
#[cfg(feature = "png")]
ImageFormat::Png => Box::new(png::PngEncoder::new(buffered_write)),
#[cfg(feature = "jpeg")]
ImageFormat::Jpeg => Box::new(jpeg::JpegEncoder::new(buffered_write)),
#[cfg(feature = "pnm")]
ImageFormat::Pnm => Box::new(pnm::PnmEncoder::new(buffered_write)),
#[cfg(feature = "gif")]
ImageFormat::Gif => Box::new(gif::GifEncoder::new(buffered_write)),
#[cfg(feature = "ico")]
ImageFormat::Ico => Box::new(ico::IcoEncoder::new(buffered_write)),
#[cfg(feature = "bmp")]
ImageFormat::Bmp => Box::new(bmp::BmpEncoder::new(buffered_write)),
#[cfg(feature = "ff")]
ImageFormat::Farbfeld => Box::new(farbfeld::FarbfeldEncoder::new(buffered_write)),
#[cfg(feature = "tga")]
ImageFormat::Tga => Box::new(tga::TgaEncoder::new(buffered_write)),
#[cfg(feature = "exr")]
ImageFormat::OpenExr => Box::new(openexr::OpenExrEncoder::new(buffered_write)),
#[cfg(feature = "tiff")]
ImageFormat::Tiff => Box::new(tiff::TiffEncoder::new(buffered_write)),
#[cfg(feature = "avif")]
ImageFormat::Avif => Box::new(avif::AvifEncoder::new(buffered_write)),
#[cfg(feature = "qoi")]
ImageFormat::Qoi => Box::new(qoi::QoiEncoder::new(buffered_write)),
#[cfg(feature = "webp")]
ImageFormat::WebP => Box::new(webp::WebPEncoder::new_lossless(buffered_write)),
#[cfg(feature = "hdr")]
ImageFormat::Hdr => Box::new(hdr::HdrEncoder::new(buffered_write)),
_ => {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormatHint::Unknown,
UnsupportedErrorKind::Format(ImageFormatHint::Name(format!("{self:?}"))),
),
));
}
})
}
}

#[cfg(test)]
Expand Down
51 changes: 3 additions & 48 deletions src/io/free_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ use std::io::{self, BufRead, BufWriter, Seek, Write};
use std::path::Path;
use std::{iter, mem::size_of};

use crate::io::encoder::ImageEncoderBoxed;
use crate::{codecs::*, ExtendedColorType, ImageReader};
use crate::{ExtendedColorType, ImageReader};

use crate::error::{
ImageError, ImageFormatHint, ImageResult, LimitError, LimitErrorKind, ParameterError,
ParameterErrorKind, UnsupportedError, UnsupportedErrorKind,
ParameterErrorKind,
};
use crate::{DynamicImage, ImageDecoder, ImageFormat};

Expand Down Expand Up @@ -53,54 +52,10 @@ pub fn save_buffer_with_format(
format: ImageFormat,
) -> ImageResult<()> {
let buffered_file_write = &mut BufWriter::new(File::create(path)?); // always seekable
let encoder = encoder_for_format(format, buffered_file_write)?;
let encoder = format.encoder(buffered_file_write)?;
encoder.write_image(buf, width, height, color.into())
}

pub(crate) fn encoder_for_format<'a, W: Write + Seek>(
format: ImageFormat,
buffered_write: &'a mut W,
) -> ImageResult<Box<dyn ImageEncoderBoxed + 'a>> {
Ok(match format {
#[cfg(feature = "png")]
ImageFormat::Png => Box::new(png::PngEncoder::new(buffered_write)),
#[cfg(feature = "jpeg")]
ImageFormat::Jpeg => Box::new(jpeg::JpegEncoder::new(buffered_write)),
#[cfg(feature = "pnm")]
ImageFormat::Pnm => Box::new(pnm::PnmEncoder::new(buffered_write)),
#[cfg(feature = "gif")]
ImageFormat::Gif => Box::new(gif::GifEncoder::new(buffered_write)),
#[cfg(feature = "ico")]
ImageFormat::Ico => Box::new(ico::IcoEncoder::new(buffered_write)),
#[cfg(feature = "bmp")]
ImageFormat::Bmp => Box::new(bmp::BmpEncoder::new(buffered_write)),
#[cfg(feature = "ff")]
ImageFormat::Farbfeld => Box::new(farbfeld::FarbfeldEncoder::new(buffered_write)),
#[cfg(feature = "tga")]
ImageFormat::Tga => Box::new(tga::TgaEncoder::new(buffered_write)),
#[cfg(feature = "exr")]
ImageFormat::OpenExr => Box::new(openexr::OpenExrEncoder::new(buffered_write)),
#[cfg(feature = "tiff")]
ImageFormat::Tiff => Box::new(tiff::TiffEncoder::new(buffered_write)),
#[cfg(feature = "avif")]
ImageFormat::Avif => Box::new(avif::AvifEncoder::new(buffered_write)),
#[cfg(feature = "qoi")]
ImageFormat::Qoi => Box::new(qoi::QoiEncoder::new(buffered_write)),
#[cfg(feature = "webp")]
ImageFormat::WebP => Box::new(webp::WebPEncoder::new_lossless(buffered_write)),
#[cfg(feature = "hdr")]
ImageFormat::Hdr => Box::new(hdr::HdrEncoder::new(buffered_write)),
_ => {
return Err(ImageError::Unsupported(
UnsupportedError::from_format_and_kind(
ImageFormatHint::Unknown,
UnsupportedErrorKind::Format(ImageFormatHint::Name(format!("{format:?}"))),
),
));
}
})
}

static MAGIC_BYTES: [(&[u8], &[u8], ImageFormat); 23] = [
(b"\x89PNG\r\n\x1a\n", b"", ImageFormat::Png),
(&[0xff, 0xd8, 0xff], b"", ImageFormat::Jpeg),
Expand Down
Loading