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_utils::LazyHash;
use crate::diag::{bail, At, SourceResult, StrResult};
use crate::diag::{bail, SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
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).
#[required]
#[parse(
let source = args.expect::<Spanned<DataSource>>("source")?;
let source = args.expect::<Spanned<ImageSource>>("source")?;
let data = source.load(engine.world)?;
Derived::new(source.v, data)
)]
pub source: Derived<DataSource, Bytes>,
pub source: Derived<ImageSource, Bytes>,
/// The image's format. Detected automatically by default.
///
@ -124,7 +124,7 @@ impl ImageElem {
pub fn decode(
span: Span,
/// 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.
#[named]
format: Option<Smart<ImageFormat>>,
@ -148,7 +148,7 @@ impl ImageElem {
scaling: Option<ImageScaling>,
) -> StrResult<Content> {
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);
if let Some(format) = format {
elem.push_format(format);
@ -240,25 +240,25 @@ impl Image {
#[comemo::memoize]
#[typst_macros::time(name = "load image")]
pub fn new(
source: ImageSource,
data: Derived<ImageSource, Bytes>,
format: ImageFormat,
options: &ImageOptions,
) -> StrResult<Image> {
let kind = match format {
ImageFormat::Raster(format) => {
let ImageSource::Readable(readable) = source else {
bail!("expected readable source for the given format (str or bytes)");
let ImageSource::DataSource(_) = data.source else {
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) => {
let ImageSource::Readable(readable) = source else {
bail!("expected readable source for the given format (str or bytes)");
let ImageSource::DataSource(_) = data.source else {
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) => {
let ImageSource::Pixmap(source) = source else {
let ImageSource::Pixmap(source) = data.source else {
bail!("source must be a pixmap");
};
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)]
pub enum ImageSource {
Readable(Readable),
DataSource(DataSource),
Pixmap(Arc<PixmapSource>),
}
impl From<Bytes> for ImageSource {
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! {
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 => {
let source = ImageSource::Pixmap(Arc::new(PixmapSource {
data: dict.take("data")?.cast()?,

View File

@ -3,9 +3,9 @@ use std::sync::Arc;
use image::{DynamicImage, ImageBuffer, Pixel};
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 data: Bytes,
pub pixel_width: u32,
@ -13,6 +13,21 @@ pub struct PixmapSource {
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.
#[derive(Clone, Hash)]
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 {
return None;
}
let image =
Image::new(Bytes::new(raster.data.to_vec()).into(), RasterFormat::Png.into(), &Default::default(),)
.ok()?;
let image = Image::new(
Bytes::new(raster.data.to_vec()).into(),
RasterFormat::Png.into(),
&Default::default(),
)
.ok()?;
Some((image, raster.x as f64, raster.y as f64))
}