mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Co-authored-by: PgBiel <9021226+PgBiel@users.noreply.github.com> Co-authored-by: Laurenz <laurmaedje@gmail.com>
69 lines
2.6 KiB
Rust
69 lines
2.6 KiB
Rust
use base64::Engine;
|
|
use ecow::{eco_format, EcoString};
|
|
use image::{codecs::png::PngEncoder, ImageEncoder};
|
|
use typst_library::foundations::Smart;
|
|
use typst_library::layout::{Abs, Axes};
|
|
use typst_library::visualize::{
|
|
ExchangeFormat, Image, ImageKind, ImageScaling, RasterFormat,
|
|
};
|
|
|
|
use crate::SVGRenderer;
|
|
|
|
impl SVGRenderer {
|
|
/// Render an image element.
|
|
pub(super) fn render_image(&mut self, image: &Image, size: &Axes<Abs>) {
|
|
let url = convert_image_to_base64_url(image);
|
|
self.xml.start_element("image");
|
|
self.xml.write_attribute("xlink:href", &url);
|
|
self.xml.write_attribute("width", &size.x.to_pt());
|
|
self.xml.write_attribute("height", &size.y.to_pt());
|
|
self.xml.write_attribute("preserveAspectRatio", "none");
|
|
match image.scaling() {
|
|
Smart::Auto => {}
|
|
Smart::Custom(ImageScaling::Smooth) => {
|
|
// This is still experimental and not implemented in all major browsers.
|
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering#browser_compatibility
|
|
self.xml.write_attribute("style", "image-rendering: smooth")
|
|
}
|
|
Smart::Custom(ImageScaling::Pixelated) => {
|
|
self.xml.write_attribute("style", "image-rendering: pixelated")
|
|
}
|
|
}
|
|
self.xml.end_element();
|
|
}
|
|
}
|
|
|
|
/// Encode an image into a data URL. The format of the URL is
|
|
/// `data:image/{format};base64,`.
|
|
#[comemo::memoize]
|
|
pub fn convert_image_to_base64_url(image: &Image) -> EcoString {
|
|
let mut buf;
|
|
let (format, data): (&str, &[u8]) = match image.kind() {
|
|
ImageKind::Raster(raster) => match raster.format() {
|
|
RasterFormat::Exchange(format) => (
|
|
match format {
|
|
ExchangeFormat::Png => "png",
|
|
ExchangeFormat::Jpg => "jpeg",
|
|
ExchangeFormat::Gif => "gif",
|
|
},
|
|
raster.data(),
|
|
),
|
|
RasterFormat::Pixel(_) => ("png", {
|
|
buf = vec![];
|
|
let mut encoder = PngEncoder::new(&mut buf);
|
|
if let Some(icc_profile) = raster.icc() {
|
|
encoder.set_icc_profile(icc_profile.to_vec()).ok();
|
|
}
|
|
raster.dynamic().write_with_encoder(encoder).unwrap();
|
|
buf.as_slice()
|
|
}),
|
|
},
|
|
ImageKind::Svg(svg) => ("svg+xml", svg.data()),
|
|
};
|
|
|
|
let mut url = eco_format!("data:image/{format};base64,");
|
|
let data = base64::engine::general_purpose::STANDARD.encode(data);
|
|
url.push_str(&data);
|
|
url
|
|
}
|