diff --git a/Cargo.lock b/Cargo.lock index 347704b33..a9b3756a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1215,6 +1215,7 @@ dependencies = [ "byteorder-lite", "color_quant", "gif", + "image-webp", "num-traits", "png", "zune-core", diff --git a/Cargo.toml b/Cargo.toml index 0f871e211..b4890e3c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ icu_provider_adapters = "1.4" icu_provider_blob = "1.4" icu_segmenter = { version = "1.4", features = ["serde"] } if_chain = "1" -image = { version = "0.25.5", default-features = false, features = ["png", "jpeg", "gif"] } +image = { version = "0.25.5", default-features = false, features = ["png", "jpeg", "gif", "webp"] } indexmap = { version = "2", features = ["serde"] } infer = { version = "0.19.0", default-features = false } kamadak-exif = "0.6" diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs index 15b4296eb..4a36045ae 100644 --- a/crates/typst-ide/src/complete.rs +++ b/crates/typst-ide/src/complete.rs @@ -841,7 +841,9 @@ fn param_value_completions<'a>( /// Returns which file extensions to complete for the given parameter if any. fn path_completion(func: &Func, param: &ParamInfo) -> Option<&'static [&'static str]> { Some(match (func.name(), param.name) { - (Some("image"), "source") => &["png", "jpg", "jpeg", "gif", "svg", "svgz"], + (Some("image"), "source") => { + &["png", "jpg", "jpeg", "gif", "svg", "svgz", "webp"] + } (Some("csv"), "source") => &["csv"], (Some("plugin"), "source") => &["wasm"], (Some("cbor"), "source") => &["cbor"], diff --git a/crates/typst-layout/src/image.rs b/crates/typst-layout/src/image.rs index 3e5b7d8bd..8136a25a3 100644 --- a/crates/typst-layout/src/image.rs +++ b/crates/typst-layout/src/image.rs @@ -147,6 +147,7 @@ fn determine_format(source: &DataSource, data: &Bytes) -> StrResult "jpg" | "jpeg" => return Ok(ExchangeFormat::Jpg.into()), "gif" => return Ok(ExchangeFormat::Gif.into()), "svg" | "svgz" => return Ok(VectorFormat::Svg.into()), + "webp" => return Ok(ExchangeFormat::Webp.into()), _ => {} } } diff --git a/crates/typst-library/src/visualize/image/mod.rs b/crates/typst-library/src/visualize/image/mod.rs index 258eb96f3..f9e345e70 100644 --- a/crates/typst-library/src/visualize/image/mod.rs +++ b/crates/typst-library/src/visualize/image/mod.rs @@ -77,8 +77,8 @@ pub struct ImageElem { /// [`source`]($image.source) (even then, Typst will try to figure out the /// format automatically, but that's not always possible). /// - /// Supported formats are `{"png"}`, `{"jpg"}`, `{"gif"}`, `{"svg"}` as well - /// as raw pixel data. Embedding PDFs as images is + /// Supported formats are `{"png"}`, `{"jpg"}`, `{"gif"}`, `{"svg"}`, + /// `{"webp"}` as well as raw pixel data. Embedding PDFs as images is /// [not currently supported](https://github.com/typst/typst/issues/145). /// /// When providing raw pixel data as the `source`, you must specify a diff --git a/crates/typst-library/src/visualize/image/raster.rs b/crates/typst-library/src/visualize/image/raster.rs index 21d5b18fc..54f832bae 100644 --- a/crates/typst-library/src/visualize/image/raster.rs +++ b/crates/typst-library/src/visualize/image/raster.rs @@ -9,6 +9,7 @@ use ecow::{eco_format, EcoString}; use image::codecs::gif::GifDecoder; use image::codecs::jpeg::JpegDecoder; use image::codecs::png::PngDecoder; +use image::codecs::webp::WebPDecoder; use image::{ guess_format, DynamicImage, ImageBuffer, ImageDecoder, ImageResult, Limits, Pixel, }; @@ -77,6 +78,7 @@ impl RasterImage { ExchangeFormat::Jpg => decode(JpegDecoder::new(cursor), icc), ExchangeFormat::Png => decode(PngDecoder::new(cursor), icc), ExchangeFormat::Gif => decode(GifDecoder::new(cursor), icc), + ExchangeFormat::Webp => decode(WebPDecoder::new(cursor), icc), } .map_err(format_image_error)?; @@ -242,6 +244,8 @@ pub enum ExchangeFormat { /// Raster format that is typically used for short animated clips. Typst can /// load GIFs, but they will become static. Gif, + /// Raster format that supports both lossy and lossless compression. + Webp, } impl ExchangeFormat { @@ -257,6 +261,7 @@ impl From for image::ImageFormat { ExchangeFormat::Png => image::ImageFormat::Png, ExchangeFormat::Jpg => image::ImageFormat::Jpeg, ExchangeFormat::Gif => image::ImageFormat::Gif, + ExchangeFormat::Webp => image::ImageFormat::WebP, } } } @@ -269,6 +274,7 @@ impl TryFrom for ExchangeFormat { image::ImageFormat::Png => ExchangeFormat::Png, image::ImageFormat::Jpeg => ExchangeFormat::Jpg, image::ImageFormat::Gif => ExchangeFormat::Gif, + image::ImageFormat::WebP => ExchangeFormat::Webp, _ => bail!("format not yet supported"), }) } diff --git a/crates/typst-svg/src/image.rs b/crates/typst-svg/src/image.rs index d74432026..1868ca39b 100644 --- a/crates/typst-svg/src/image.rs +++ b/crates/typst-svg/src/image.rs @@ -45,6 +45,7 @@ pub fn convert_image_to_base64_url(image: &Image) -> EcoString { ExchangeFormat::Png => "png", ExchangeFormat::Jpg => "jpeg", ExchangeFormat::Gif => "gif", + ExchangeFormat::Webp => "webp", }, raster.data(), ), diff --git a/docs/tutorial/1-writing.md b/docs/tutorial/1-writing.md index acc257830..d505d2d03 100644 --- a/docs/tutorial/1-writing.md +++ b/docs/tutorial/1-writing.md @@ -69,7 +69,7 @@ the first item of the list above by indenting it. ## Adding a figure { #figure } You think that your report would benefit from a figure. Let's add one. Typst -supports images in the formats PNG, JPEG, GIF, and SVG. To add an image file to +supports images in the formats PNG, JPEG, GIF, SVG, and WebP. To add an image file to your project, first open the _file panel_ by clicking the box icon in the left sidebar. Here, you can see a list of all files in your project. Currently, there is only one: The main Typst file you are writing in. To upload another file, diff --git a/tests/suite/visualize/image.typ b/tests/suite/visualize/image.typ index 9a77870af..73c4feff8 100644 --- a/tests/suite/visualize/image.typ +++ b/tests/suite/visualize/image.typ @@ -243,7 +243,7 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B --- image-png-but-pixmap-format --- #image( read("/assets/images/tiger.jpg", encoding: none), - // Error: 11-18 expected "png", "jpg", "gif", dictionary, "svg", or auto + // Error: 11-18 expected "png", "jpg", "gif", "webp", dictionary, "svg", or auto format: "rgba8", )