use std::io::Write;
use crate::{
converter::{ConversionError, Converter, QueueConverter},
format::Format,
};
pub struct SvgConverter;
impl Converter for SvgConverter {
fn supported_formats(&self) -> Vec<Format> {
vec![
Format::Svg,
Format::Jpeg,
Format::Png,
Format::Tiff,
Format::Bmp,
Format::Gif,
]
}
fn to_svg(&self, input: &Vec<u8>, output: &mut Vec<u8>) -> Result<(), ConversionError> {
output.clone_from(input);
Ok(())
}
fn to_bmp(&self, input: &Vec<u8>, output: &mut Vec<u8>) -> Result<(), ConversionError> {
let mut converter = QueueConverter::new();
converter.push(Format::Png);
converter.push(Format::Bmp);
converter.process(input, output, &Format::Svg)
}
fn to_tiff(&self, input: &Vec<u8>, output: &mut Vec<u8>) -> Result<(), ConversionError> {
let mut converter = QueueConverter::new();
converter.push(Format::Png);
converter.push(Format::Tiff);
converter.process(input, output, &Format::Svg)
}
fn to_png(&self, input: &Vec<u8>, output: &mut Vec<u8>) -> Result<(), ConversionError> {
let mut opt = usvg::Options::default();
opt.fontdb.load_system_fonts();
let tree = usvg::Tree::from_data(input, &opt.to_ref()).unwrap();
let pixmap_size = tree.svg_node().size.to_screen_size();
let mut pixmap = tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap();
resvg::render(
&tree,
usvg::FitTo::Original,
tiny_skia::Transform::default(),
pixmap.as_mut(),
)
.unwrap();
output
.write_all(pixmap.encode_png().unwrap().as_slice())
.expect("Failed to write to output");
Ok(())
}
fn to_jpeg(&self, input: &Vec<u8>, output: &mut Vec<u8>) -> Result<(), ConversionError> {
let mut converter = QueueConverter::new();
converter.push(Format::Png);
converter.push(Format::Jpeg);
converter.process(input, output, &Format::Svg)
}
fn to_gif(&self, input: &Vec<u8>, output: &mut Vec<u8>) -> Result<(), ConversionError> {
let mut converter = QueueConverter::new();
converter.push(Format::Png);
converter.push(Format::Gif);
converter.process(input, output, &Format::Svg)
}
}
#[cfg(test)]
mod tests {
use image::codecs::bmp::BmpDecoder;
use image::codecs::gif::GifDecoder;
use image::codecs::jpeg::JpegDecoder;
use image::codecs::png::PngDecoder;
use image::codecs::tiff::TiffDecoder;
use crate::converter::{test_utils, Converter, SvgConverter};
use crate::format::Format;
static CONVERTER: SvgConverter = SvgConverter;
static SOURCE_EXT: &str = "svg";
#[test]
fn test_supported_formats() {
let formats = CONVERTER.supported_formats();
assert_eq!(formats.len(), 6);
assert!(formats.contains(&Format::Svg));
assert!(formats.contains(&Format::Tiff));
assert!(formats.contains(&Format::Png));
assert!(formats.contains(&Format::Jpeg));
assert!(formats.contains(&Format::Bmp));
assert!(formats.contains(&Format::Gif));
}
#[test]
fn test_to_svg() {
let target_ext = "svg";
test_utils::test_conversion_to(
Format::Svg,
&CONVERTER,
SOURCE_EXT,
target_ext,
|source, target| {
let input_size = source.metadata().unwrap().len();
let output_size = target.metadata().unwrap().len();
input_size == output_size
},
);
}
#[test]
fn test_to_bmp() {
let target_ext = "bmp";
test_utils::test_conversion_to(
Format::Bmp,
&CONVERTER,
SOURCE_EXT,
target_ext,
|_, target| {
let decoding = BmpDecoder::new(target);
decoding.is_ok()
},
);
}
#[test]
fn test_to_tiff() {
let target_ext = "tiff";
test_utils::test_conversion_to(
Format::Tiff,
&CONVERTER,
SOURCE_EXT,
target_ext,
|_, target| {
let decoding = TiffDecoder::new(target);
decoding.is_ok()
},
);
}
#[test]
fn test_to_png() {
let target_ext = "png";
test_utils::test_conversion_to(
Format::Png,
&CONVERTER,
SOURCE_EXT,
target_ext,
|_, target| {
let decoding = PngDecoder::new(target);
decoding.is_ok()
},
);
}
#[test]
fn test_to_jpeg() {
let target_ext = "jpeg";
test_utils::test_conversion_to(
Format::Jpeg,
&CONVERTER,
SOURCE_EXT,
target_ext,
|_, target| {
let decoding = JpegDecoder::new(target);
decoding.is_ok()
},
);
}
#[test]
fn test_to_gif() {
let target_ext = "gif";
test_utils::test_conversion_to(
Format::Gif,
&CONVERTER,
SOURCE_EXT,
target_ext,
|_, target| {
let decoding = GifDecoder::new(target);
decoding.is_ok()
},
);
}
}