attempt 2: use datasource

This commit is contained in:
PgBiel 2025-01-30 02:36:39 -03:00
parent 477e1b22b3
commit 283fcbb71c
3 changed files with 55 additions and 22 deletions

View File

@ -17,7 +17,7 @@ use pixmap::{Pixmap, PixmapFormat, PixmapSource};
use typst_syntax::{Span, Spanned}; use typst_syntax::{Span, Spanned};
use typst_utils::LazyHash; use typst_utils::LazyHash;
use crate::diag::{bail, At, SourceResult, StrResult}; use crate::diag::{bail, SourceResult, StrResult};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
cast, elem, func, scope, AutoValue, Bytes, Cast, Content, Derived, Dict, NativeElement, cast, elem, func, scope, AutoValue, Bytes, Cast, Content, Derived, Dict, NativeElement,
@ -54,11 +54,11 @@ pub struct ImageElem {
/// For more details about paths, see the [Paths section]($syntax/#paths). /// For more details about paths, see the [Paths section]($syntax/#paths).
#[required] #[required]
#[parse( #[parse(
let source = args.expect::<Spanned<DataSource>>("source")?; let source = args.expect::<Spanned<ImageSource>>("source")?;
let data = source.load(engine.world)?; let data = source.load(engine.world)?;
Derived::new(source.v, data) Derived::new(source.v, data)
)] )]
pub source: Derived<DataSource, Bytes>, pub source: Derived<ImageSource, Bytes>,
/// The image's format. Detected automatically by default. /// The image's format. Detected automatically by default.
/// ///
@ -124,7 +124,7 @@ impl ImageElem {
pub fn decode( pub fn decode(
span: Span, span: Span,
/// The data to decode as an image. Can be a string for SVGs. /// The data to decode as an image. Can be a string for SVGs.
source: ImageSource, data: Readable,
/// The image's format. Detected automatically by default. /// The image's format. Detected automatically by default.
#[named] #[named]
format: Option<Smart<ImageFormat>>, format: Option<Smart<ImageFormat>>,
@ -148,7 +148,7 @@ impl ImageElem {
scaling: Option<ImageScaling>, scaling: Option<ImageScaling>,
) -> StrResult<Content> { ) -> StrResult<Content> {
let bytes = data.into_bytes(); let bytes = data.into_bytes();
let source = Derived::new(DataSource::Bytes(bytes.clone()), bytes); let source = Derived::new(ImageSource::DataSource(DataSource::Bytes(bytes.clone())), bytes);
let mut elem = ImageElem::new(source); let mut elem = ImageElem::new(source);
if let Some(format) = format { if let Some(format) = format {
elem.push_format(format); elem.push_format(format);
@ -240,25 +240,25 @@ impl Image {
#[comemo::memoize] #[comemo::memoize]
#[typst_macros::time(name = "load image")] #[typst_macros::time(name = "load image")]
pub fn new( pub fn new(
source: ImageSource, data: Derived<ImageSource, Bytes>,
format: ImageFormat, format: ImageFormat,
options: &ImageOptions, options: &ImageOptions,
) -> StrResult<Image> { ) -> StrResult<Image> {
let kind = match format { let kind = match format {
ImageFormat::Raster(format) => { ImageFormat::Raster(format) => {
let ImageSource::Readable(readable) = source else { let ImageSource::DataSource(_) = data.source else {
bail!("expected readable source for the given format (str or bytes)"); bail!("expected non-pixmap source for the given format");
}; };
ImageKind::Raster(RasterImage::new(readable.into(), format)?) ImageKind::Raster(RasterImage::new(data.derived, format)?)
} }
ImageFormat::Vector(VectorFormat::Svg) => { ImageFormat::Vector(VectorFormat::Svg) => {
let ImageSource::Readable(readable) = source else { let ImageSource::DataSource(_) = data.source else {
bail!("expected readable source for the given format (str or bytes)"); bail!("expected non-pixmap source for the given format");
}; };
ImageKind::Svg(SvgImage::new(readable.into(), options)?) ImageKind::Svg(SvgImage::new(data.derived, options)?)
} }
ImageFormat::Pixmap(format) => { ImageFormat::Pixmap(format) => {
let ImageSource::Pixmap(source) = source else { let ImageSource::Pixmap(source) = data.source else {
bail!("source must be a pixmap"); bail!("source must be a pixmap");
}; };
ImageKind::Pixmap(Pixmap::new(source, format)?) ImageKind::Pixmap(Pixmap::new(source, format)?)
@ -336,22 +336,37 @@ impl Debug for Image {
} }
} }
/// Information required to decode an image. /// Information specifying the source of an image's byte data.
#[derive(Debug, Clone, PartialEq, Hash)] #[derive(Debug, Clone, PartialEq, Hash)]
pub enum ImageSource { pub enum ImageSource {
Readable(Readable), DataSource(DataSource),
Pixmap(Arc<PixmapSource>), Pixmap(Arc<PixmapSource>),
} }
impl From<Bytes> for ImageSource { impl From<Bytes> for ImageSource {
fn from(bytes: Bytes) -> Self { fn from(bytes: Bytes) -> Self {
ImageSource::Readable(Readable::Bytes(bytes)) ImageSource::DataSource(DataSource::Bytes(bytes))
}
}
impl Load for Spanned<ImageSource> {
type Output = Bytes;
fn load(&self, world: Tracked<dyn World + '_>) -> SourceResult<Self::Output> {
match &self.v {
ImageSource::DataSource(data_source) => Spanned::new(data_source, self.span).load(world),
ImageSource::Pixmap(pixmap_source) => Ok(pixmap_source.data.clone()),
}
} }
} }
cast! { cast! {
ImageSource, ImageSource,
data: Readable => ImageSource::Readable(data), self => match self {
Self::DataSource(data) => data.into_value(),
Self::Pixmap(pixmap) => pixmap.into_value(),
},
data: DataSource => ImageSource::DataSource(data),
mut dict: Dict => { mut dict: Dict => {
let source = ImageSource::Pixmap(Arc::new(PixmapSource { let source = ImageSource::Pixmap(Arc::new(PixmapSource {
data: dict.take("data")?.cast()?, data: dict.take("data")?.cast()?,

View File

@ -3,9 +3,9 @@ use std::sync::Arc;
use image::{DynamicImage, ImageBuffer, Pixel}; use image::{DynamicImage, ImageBuffer, Pixel};
use crate::diag::{bail, StrResult}; use crate::diag::{bail, StrResult};
use crate::foundations::{Bytes, Cast}; use crate::foundations::{cast, dict, Bytes, Cast, Dict};
#[derive(Debug, PartialEq, Hash)] #[derive(Debug, Clone, PartialEq, Hash)]
pub struct PixmapSource { pub struct PixmapSource {
pub data: Bytes, pub data: Bytes,
pub pixel_width: u32, pub pixel_width: u32,
@ -13,6 +13,21 @@ pub struct PixmapSource {
pub icc_profile: Option<Bytes>, pub icc_profile: Option<Bytes>,
} }
cast! {
Arc<PixmapSource>,
self => dict!("data" => self.data.clone(), "pixel_width" => self.pixel_width, "pixel_height" => self.pixel_height, "icc_profile" => self.icc_profile.clone()).into_value(),
mut dict: Dict => {
let source = Arc::new(PixmapSource {
data: dict.take("data")?.cast()?,
pixel_width: dict.take("pixel-width")?.cast()?,
pixel_height: dict.take("pixel-height")?.cast()?,
icc_profile: dict.take("icc-profile").ok().map(|value| value.cast()).transpose()?,
});
dict.finish(&["data", "pixel-width", "pixel-height", "icc-profile"])?;
source
}
}
/// A raster image based on a flat pixmap. /// A raster image based on a flat pixmap.
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
pub struct Pixmap(Arc<Repr>); pub struct Pixmap(Arc<Repr>);

View File

@ -244,9 +244,12 @@ fn convert_bitmap_glyph_to_image(font: &Font, id: GlyphId) -> Option<(Image, f64
if raster.format != ttf_parser::RasterImageFormat::PNG { if raster.format != ttf_parser::RasterImageFormat::PNG {
return None; return None;
} }
let image = let image = Image::new(
Image::new(Bytes::new(raster.data.to_vec()).into(), RasterFormat::Png.into(), &Default::default(),) Bytes::new(raster.data.to_vec()).into(),
.ok()?; RasterFormat::Png.into(),
&Default::default(),
)
.ok()?;
Some((image, raster.x as f64, raster.y as f64)) Some((image, raster.x as f64, raster.y as f64))
} }