Skip to content
Open
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
11 changes: 4 additions & 7 deletions src/codecs/bmp/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::error::{
EncodingError, ImageError, ImageFormatHint, ImageResult, ParameterError, ParameterErrorKind,
UnsupportedError, UnsupportedErrorKind,
};
use crate::{DynamicImage, ExtendedColorType, ImageEncoder, ImageFormat};
use crate::{ExtendedColorType, ImageEncoder, ImageFormat};

const BITMAPFILEHEADER_SIZE: u32 = 14;
const BITMAPINFOHEADER_SIZE: u32 = 40;
Expand Down Expand Up @@ -366,12 +366,9 @@ impl<W: Write> ImageEncoder for BmpEncoder<W> {
self.encode(buf, width, height, color_type)
}

fn make_compatible_img(
&self,
_: crate::io::encoder::MethodSealedToImage,
img: &DynamicImage,
) -> Option<DynamicImage> {
crate::io::encoder::dynimage_conversion_8bit(img)
fn supported_colors(&self) -> Option<&[ExtendedColorType]> {
use ExtendedColorType::*;
Some(&[Rgb8, Rgba8, L1, L8, La8])
}
}

Expand Down
16 changes: 4 additions & 12 deletions src/codecs/jpeg/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{error, fmt};
use crate::error::{
EncodingError, ImageError, ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use crate::{ColorType, DynamicImage, ExtendedColorType, ImageEncoder, ImageFormat};
use crate::{ExtendedColorType, ImageEncoder, ImageFormat};

use jpeg_encoder::Encoder;

Expand Down Expand Up @@ -293,17 +293,9 @@ impl<W: Write> ImageEncoder for JpegEncoder<W> {
Ok(())
}

fn make_compatible_img(
&self,
_: crate::io::encoder::MethodSealedToImage,
img: &DynamicImage,
) -> Option<DynamicImage> {
use ColorType::*;
match img.color() {
L8 | Rgb8 => None,
La8 | L16 | L32F | La16 | La32F => Some(img.to_luma8().into()),
Rgba8 | Rgb16 | Rgb32F | Rgba16 | Rgba32F => Some(img.to_rgb8().into()),
}
fn supported_colors(&self) -> Option<&[ExtendedColorType]> {
use ExtendedColorType::*;
Some(&[Rgb8, L8])
}
}

Expand Down
16 changes: 3 additions & 13 deletions src/codecs/png.rs
Original file line number Diff line number Diff line change
Expand Up @@ -945,19 +945,9 @@ impl<W: Write> ImageEncoder for PngEncoder<W> {
Ok(())
}

fn make_compatible_img(
&self,
_: crate::io::encoder::MethodSealedToImage,
img: &DynamicImage,
) -> Option<DynamicImage> {
use ColorType::*;
match img.color() {
L32F => Some(img.to_luma16().into()),
La32F => Some(img.to_luma_alpha16().into()),
Rgb32F => Some(img.to_rgb16().into()),
Rgba32F => Some(img.to_rgba16().into()),
L8 | La8 | Rgb8 | Rgba8 | L16 | La16 | Rgb16 | Rgba16 => None,
}
fn supported_colors(&self) -> Option<&[ExtendedColorType]> {
use ExtendedColorType::*;
Some(&[Rgb8, Rgba8, L8, La8, Rgb16, Rgba16, L16, La16])
}
}

Expand Down
11 changes: 4 additions & 7 deletions src/codecs/tga/encoder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::header::Header;
use crate::{codecs::tga::header::ImageType, error::EncodingError, utils::vec_try_with_capacity};
use crate::{DynamicImage, ExtendedColorType, ImageEncoder, ImageError, ImageFormat, ImageResult};
use crate::{ExtendedColorType, ImageEncoder, ImageError, ImageFormat, ImageResult};
use std::{error, fmt, io::Write};

/// Errors that can occur during encoding and saving of a TGA image.
Expand Down Expand Up @@ -253,12 +253,9 @@ impl<W: Write> ImageEncoder for TgaEncoder<W> {
self.encode(buf, width, height, color_type)
}

fn make_compatible_img(
&self,
_: crate::io::encoder::MethodSealedToImage,
img: &DynamicImage,
) -> Option<DynamicImage> {
crate::io::encoder::dynimage_conversion_8bit(img)
fn supported_colors(&self) -> Option<&[ExtendedColorType]> {
use ExtendedColorType::*;
Some(&[Rgb8, Rgba8, L8, La8])
}
}

Expand Down
11 changes: 4 additions & 7 deletions src/codecs/webp/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::io::Write;

use crate::error::{EncodingError, UnsupportedError, UnsupportedErrorKind};
use crate::{DynamicImage, ExtendedColorType, ImageEncoder, ImageError, ImageFormat, ImageResult};
use crate::{ExtendedColorType, ImageEncoder, ImageError, ImageFormat, ImageResult};

/// WebP Encoder.
///
Expand Down Expand Up @@ -110,12 +110,9 @@ impl<W: Write> ImageEncoder for WebPEncoder<W> {
Ok(())
}

fn make_compatible_img(
&self,
_: crate::io::encoder::MethodSealedToImage,
img: &DynamicImage,
) -> Option<DynamicImage> {
crate::io::encoder::dynimage_conversion_8bit(img)
fn supported_colors(&self) -> Option<&[ExtendedColorType]> {
use ExtendedColorType::*;
Some(&[Rgb8, Rgba8, L8, La8])
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/images/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,30 @@ where
}
buffer
}

pub(crate) fn convert_precision<ToType: Pixel>(
&self,
) -> ImageBuffer<ToType, Vec<ToType::Subpixel>>
where
ToType::Subpixel: FromPrimitive<P::Subpixel>,
{
assert_eq!(P::CHANNEL_COUNT, ToType::CHANNEL_COUNT);
assert_eq!(P::COLOR_MODEL, ToType::COLOR_MODEL);

// outlined inner function to avoid monomorphization bloat
fn inner<From, To>(buffer: &[From]) -> Vec<To>
where
From: Copy,
To: FromPrimitive<From>,
{
buffer.iter().copied().map(To::from_primitive).collect()
}

let data = inner(self.subpixels());
let mut buffer = ImageBuffer::from_raw(self.width, self.height, data).unwrap();
buffer.copy_color_space_from(self);
buffer
}
}

/// Inputs to [`ImageBuffer::copy_from_color_space`].
Expand Down
72 changes: 54 additions & 18 deletions src/images/dynimage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,52 @@ impl DynamicImage {
}
}

pub(crate) fn to_u8(&self) -> DynamicImage {
use DynamicImage::*;
match self {
ImageLuma8(_) | ImageLumaA8(_) | ImageRgb8(_) | ImageRgba8(_) => self.clone(),

ImageLuma16(buffer) => ImageLuma8(buffer.convert_precision()),
ImageLumaA16(buffer) => ImageLumaA8(buffer.convert_precision()),
ImageRgb16(buffer) => ImageRgb8(buffer.convert_precision()),
ImageRgba16(buffer) => ImageRgba8(buffer.convert_precision()),
ImageLuma32F(buffer) => ImageLuma8(buffer.convert_precision()),
ImageLumaA32F(buffer) => ImageLumaA8(buffer.convert_precision()),
ImageRgb32F(buffer) => ImageRgb8(buffer.convert_precision()),
ImageRgba32F(buffer) => ImageRgba8(buffer.convert_precision()),
}
}
pub(crate) fn to_u16(&self) -> DynamicImage {
use DynamicImage::*;
match self {
ImageLuma16(_) | ImageLumaA16(_) | ImageRgb16(_) | ImageRgba16(_) => self.clone(),

ImageLuma8(buffer) => ImageLuma16(buffer.convert_precision()),
ImageLumaA8(buffer) => ImageLumaA16(buffer.convert_precision()),
ImageRgb8(buffer) => ImageRgb16(buffer.convert_precision()),
ImageRgba8(buffer) => ImageRgba16(buffer.convert_precision()),
ImageLuma32F(buffer) => ImageLuma16(buffer.convert_precision()),
ImageLumaA32F(buffer) => ImageLumaA16(buffer.convert_precision()),
ImageRgb32F(buffer) => ImageRgb16(buffer.convert_precision()),
ImageRgba32F(buffer) => ImageRgba16(buffer.convert_precision()),
}
}
pub(crate) fn to_f32(&self) -> DynamicImage {
use DynamicImage::*;
match self {
ImageLuma32F(_) | ImageLumaA32F(_) | ImageRgb32F(_) | ImageRgba32F(_) => self.clone(),

ImageLuma8(buffer) => ImageLuma32F(buffer.convert_precision()),
ImageLumaA8(buffer) => ImageLumaA32F(buffer.convert_precision()),
ImageRgb8(buffer) => ImageRgb32F(buffer.convert_precision()),
ImageRgba8(buffer) => ImageRgba32F(buffer.convert_precision()),
ImageLuma16(buffer) => ImageLuma32F(buffer.convert_precision()),
ImageLumaA16(buffer) => ImageLumaA32F(buffer.convert_precision()),
ImageRgb16(buffer) => ImageRgb32F(buffer.convert_precision()),
ImageRgba16(buffer) => ImageRgba32F(buffer.convert_precision()),
}
}

/// Return a grayscale version of this image.
/// Returns either a `Luma` or `LumaA` image.
#[must_use]
Expand Down Expand Up @@ -1599,7 +1645,7 @@ impl DynamicImage {
&self,
encoder: Box<dyn ImageEncoderBoxed + 'a>,
) -> ImageResult<()> {
let converted = encoder.make_compatible_img(crate::io::encoder::MethodSealedToImage, self);
let converted = crate::io::encoder::make_compatible_img(self, encoder.supported_colors());
let img = converted.as_ref().unwrap_or(self);

encoder.write_image(
Expand All @@ -1615,23 +1661,15 @@ impl DynamicImage {
/// Assumes the writer is buffered. In most cases, you should wrap your writer in a `BufWriter`
/// for best performance.
///
/// ## Color Conversion
///
/// Unlike other encoding methods in this crate, methods on `DynamicImage` try to automatically
/// 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.
/// For information about possible color conversions, see [`DynamicImage::save`].
pub fn write_to<W: Write + Seek>(&self, mut w: W, format: ImageFormat) -> ImageResult<()> {
let encoder = encoder_for_format(format, &mut w)?;
self.write_with_encoder_impl(encoder)
}

/// Encode this image with the provided encoder.
///
/// ## Color Conversion
///
/// Unlike other encoding methods in this crate, methods on `DynamicImage` try to automatically
/// 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.
/// For information about possible color conversions, see [`DynamicImage::save`].
pub fn write_with_encoder(&self, encoder: impl ImageEncoder) -> ImageResult<()> {
self.write_with_encoder_impl(Box::new(encoder))
}
Expand All @@ -1641,8 +1679,10 @@ impl DynamicImage {
/// ## Color Conversion
///
/// Unlike other encoding methods in this crate, methods on `DynamicImage` try to automatically
/// 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.
/// convert the image to some color type supported by the underlying encoder. This may result in a loss of
/// precision and/or the removal of the alpha channel.
///
/// Conversions are not guaranteed to happen and may change in the future.
pub fn save<Q>(&self, path: Q) -> ImageResult<()>
where
Q: AsRef<Path>,
Expand All @@ -1653,11 +1693,7 @@ impl DynamicImage {

/// Saves the buffer to a file with the specified format.
///
/// ## Color Conversion
///
/// Unlike other encoding methods in this crate, methods on `DynamicImage` try to automatically
/// 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.
/// For information about possible color conversions, see [`DynamicImage::save`].
pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> ImageResult<()>
where
Q: AsRef<Path>,
Expand Down
Loading
Loading