I'm trying to use convert using an encoder chosen at runtime.
This has been a nightmare:
Originally one can do:
dyn_image.write_to( writer, format );
But this uses default compression settings. I want custom settings.
AFAIK, I can use dyn_image.write_with_encoder() for that. Great!
BUT:
let encoder = match dst_format {
MyImageFormat::Png => codecs::png::PngEncoder::new_with_quality(
cursor,
codecs::png::CompressionType::Level(settings.quality),
codecs::png::FilterType::Adaptive,
),
MyImageFormat::Jpg => codecs::jpeg::JpegEncoder::new_with_quality(
cursor,
settings.quality,
),
MyImageFormat::Webp => todo!(),
MyImageFormat::Qoi => todo!(),
};
This fails because encoder can't be PngEncoder or JpegEncoder. So I copied what image is doing internally:
trait ImageEncoderBoxed: image::ImageEncoder {
fn write_image(
self: Box<Self>,
buf: &'_ [u8],
width: u32,
height: u32,
color: image::ExtendedColorType,
) -> image::ImageResult<()>;
}
impl<T: image::ImageEncoder> ImageEncoderBoxed for T {
fn write_image(
self: Box<Self>,
buf: &'_ [u8],
width: u32,
height: u32,
color: image::ExtendedColorType,
) -> image::ImageResult<()> {
(*self).write_image(buf, width, height, color)
}
}
let encoder: Box<dyn ImageEncoderBoxed> = match dst_format {
ImageFormat::Png => Box::new(codecs::png::PngEncoder::new_with_quality(
cursor,
codecs::png::CompressionType::Level(settings.quality),
codecs::png::FilterType::Adaptive,
)),
ImageFormat::Jpg => Box::new(codecs::jpeg::JpegEncoder::new_with_quality(
cursor,
settings.quality,
)),
ImageFormat::Webp => todo!(),
ImageFormat::Qoi => todo!(),
};
layer.img.write_with_encoder(encoder)
But now this fails because write_with_encoder isn't like the internal function write_with_encoder_impl:
the trait bound `Box<dyn ImageEncoderBoxed>: ImageEncoder` is not satisfied rustc(E0277)
Doing layer.img.write_with_encoder(*encoder) also doesn't work:
error[E0277]: the size for values of type `dyn ImageEncoderBoxed` cannot be known at compilation time
--> _wasm/src/image_converter.rs:237:48
|
237 | match layer.img.write_with_encoder(*encoder) {
| ------------------ ^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn ImageEncoderBoxed`
note: required by an implicit `Sized` bound in `DynamicImage::write_with_encoder`
--> /home/matias/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/image-0.25.10/src/images/dynimage.rs:1383:47
|
1383 | pub fn write_with_encoder(&self, encoder: impl ImageEncoder) -> ImageResult<()> {
| ^^^^^^^^^^^^^^^^^ required by the implicit `Sized` requirement on this type parameter in `DynamicImage::write_with_encoder`
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
|
237 - match layer.img.write_with_encoder(*encoder) {
237 + match layer.img.write_with_encoder(encoder) {
|
I can "fix" this by later calling encoder() in every branch. Or I can try doing something clever with templates.
But this sounds like something overly complicated for something that can be resolved at the API level by simply offering a function that accepts a boxed encoder.
Btw this is a recurrent problem I see with this library: whenever I need something that exceeds very basic functionality (like setting compression quality or accessing another frame in an animated image), the user needs to become aware of all decoders and encoder types, with no generic interface to avoid that.
I'm trying to use convert using an encoder chosen at runtime.
This has been a nightmare:
Originally one can do:
But this uses default compression settings. I want custom settings.
AFAIK, I can use
dyn_image.write_with_encoder()for that. Great!BUT:
This fails because
encodercan't be PngEncoder or JpegEncoder. So I copied what image is doing internally:But now this fails because write_with_encoder isn't like the internal function write_with_encoder_impl:
Doing
layer.img.write_with_encoder(*encoder)also doesn't work:I can "fix" this by later calling encoder() in every branch. Or I can try doing something clever with templates.
But this sounds like something overly complicated for something that can be resolved at the API level by simply offering a function that accepts a boxed encoder.
Btw this is a recurrent problem I see with this library: whenever I need something that exceeds very basic functionality (like setting compression quality or accessing another frame in an animated image), the user needs to become aware of all decoders and encoder types, with no generic interface to avoid that.