summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bench/src/bench.rs23
-rw-r--r--src/env.rs75
-rw-r--r--src/eval/mod.rs12
-rw-r--r--src/export/pdf.rs26
-rw-r--r--src/font.rs6
-rw-r--r--src/layout/mod.rs14
-rw-r--r--src/layout/text.rs4
-rw-r--r--src/lib.rs16
-rw-r--r--src/library/insert.rs66
-rw-r--r--src/main.rs13
-rw-r--r--tests/typeset.rs49
11 files changed, 189 insertions, 115 deletions
diff --git a/bench/src/bench.rs b/bench/src/bench.rs
index bc13ed01..c232d4bf 100644
--- a/bench/src/bench.rs
+++ b/bench/src/bench.rs
@@ -4,6 +4,7 @@ use std::rc::Rc;
use criterion::{criterion_group, criterion_main, Criterion};
use fontdock::fs::{FsIndex, FsSource};
+use typst::env::{Env, ResourceLoader};
use typst::eval::{eval, State};
use typst::export::pdf;
use typst::font::FontLoader;
@@ -25,23 +26,25 @@ fn benchmarks(c: &mut Criterion) {
index.search_dir(FONT_DIR);
let (files, descriptors) = index.into_vecs();
- let loader = Rc::new(RefCell::new(FontLoader::new(
- Box::new(FsSource::new(files)),
- descriptors,
- )));
+ let env = Rc::new(RefCell::new(Env {
+ fonts: FontLoader::new(Box::new(FsSource::new(files)), descriptors),
+ resources: ResourceLoader::new(),
+ }));
// Prepare intermediate results and run warm.
let state = State::default();
let tree = parse(COMA).output;
- let document = eval(&tree, state.clone()).output;
- let layouts = layout(&document, Rc::clone(&loader));
+ let document = eval(&tree, Rc::clone(&env), state.clone()).output;
+ let layouts = layout(&document, Rc::clone(&env));
// Bench!
bench!("parse-coma": parse(COMA));
- bench!("eval-coma": eval(&tree, state.clone()));
- bench!("layout-coma": layout(&document, Rc::clone(&loader)));
- bench!("typeset-coma": typeset(COMA, state.clone(), Rc::clone(&loader)));
- bench!("export-pdf-coma": pdf::export(&layouts, &loader.borrow()));
+ bench!("eval-coma": eval(&tree, Rc::clone(&env), state.clone()));
+ bench!("layout-coma": layout(&document, Rc::clone(&env)));
+ bench!("typeset-coma": typeset(COMA, Rc::clone(&env), state.clone()));
+
+ let env = env.borrow();
+ bench!("export-pdf-coma": pdf::export(&layouts, &env));
}
criterion_group!(benches, benchmarks);
diff --git a/src/env.rs b/src/env.rs
new file mode 100644
index 00000000..eba0e59b
--- /dev/null
+++ b/src/env.rs
@@ -0,0 +1,75 @@
+//! Environment interactions.
+
+use std::any::Any;
+use std::cell::RefCell;
+use std::collections::{hash_map::Entry, HashMap};
+use std::fmt::{self, Debug, Formatter};
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::rc::Rc;
+
+use crate::font::FontLoader;
+
+/// A reference-counted shared environment.
+pub type SharedEnv = Rc<RefCell<Env>>;
+
+/// Encapsulates all environment dependencies (fonts, resources).
+#[derive(Debug)]
+pub struct Env {
+ /// Loads fonts from a dynamic font source.
+ pub fonts: FontLoader,
+ /// Loads resource from the file system.
+ pub resources: ResourceLoader,
+}
+
+/// Loads resource from the file system.
+pub struct ResourceLoader {
+ paths: HashMap<PathBuf, ResourceId>,
+ entries: Vec<Box<dyn Any>>,
+}
+
+/// A unique identifier for a resource.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct ResourceId(usize);
+
+impl ResourceLoader {
+ /// Create a new resource loader.
+ pub fn new() -> Self {
+ Self { paths: HashMap::new(), entries: vec![] }
+ }
+
+ /// Load a resource from a path.
+ pub fn load<R: 'static>(
+ &mut self,
+ path: impl AsRef<Path>,
+ parse: impl FnOnce(Vec<u8>) -> Option<R>,
+ ) -> Option<(ResourceId, &R)> {
+ let path = path.as_ref();
+ let id = match self.paths.entry(path.to_owned()) {
+ Entry::Occupied(entry) => *entry.get(),
+ Entry::Vacant(entry) => {
+ let id = *entry.insert(ResourceId(self.entries.len()));
+ let data = fs::read(path).ok()?;
+ let resource = parse(data)?;
+ self.entries.push(Box::new(resource));
+ id
+ }
+ };
+
+ Some((id, self.get_loaded(id)))
+ }
+
+ /// Retrieve a previously loaded resource by its id.
+ ///
+ /// # Panics
+ /// This panics if no resource with this id was loaded.
+ pub fn get_loaded<R: 'static>(&self, id: ResourceId) -> &R {
+ self.entries[id.0].downcast_ref().expect("bad resource type")
+ }
+}
+
+impl Debug for ResourceLoader {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ f.debug_set().entries(self.paths.keys()).finish()
+ }
+}
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index c45e46ae..4cfebd3e 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -22,6 +22,7 @@ use fontdock::FontStyle;
use crate::diag::Diag;
use crate::diag::{Deco, Feedback, Pass};
+use crate::env::SharedEnv;
use crate::geom::{BoxAlign, Dir, Flow, Gen, Length, Linear, Relative, Sides, Size};
use crate::layout::{
Document, Expansion, LayoutNode, Pad, Pages, Par, Softness, Spacing, Stack, Text,
@@ -30,10 +31,10 @@ use crate::syntax::*;
/// Evaluate a syntax tree into a document.
///
-/// The given `state` the base state that may be updated over the course of
+/// The given `state` is the base state that may be updated over the course of
/// evaluation.
-pub fn eval(tree: &SynTree, state: State) -> Pass<Document> {
- let mut ctx = EvalContext::new(state);
+pub fn eval(tree: &SynTree, env: SharedEnv, state: State) -> Pass<Document> {
+ let mut ctx = EvalContext::new(env, state);
ctx.start_page_group(false);
tree.eval(&mut ctx);
ctx.end_page_group();
@@ -43,6 +44,8 @@ pub fn eval(tree: &SynTree, state: State) -> Pass<Document> {
/// The context for evaluation.
#[derive(Debug)]
pub struct EvalContext {
+ /// The environment from which resources are gathered.
+ pub env: SharedEnv,
/// The active evaluation state.
pub state: State,
/// The accumulated feedback.
@@ -62,8 +65,9 @@ pub struct EvalContext {
impl EvalContext {
/// Create a new evaluation context with a base state.
- pub fn new(state: State) -> Self {
+ pub fn new(env: SharedEnv, state: State) -> Self {
Self {
+ env,
state,
groups: vec![],
inner: vec![],
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index af3ca0a6..43237dc7 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -3,14 +3,14 @@
use std::collections::HashMap;
use fontdock::FaceId;
-use image::RgbImage;
+use image::{DynamicImage, GenericImageView};
use pdf_writer::{
CidFontType, ColorSpace, Content, FontFlags, Name, PdfWriter, Rect, Ref, Str,
SystemInfo, UnicodeCmap,
};
use ttf_parser::{name_id, GlyphId};
-use crate::font::FontLoader;
+use crate::env::{Env, ResourceId};
use crate::geom::Length;
use crate::layout::{BoxLayout, LayoutElement};
@@ -21,14 +21,14 @@ use crate::layout::{BoxLayout, LayoutElement};
/// included in the _PDF_.
///
/// Returns the raw bytes making up the _PDF_ document.
-pub fn export(layouts: &[BoxLayout], loader: &FontLoader) -> Vec<u8> {
- PdfExporter::new(layouts, loader).write()
+pub fn export(layouts: &[BoxLayout], env: &Env) -> Vec<u8> {
+ PdfExporter::new(layouts, env).write()
}
struct PdfExporter<'a> {
writer: PdfWriter,
layouts: &'a [BoxLayout],
- loader: &'a FontLoader,
+ env: &'a Env,
/// We need to know exactly which indirect reference id will be used for
/// which objects up-front to correctly declare the document catalogue, page
/// tree and so on. These offsets are computed in the beginning and stored
@@ -41,13 +41,13 @@ struct PdfExporter<'a> {
/// Backwards from the pdf indices to the old face ids.
fonts_to_layout: Vec<FaceId>,
/// The already visited images.
- images: Vec<&'a RgbImage>,
+ images: Vec<ResourceId>,
/// The total number of images.
image_count: usize,
}
impl<'a> PdfExporter<'a> {
- fn new(layouts: &'a [BoxLayout], loader: &'a FontLoader) -> Self {
+ fn new(layouts: &'a [BoxLayout], env: &'a Env) -> Self {
let mut writer = PdfWriter::new(1, 7);
writer.set_indent(2);
@@ -75,7 +75,7 @@ impl<'a> PdfExporter<'a> {
Self {
writer,
layouts,
- loader,
+ env,
refs,
fonts_to_pdf,
fonts_to_layout,
@@ -185,7 +185,7 @@ impl<'a> PdfExporter<'a> {
content.x_object(Name(name.as_bytes()));
content.restore_state();
- self.images.push(&image.buf);
+ self.images.push(image.resource);
}
}
@@ -194,7 +194,7 @@ impl<'a> PdfExporter<'a> {
fn write_fonts(&mut self) {
for (refs, &face_id) in self.refs.fonts().zip(&self.fonts_to_layout) {
- let owned_face = self.loader.get_loaded(face_id);
+ let owned_face = self.env.fonts.get_loaded(face_id);
let face = owned_face.get();
let name = face
@@ -302,9 +302,11 @@ impl<'a> PdfExporter<'a> {
}
fn write_images(&mut self) {
- for (id, image) in self.refs.images().zip(&self.images) {
+ for (id, &resource) in self.refs.images().zip(&self.images) {
+ let image = self.env.resources.get_loaded::<DynamicImage>(resource);
+ let data = image.to_rgb8().into_raw();
self.writer
- .image_stream(id, &image.as_raw())
+ .image_stream(id, &data)
.width(image.width() as i32)
.height(image.height() as i32)
.color_space(ColorSpace::DeviceRGB)
diff --git a/src/font.rs b/src/font.rs
index 513c31f1..68a2db67 100644
--- a/src/font.rs
+++ b/src/font.rs
@@ -1,14 +1,8 @@
//! Font handling.
-use std::cell::RefCell;
-use std::rc::Rc;
-
use fontdock::{ContainsChar, FaceFromVec, FontSource};
use ttf_parser::Face;
-/// A reference-counted shared font loader backed by a dynamic font source.
-pub type SharedFontLoader = Rc<RefCell<FontLoader>>;
-
/// A font loader backed by a dynamic source.
pub type FontLoader = fontdock::FontLoader<Box<DynSource>>;
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 28b27899..1f7d6c9f 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -8,9 +8,7 @@ mod spacing;
mod stack;
mod text;
-use image::RgbImage;
-
-use crate::font::SharedFontLoader;
+use crate::env::{ResourceId, SharedEnv};
use crate::geom::*;
use crate::shaping::Shaped;
@@ -23,16 +21,16 @@ pub use stack::*;
pub use text::*;
/// Layout a document and return the produced layouts.
-pub fn layout(document: &Document, loader: SharedFontLoader) -> Vec<BoxLayout> {
- let mut ctx = LayoutContext { loader };
+pub fn layout(document: &Document, env: SharedEnv) -> Vec<BoxLayout> {
+ let mut ctx = LayoutContext { env };
document.layout(&mut ctx)
}
/// The context for layouting.
#[derive(Debug, Clone)]
pub struct LayoutContext {
- /// The font loader to query fonts from when typesetting text.
- pub loader: SharedFontLoader,
+ /// The environment from which fonts are gathered.
+ pub env: SharedEnv,
}
/// Layout a node.
@@ -185,7 +183,7 @@ pub enum LayoutElement {
#[derive(Debug, Clone, PartialEq)]
pub struct ImageElement {
/// The image.
- pub buf: RgbImage,
+ pub resource: ResourceId,
/// The document size of the image.
pub size: Size,
}
diff --git a/src/layout/text.rs b/src/layout/text.rs
index fc319fa5..56b2328e 100644
--- a/src/layout/text.rs
+++ b/src/layout/text.rs
@@ -25,10 +25,10 @@ pub struct Text {
impl Layout for Text {
fn layout(&self, ctx: &mut LayoutContext, _: &Areas) -> Layouted {
- let mut loader = ctx.loader.borrow_mut();
+ let mut env = ctx.env.borrow_mut();
Layouted::Layout(
shaping::shape(
- &mut loader,
+ &mut env.fonts,
&self.text,
self.dir,
self.font_size,
diff --git a/src/lib.rs b/src/lib.rs
index 7d54da4c..d471b09d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,6 +29,7 @@ pub mod diag;
#[macro_use]
pub mod eval;
pub mod color;
+pub mod env;
pub mod export;
pub mod font;
pub mod geom;
@@ -40,19 +41,18 @@ pub mod prelude;
pub mod shaping;
pub mod syntax;
+use std::rc::Rc;
+
use crate::diag::{Feedback, Pass};
+use crate::env::SharedEnv;
use crate::eval::State;
-use crate::font::SharedFontLoader;
use crate::layout::BoxLayout;
/// Process _Typst_ source code directly into a collection of layouts.
-pub fn typeset(
- src: &str,
- state: State,
- loader: SharedFontLoader,
-) -> Pass<Vec<BoxLayout>> {
+pub fn typeset(src: &str, env: SharedEnv, state: State) -> Pass<Vec<BoxLayout>> {
let Pass { output: tree, feedback: f1 } = parse::parse(src);
- let Pass { output: document, feedback: f2 } = eval::eval(&tree, state);
- let layouts = layout::layout(&document, loader);
+ let Pass { output: document, feedback: f2 } =
+ eval::eval(&tree, Rc::clone(&env), state);
+ let layouts = layout::layout(&document, env);
Pass::new(layouts, Feedback::join(f1, f2))
}
diff --git a/src/library/insert.rs b/src/library/insert.rs
index 2904c958..b2cdc255 100644
--- a/src/library/insert.rs
+++ b/src/library/insert.rs
@@ -1,10 +1,9 @@
-use std::fmt::{self, Debug, Formatter};
-use std::fs::File;
-use std::io::BufReader;
+use std::io::Cursor;
use image::io::Reader;
-use image::RgbImage;
+use image::GenericImageView;
+use crate::env::ResourceId;
use crate::layout::*;
use crate::prelude::*;
@@ -20,25 +19,27 @@ pub fn image(mut args: Args, ctx: &mut EvalContext) -> Value {
let height = args.get::<_, Linear>(ctx, "height");
if let Some(path) = path {
- if let Ok(file) = File::open(path.v) {
- match Reader::new(BufReader::new(file))
+ let mut env = ctx.env.borrow_mut();
+ let loaded = env.resources.load(path.v, |data| {
+ Reader::new(Cursor::new(data))
.with_guessed_format()
- .map_err(|err| err.into())
- .and_then(|reader| reader.decode())
- .map(|img| img.into_rgb8())
- {
- Ok(buf) => {
- ctx.push(Image {
- buf,
- width,
- height,
- align: ctx.state.align,
- });
- }
- Err(err) => ctx.diag(error!(path.span, "invalid image: {}", err)),
- }
+ .ok()
+ .and_then(|reader| reader.decode().ok())
+ });
+
+ if let Some((resource, buf)) = loaded {
+ let dimensions = buf.dimensions();
+ drop(env);
+ ctx.push(Image {
+ resource,
+ dimensions,
+ width,
+ height,
+ align: ctx.state.align,
+ });
} else {
- ctx.diag(error!(path.span, "failed to open image file"));
+ drop(env);
+ ctx.diag(error!(path.span, "failed to load image"));
}
}
@@ -46,10 +47,12 @@ pub fn image(mut args: Args, ctx: &mut EvalContext) -> Value {
}
/// An image node.
-#[derive(Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq)]
struct Image {
- /// The image.
- buf: RgbImage,
+ /// The resource id of the image file.
+ resource: ResourceId,
+ /// The pixel dimensions of the image.
+ dimensions: (u32, u32),
/// The fixed width, if any.
width: Option<Linear>,
/// The fixed height, if any.
@@ -61,8 +64,7 @@ struct Image {
impl Layout for Image {
fn layout(&self, _: &mut LayoutContext, areas: &Areas) -> Layouted {
let Area { rem, full } = areas.current;
- let (pixel_width, pixel_height) = self.buf.dimensions();
- let pixel_ratio = (pixel_width as f64) / (pixel_height as f64);
+ let pixel_ratio = (self.dimensions.0 as f64) / (self.dimensions.1 as f64);
let width = self.width.map(|w| w.resolve(full.width));
let height = self.height.map(|w| w.resolve(full.height));
@@ -85,23 +87,13 @@ impl Layout for Image {
let mut boxed = BoxLayout::new(size);
boxed.push(
Point::ZERO,
- LayoutElement::Image(ImageElement { buf: self.buf.clone(), size }),
+ LayoutElement::Image(ImageElement { resource: self.resource, size }),
);
Layouted::Layout(boxed, self.align)
}
}
-impl Debug for Image {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.debug_struct("Image")
- .field("width", &self.width)
- .field("height", &self.height)
- .field("align", &self.align)
- .finish()
- }
-}
-
impl From<Image> for LayoutNode {
fn from(image: Image) -> Self {
Self::dynamic(image)
diff --git a/src/main.rs b/src/main.rs
index 715ee59f..3f12655b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,6 +7,7 @@ use anyhow::{anyhow, bail, Context};
use fontdock::fs::{FsIndex, FsSource};
use typst::diag::{Feedback, Pass};
+use typst::env::{Env, ResourceLoader};
use typst::eval::State;
use typst::export::pdf;
use typst::font::FontLoader;
@@ -41,16 +42,16 @@ fn main() -> anyhow::Result<()> {
index.search_os();
let (files, descriptors) = index.into_vecs();
- let loader = Rc::new(RefCell::new(FontLoader::new(
- Box::new(FsSource::new(files)),
- descriptors,
- )));
+ let env = Rc::new(RefCell::new(Env {
+ fonts: FontLoader::new(Box::new(FsSource::new(files)), descriptors),
+ resources: ResourceLoader::new(),
+ }));
let state = State::default();
let Pass {
output: layouts,
feedback: Feedback { mut diags, .. },
- } = typeset(&src, state, Rc::clone(&loader));
+ } = typeset(&src, Rc::clone(&env), state);
if !diags.is_empty() {
diags.sort();
@@ -71,7 +72,7 @@ fn main() -> anyhow::Result<()> {
}
}
- let pdf_data = pdf::export(&layouts, &loader.borrow());
+ let pdf_data = pdf::export(&layouts, &env.borrow());
fs::write(&dest_path, pdf_data).context("Failed to write PDF file.")?;
Ok(())
diff --git a/tests/typeset.rs b/tests/typeset.rs
index d9a1056a..82d801a2 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -6,6 +6,7 @@ use std::path::Path;
use std::rc::Rc;
use fontdock::fs::{FsIndex, FsSource};
+use image::{DynamicImage, GenericImageView, Rgba};
use memmap::Mmap;
use tiny_skia::{
Canvas, Color, ColorU8, FillRule, FilterQuality, Paint, PathBuilder, Pattern, Pixmap,
@@ -14,9 +15,10 @@ use tiny_skia::{
use ttf_parser::OutlineBuilder;
use typst::diag::{Feedback, Pass};
+use typst::env::{Env, ResourceLoader, SharedEnv};
use typst::eval::State;
use typst::export::pdf;
-use typst::font::{FontLoader, SharedFontLoader};
+use typst::font::FontLoader;
use typst::geom::{Length, Point};
use typst::layout::{BoxLayout, ImageElement, LayoutElement};
use typst::parse::LineMap;
@@ -67,16 +69,16 @@ fn main() {
index.search_dir(FONT_DIR);
let (files, descriptors) = index.into_vecs();
- let loader = Rc::new(RefCell::new(FontLoader::new(
- Box::new(FsSource::new(files)),
- descriptors,
- )));
+ let env = Rc::new(RefCell::new(Env {
+ fonts: FontLoader::new(Box::new(FsSource::new(files)), descriptors),
+ resources: ResourceLoader::new(),
+ }));
let mut ok = true;
for (name, src_path, pdf_path, png_path, ref_path) in filtered {
print!("Testing {}.", name);
- test(&src_path, &pdf_path, &png_path, &loader);
+ test(&src_path, &pdf_path, &png_path, &env);
let png_file = File::open(&png_path).unwrap();
let ref_file = match File::open(&ref_path) {
@@ -104,13 +106,13 @@ fn main() {
}
}
-fn test(src_path: &Path, pdf_path: &Path, png_path: &Path, loader: &SharedFontLoader) {
+fn test(src_path: &Path, pdf_path: &Path, png_path: &Path, env: &SharedEnv) {
let src = fs::read_to_string(src_path).unwrap();
let state = State::default();
let Pass {
output: layouts,
feedback: Feedback { mut diags, .. },
- } = typeset(&src, state, Rc::clone(loader));
+ } = typeset(&src, Rc::clone(env), state);
if !diags.is_empty() {
diags.sort();
@@ -131,12 +133,11 @@ fn test(src_path: &Path, pdf_path: &Path, png_path: &Path, loader: &SharedFontLo
}
}
- let loader = loader.borrow();
-
- let canvas = draw(&layouts, &loader, 2.0);
+ let env = env.borrow();
+ let canvas = draw(&layouts, &env, 2.0);
canvas.pixmap.save_png(png_path).unwrap();
- let pdf_data = pdf::export(&layouts, &loader);
+ let pdf_data = pdf::export(&layouts, &env);
fs::write(pdf_path, pdf_data).unwrap();
}
@@ -170,7 +171,7 @@ impl TestFilter {
}
}
-fn draw(layouts: &[BoxLayout], loader: &FontLoader, pixel_per_pt: f32) -> Canvas {
+fn draw(layouts: &[BoxLayout], env: &Env, pixel_per_pt: f32) -> Canvas {
let pad = Length::pt(5.0);
let height = pad + layouts.iter().map(|l| l.size.height + pad).sum::<Length>();
@@ -207,9 +208,11 @@ fn draw(layouts: &[BoxLayout], loader: &FontLoader, pixel_per_pt: f32) -> Canvas
let pos = origin + pos;
match element {
LayoutElement::Text(shaped) => {
- draw_text(&mut canvas, loader, shaped, pos)
+ draw_text(&mut canvas, pos, env, shaped);
+ }
+ LayoutElement::Image(image) => {
+ draw_image(&mut canvas, pos, env, image);
}
- LayoutElement::Image(image) => draw_image(&mut canvas, image, pos),
}
}
@@ -219,8 +222,8 @@ fn draw(layouts: &[BoxLayout], loader: &FontLoader, pixel_per_pt: f32) -> Canvas
canvas
}
-fn draw_text(canvas: &mut Canvas, loader: &FontLoader, shaped: &Shaped, pos: Point) {
- let face = loader.get_loaded(shaped.face).get();
+fn draw_text(canvas: &mut Canvas, pos: Point, env: &Env, shaped: &Shaped) {
+ let face = env.fonts.get_loaded(shaped.face).get();
for (&glyph, &offset) in shaped.glyphs.iter().zip(&shaped.offsets) {
let units_per_em = face.units_per_em().unwrap_or(1000);
@@ -244,11 +247,13 @@ fn draw_text(canvas: &mut Canvas, loader: &FontLoader, shaped: &Shaped, pos: Poi
}
}
-fn draw_image(canvas: &mut Canvas, image: &ImageElement, pos: Point) {
- let mut pixmap = Pixmap::new(image.buf.width(), image.buf.height()).unwrap();
- for (src, dest) in image.buf.pixels().zip(pixmap.pixels_mut()) {
- let [r, g, b] = src.0;
- *dest = ColorU8::from_rgba(r, g, b, 255).premultiply();
+fn draw_image(canvas: &mut Canvas, pos: Point, env: &Env, image: &ImageElement) {
+ let buf = env.resources.get_loaded::<DynamicImage>(image.resource);
+
+ let mut pixmap = Pixmap::new(buf.width(), buf.height()).unwrap();
+ for ((_, _, src), dest) in buf.pixels().zip(pixmap.pixels_mut()) {
+ let Rgba([r, g, b, a]) = src;
+ *dest = ColorU8::from_rgba(r, g, b, a).premultiply();
}
let view_width = image.size.width.to_pt() as f32;