mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-28 11:47:21 -06:00
Type: emoji go with type that effects reshape and Expand Appearance
Squashed from #3879 onto main.
This commit is contained in:
@@ -264,6 +264,7 @@ fn art_bounds_take_in_the_effects_of_groups_type_and_images() {
|
||||
xf: vectorcraft_geom::Affine::translate((20.0, 50.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
};
|
||||
let image = Node::new(d.alloc_id(), NodeKind::Image(Box::new(im)));
|
||||
let cut_off: Vec<_> = [("group", group), ("type", text), ("image", image)]
|
||||
|
||||
+18
-4
@@ -2964,8 +2964,15 @@ mod tests {
|
||||
let mut d = Document::new(100.0, 100.0);
|
||||
// A PNG signature with nothing after it.
|
||||
d.images.insert("cut".into(), ImageBlob::new("image/png", b"\x89PNG\r\n\x1a\n".to_vec()));
|
||||
let im =
|
||||
ImageObject { key: "cut".into(), width: 40, height: 40, xf: Affine::translate((30.0, 30.0)), link: None, placement: Default::default() };
|
||||
let im = ImageObject {
|
||||
key: "cut".into(),
|
||||
width: 40,
|
||||
height: 40,
|
||||
xf: Affine::translate((30.0, 30.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
};
|
||||
let mut n = Node::new(d.alloc_id(), NodeKind::Image(Box::new(im)));
|
||||
n.appearance.effects = vec![Effect { id: "blur.gaussian".into(), params: json!({"radius": 4.0}), visible: true }];
|
||||
d.insert(Some(d.layers[0].id), 0, n).unwrap();
|
||||
@@ -2989,8 +2996,15 @@ mod tests {
|
||||
let mut d = Document::new(100.0, 100.0);
|
||||
// A PNG signature with nothing after it.
|
||||
d.images.insert("cut".into(), ImageBlob::new("image/png", b"\x89PNG\r\n\x1a\n".to_vec()));
|
||||
let im =
|
||||
ImageObject { key: "cut".into(), width: 40, height: 40, xf: Affine::translate((30.0, 30.0)), link: None, placement: Default::default() };
|
||||
let im = ImageObject {
|
||||
key: "cut".into(),
|
||||
width: 40,
|
||||
height: 40,
|
||||
xf: Affine::translate((30.0, 30.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
};
|
||||
let mut n = Node::new(d.alloc_id(), NodeKind::Image(Box::new(im)));
|
||||
n.appearance.effects = [
|
||||
("rasterize", json!({"background": "white"})),
|
||||
|
||||
@@ -410,7 +410,8 @@ mod tests {
|
||||
let mut d = Document::new_with_mode(20.0, 10.0, ColorMode::Cmyk);
|
||||
d.images.insert("img".into(), ImageBlob::cmyk_tiff(&Inks::new(2, 2, ink.repeat(4)).unwrap()).unwrap());
|
||||
let l = d.layers[0].id;
|
||||
let im = ImageObject { key: "img".into(), width: 2, height: 2, xf: Affine::scale(5.0), link: None, placement: Default::default() };
|
||||
let im =
|
||||
ImageObject { key: "img".into(), width: 2, height: 2, xf: Affine::scale(5.0), link: None, placement: Default::default(), pixels: None };
|
||||
let n = Node::new(d.alloc_id(), NodeKind::Image(Box::new(im)));
|
||||
d.insert(Some(l), 0, n).unwrap();
|
||||
// The same inks as a fill beside it.
|
||||
|
||||
+25
-18
@@ -2009,11 +2009,11 @@ impl Renderer {
|
||||
let unit = f.view * im.xf * Affine::scale_non_uniform(im.width as f64, im.height as f64);
|
||||
let shown = if outline && !f.doc.setup.outline_images {
|
||||
None
|
||||
} else if let Some(pm) = mips.then(|| self.kept_mip(f, &im.key, outline, unit)).flatten() {
|
||||
} else if let Some(pm) = mips.then(|| self.kept_mip(f, &im.key, im.pixels.as_deref(), outline, unit)).flatten() {
|
||||
Some(pm)
|
||||
} else {
|
||||
self.image_pixmap(f.doc, &im.key, outline, !mips).map(|(key, pm)| {
|
||||
let (key, pm) = if outline { (key, pm) } else { ink::ink_image(&key, &pm, f.ink, f.doc.images.get(&im.key), !mips) };
|
||||
self.image_pixmap(f.doc, &im.key, im.pixels.as_deref(), outline, !mips).map(|(key, pm)| {
|
||||
let (key, pm) = if outline { (key, pm) } else { ink::ink_image(&key, &pm, f.ink, f.doc.image_blob(im), !mips) };
|
||||
if mips { image_mip(&key, pm, unit) } else { pm }
|
||||
})
|
||||
};
|
||||
@@ -2075,15 +2075,22 @@ impl Renderer {
|
||||
self.adjusts.insert(derived, (key.to_string(), hash, map.clone()));
|
||||
}
|
||||
|
||||
/// The pixels of image `key` (a blob of `doc`, or a recoloured one named by
|
||||
/// [`Self::adjusted_image`]), or a greyscale copy of them, with their key in the shared store.
|
||||
/// `touch` marks them used there.
|
||||
fn image_pixmap(&mut self, doc: &Document, key: &str, grey: bool, touch: bool) -> Option<(images::ImageKey, Arc<Pixmap>)> {
|
||||
let (key, colour) = match doc.images.get(key) {
|
||||
/// The pixels of image `key` (`own`, the pixels an image holds itself, a blob of `doc`, or a
|
||||
/// recoloured one named by [`Self::adjusted_image`]), or a greyscale copy of them, with their
|
||||
/// key in the shared store. `touch` marks them used there.
|
||||
fn image_pixmap(
|
||||
&mut self,
|
||||
doc: &Document,
|
||||
key: &str,
|
||||
own: Option<&vectorcraft_doc::ImageBlob>,
|
||||
grey: bool,
|
||||
touch: bool,
|
||||
) -> Option<(images::ImageKey, Arc<Pixmap>)> {
|
||||
let (key, colour) = match own.or_else(|| doc.images.get(key)) {
|
||||
Some(blob) => blob_pixmap(blob, touch)?,
|
||||
None => {
|
||||
let (src, hash, map) = self.adjusts.get(key)?.clone();
|
||||
let (src_key, src) = self.image_pixmap(doc, &src, false, touch)?;
|
||||
let (src_key, src) = self.image_pixmap(doc, &src, None, false, touch)?;
|
||||
let key = images::ImageKey { adjust: Some(hash), ..src_key };
|
||||
match lookup(&key, touch) {
|
||||
Some(pm) => (key, pm),
|
||||
@@ -2122,28 +2129,28 @@ impl Renderer {
|
||||
Some((key, pm))
|
||||
}
|
||||
|
||||
/// The key [`Self::image_pixmap`] gives the pixels of image `key` and their size, without
|
||||
/// The key [`Self::image_pixmap`] gives the pixels of image `key` (or `own`) and their size, without
|
||||
/// making or looking at them: `None` until the image has been decoded.
|
||||
fn image_key(&self, doc: &Document, key: &str, grey: bool) -> Option<(images::ImageKey, (u16, u16))> {
|
||||
let (key, size) = match doc.images.get(key) {
|
||||
fn image_key(&self, doc: &Document, key: &str, own: Option<&vectorcraft_doc::ImageBlob>, grey: bool) -> Option<(images::ImageKey, (u16, u16))> {
|
||||
let (key, size) = match own.or_else(|| doc.images.get(key)) {
|
||||
Some(blob) => {
|
||||
let (key, _, size) = blob_key(blob);
|
||||
(key, size?)
|
||||
}
|
||||
None => {
|
||||
let (src, hash, _) = self.adjusts.get(key)?;
|
||||
let (src_key, size) = self.image_key(doc, src, false)?;
|
||||
let (src_key, size) = self.image_key(doc, src, None, false)?;
|
||||
(images::ImageKey { adjust: Some(*hash), ..src_key }, size)
|
||||
}
|
||||
};
|
||||
Some((if grey { images::ImageKey { grey: true, ..key } } else { key }, size))
|
||||
}
|
||||
|
||||
/// The mip [`image_mip`] draws image `key` (in greyscale with `grey`, the outline view's) with
|
||||
/// through `m` when the store holds it, marked used there; `None` when it draws the full pixels
|
||||
/// or the mip is yet to be made.
|
||||
fn kept_mip(&self, f: &Frame, key: &str, grey: bool, m: Affine) -> Option<Arc<Pixmap>> {
|
||||
let (key, (w, h)) = self.image_key(f.doc, key, grey)?;
|
||||
/// The mip [`image_mip`] draws image `key` (or `own`) with through `m`, in greyscale with
|
||||
/// `grey` (the outline view's), when the store holds it, marked used there; `None` when it
|
||||
/// draws the full pixels or the mip is yet to be made.
|
||||
fn kept_mip(&self, f: &Frame, key: &str, own: Option<&vectorcraft_doc::ImageBlob>, grey: bool, m: Affine) -> Option<Arc<Pixmap>> {
|
||||
let (key, (w, h)) = self.image_key(f.doc, key, own, grey)?;
|
||||
let key = if grey { key } else { ink::ink_key(&key, f.ink) };
|
||||
let level = mip_level(m, w, h);
|
||||
if level == 0 {
|
||||
|
||||
@@ -621,7 +621,8 @@ mod tests {
|
||||
let mut d = doc_with_pattern(TileType::Grid);
|
||||
// A PNG signature with nothing after it.
|
||||
d.images.insert("cut".into(), ImageBlob::new("image/png", b"\x89PNG\r\n\x1a\n".to_vec()));
|
||||
let im = ImageObject { key: "cut".into(), width: 10, height: 10, xf: Affine::IDENTITY, link: None, placement: Default::default() };
|
||||
let im =
|
||||
ImageObject { key: "cut".into(), width: 10, height: 10, xf: Affine::IDENTITY, link: None, placement: Default::default(), pixels: None };
|
||||
d.patterns[0].art = vec![Arc::new(Node::new(NodeId(901), NodeKind::Image(Box::new(im))))];
|
||||
let mut r = Renderer::new();
|
||||
let start = tiles_rasterized();
|
||||
|
||||
@@ -833,7 +833,7 @@ fn images_take_their_nearest_pixel_without_smoothing() {
|
||||
let mut d = Document::new(40.0, 20.0);
|
||||
d.images.insert("bw".into(), ImageBlob::new("image/png", png));
|
||||
let id = d.alloc_id();
|
||||
let im = ImageObject { key: "bw".into(), width: 2, height: 1, xf: Affine::scale(20.0), link: None, placement: Default::default() };
|
||||
let im = ImageObject { key: "bw".into(), width: 2, height: 1, xf: Affine::scale(20.0), link: None, placement: Default::default(), pixels: None };
|
||||
d.insert(Some(d.layers[0].id), 0, Node::new(id, NodeKind::Image(Box::new(im)))).unwrap();
|
||||
// How many pixels across the image are neither black nor white.
|
||||
let greys = |smooth_images| {
|
||||
@@ -905,7 +905,8 @@ fn a_gray_image_draws_its_gray_levels() {
|
||||
let mut d = Document::new(40.0, 20.0);
|
||||
d.images.insert("gray".into(), ImageBlob::new("image/png", png));
|
||||
let id = d.alloc_id();
|
||||
let im = ImageObject { key: "gray".into(), width: 2, height: 1, xf: Affine::scale(20.0), link: None, placement: Default::default() };
|
||||
let im =
|
||||
ImageObject { key: "gray".into(), width: 2, height: 1, xf: Affine::scale(20.0), link: None, placement: Default::default(), pixels: None };
|
||||
d.insert(Some(d.layers[0].id), 0, Node::new(id, NodeKind::Image(Box::new(im)))).unwrap();
|
||||
let r = Renderer::new().render(&d, 40, 20, Affine::IDENTITY, &RenderOptions { smooth_images: false, ..Default::default() });
|
||||
assert_eq!((r.pixel(5, 10), r.pixel(35, 10)), ([40, 40, 40, 255], [200, 200, 200, 255]));
|
||||
|
||||
@@ -93,6 +93,7 @@ fn an_embedded_image_is_recoloured_and_the_original_pixels_stay() {
|
||||
xf: Affine::translate((20.0, 20.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
})),
|
||||
);
|
||||
n.appearance.effects.push(hue());
|
||||
|
||||
@@ -45,3 +45,40 @@ fn outline_mode_draws_a_bitmap_glyph_as_its_box() {
|
||||
// The box's left edge at x 32.5 (the bearing of 2 px of 6.25 pt), from y 45 to 145.
|
||||
assert!((31..=34).any(|x| img.pixel(x, 100)[0] < 128), "the box's edge shows");
|
||||
}
|
||||
|
||||
/// 100 pt [`COLOUR_CHAR`] in the `CBDT` test font with `effects`, on a white 160×160 page.
|
||||
fn render_with(effects: Vec<vectorcraft_doc::Effect>) -> Rendered {
|
||||
let _adding = crate::tests_fontchange::adding_fonts();
|
||||
vectorcraft_text::FontDb::global().add_font(colour_bitmap_font(false).unwrap());
|
||||
let mut d = Document::new(160.0, 160.0);
|
||||
let st = CharStyle { font_family: colour_bitmap_family(false).into(), size: 100.0, ..Default::default() };
|
||||
let mut n = Node::new(d.alloc_id(), NodeKind::Text(Box::new(TextObject::point(Point::new(20.0, 120.0), &COLOUR_CHAR.to_string(), st))));
|
||||
let mut appearance = (*n.appearance).clone();
|
||||
appearance.effects = effects;
|
||||
n.appearance = appearance.into();
|
||||
let l = d.layers[0].id;
|
||||
d.insert(Some(l), 0, n).unwrap();
|
||||
Renderer::new().render(&d, 160, 160, Affine::IDENTITY, &RenderOptions { background: Some([255, 255, 255, 255]), ..Default::default() })
|
||||
}
|
||||
|
||||
fn effect(id: &str, params: serde_json::Value) -> vectorcraft_doc::Effect {
|
||||
vectorcraft_doc::Effect { id: id.into(), params, visible: true }
|
||||
}
|
||||
|
||||
/// Type with a geometry effect is drawn as its outlines: its emoji go with them, as images that
|
||||
/// hold their own pixels (here moved 40 pt by a Transform effect).
|
||||
#[test]
|
||||
fn bitmap_glyphs_go_with_type_that_a_geometry_effect_reshapes() {
|
||||
let img = render_with(vec![effect("distort.transform", serde_json::json!({"moveH": 40}))]);
|
||||
assert_eq!(img.pixel(110, 80), COLOUR_LARGE, "moved with the type");
|
||||
assert_eq!(img.pixel(50, 80), [255, 255, 255, 255], "not where it was");
|
||||
}
|
||||
|
||||
/// A colour adjustment leaves the emoji of reshaped type in their colours, as it does those of
|
||||
/// type, and as exports and Expand Appearance draw them.
|
||||
#[test]
|
||||
fn a_colour_adjustment_leaves_the_emoji_of_reshaped_type_as_they_are() {
|
||||
let moved = effect("distort.transform", serde_json::json!({"moveH": 40}));
|
||||
let img = render_with(vec![moved, effect("adjust.hueSaturation", serde_json::json!({"hue": 120}))]);
|
||||
assert_eq!(img.pixel(110, 80), COLOUR_LARGE);
|
||||
}
|
||||
|
||||
@@ -222,6 +222,7 @@ fn placed_images_are_separated_not_blackened() {
|
||||
xf: Affine::IDENTITY,
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
})),
|
||||
);
|
||||
add(&mut d, n);
|
||||
@@ -256,7 +257,7 @@ fn rich_black_shows_black_ink_alone_as_rgb_black() {
|
||||
let mut png = vec![];
|
||||
img.write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png).unwrap();
|
||||
d.images.insert("red".into(), ImageBlob::new("image/png", png));
|
||||
let im = ImageObject { key: "red".into(), width: 20, height: 20, xf: Affine::IDENTITY, link: None, placement: Default::default() };
|
||||
let im = ImageObject { key: "red".into(), width: 20, height: 20, xf: Affine::IDENTITY, link: None, placement: Default::default(), pixels: None };
|
||||
let n = Node::new(d.alloc_id(), NodeKind::Image(Box::new(im)));
|
||||
add(&mut d, n);
|
||||
assert_eq!(centre_with(&d, true), centre_with(&d, false), "an image shows as it is");
|
||||
|
||||
@@ -158,7 +158,15 @@ fn group_geometry_effects_move_and_copy_images_too() {
|
||||
image::RgbaImage::from_pixel(4, 4, image::Rgba([255, 0, 0, 255])).write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png).unwrap();
|
||||
d.images.insert("red".into(), ImageBlob::new("image/png", png));
|
||||
let b = rect(&mut d, Rect::new(0.0, 0.0, 20.0, 20.0), solid(0.0, 0.0, 1.0));
|
||||
let im = ImageObject { key: "red".into(), width: 30, height: 30, xf: Affine::translate((10.0, 30.0)), link: None, placement: Default::default() };
|
||||
let im = ImageObject {
|
||||
key: "red".into(),
|
||||
width: 30,
|
||||
height: 30,
|
||||
xf: Affine::translate((10.0, 30.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
};
|
||||
let image = Arc::new(Node::new(d.alloc_id(), NodeKind::Image(Box::new(im))));
|
||||
let mut g = Node::group(d.alloc_id(), vec![b, image]);
|
||||
g.appearance.effects.push(fx("distort.transform", json!({"moveH": 50, "copies": 1})));
|
||||
|
||||
@@ -27,6 +27,7 @@ fn doc(layer: impl FnOnce(&mut NodeKind)) -> Document {
|
||||
xf: Affine::translate((50.0, 10.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
})),
|
||||
);
|
||||
im.id = d.alloc_id();
|
||||
|
||||
@@ -26,7 +26,7 @@ fn doc_with_image(key: &str, bytes: Vec<u8>, w: u32, h: u32) -> Document {
|
||||
let mut d = Document::new(w as f64, h as f64);
|
||||
d.images.insert(key.into(), ImageBlob::new("image/png", bytes));
|
||||
let (id, layer) = (d.alloc_id(), d.layers[0].id);
|
||||
let im = ImageObject { key: key.into(), width: w, height: h, xf: Affine::IDENTITY, link: None, placement: Default::default() };
|
||||
let im = ImageObject { key: key.into(), width: w, height: h, xf: Affine::IDENTITY, link: None, placement: Default::default(), pixels: None };
|
||||
d.insert(Some(layer), 0, Node::new(id, NodeKind::Image(Box::new(im)))).unwrap();
|
||||
d
|
||||
}
|
||||
@@ -39,16 +39,16 @@ fn renderers_share_one_decode_of_an_image() {
|
||||
// Another document holding the same image under another key (its own copy of the bytes).
|
||||
let b = doc_with_image("photo", bytes, 16, 16);
|
||||
let (mut r1, mut r2) = (Renderer::new(), Renderer::new());
|
||||
let (k1, p1) = r1.image_pixmap(&a, "img", false, true).unwrap();
|
||||
let (k2, p2) = r2.image_pixmap(&b, "photo", false, true).unwrap();
|
||||
let (k1, p1) = r1.image_pixmap(&a, "img", None, false, true).unwrap();
|
||||
let (k2, p2) = r2.image_pixmap(&b, "photo", None, false, true).unwrap();
|
||||
assert_eq!(k1, k2);
|
||||
assert!(Arc::ptr_eq(&p1, &p2), "decoded once for both renderers");
|
||||
// Drawing goes through the store too: the pixels stay the ones decoded.
|
||||
let _ = r2.render(&b, 16, 16, Affine::IDENTITY, &RenderOptions::default());
|
||||
assert!(Arc::ptr_eq(&r1.image_pixmap(&b, "photo", false, true).unwrap().1, &p1));
|
||||
assert!(Arc::ptr_eq(&r1.image_pixmap(&b, "photo", None, false, true).unwrap().1, &p1));
|
||||
// A document using the same key for other pixels gets its own.
|
||||
let c = doc_with_image("img", png(16, 16, 102), 16, 16);
|
||||
let (k3, p3) = r1.image_pixmap(&c, "img", false, true).unwrap();
|
||||
let (k3, p3) = r1.image_pixmap(&c, "img", None, false, true).unwrap();
|
||||
assert!(k3 != k1 && !Arc::ptr_eq(&p3, &p1));
|
||||
assert!(
|
||||
r1.render(&c, 16, 16, Affine::IDENTITY, &RenderOptions::default()).pixels
|
||||
@@ -102,7 +102,7 @@ fn image_mips_are_opt_in_and_change_nothing_off() {
|
||||
// On, the quarter-size image samples the quarter-size mip: close to the full pixels' average
|
||||
// but not the same pixels.
|
||||
assert!(mipped.pixels != cold.pixels);
|
||||
let (key, _) = warm.image_pixmap(&d, "img", false, true).unwrap();
|
||||
let (key, _) = warm.image_pixmap(&d, "img", None, false, true).unwrap();
|
||||
let mip = images::store().peek(&images::ImageKey { mip: 2, ..key }).expect("quarter mip kept");
|
||||
assert_eq!((mip.width(), mip.height()), (16, 16));
|
||||
// Above half size, mips on draw the full pixels.
|
||||
@@ -122,7 +122,7 @@ fn kept_mips_draw_without_decoding_the_full_pixels_again() {
|
||||
let quarter = Affine::scale(0.25);
|
||||
let mut r = Renderer::new();
|
||||
let _ = r.render(&d, 32, 16, quarter, &on);
|
||||
let full = r.image_pixmap(&d, "img", false, false).unwrap().0;
|
||||
let full = r.image_pixmap(&d, "img", None, false, false).unwrap().0;
|
||||
images::store().remove(&full);
|
||||
// The image dragged 4 pt (a device pixel) right.
|
||||
let mut moved = d.clone();
|
||||
@@ -475,7 +475,15 @@ fn art_placed_again_in_every_frame_keeps_one_outline_per_stroke() {
|
||||
let mut d = Document::new(200.0, 100.0);
|
||||
d.images.insert("dot".into(), ImageBlob::new("image/png", png(4, 4, 108)));
|
||||
let mut art = symbol_art(&mut d);
|
||||
let im = ImageObject { key: "dot".into(), width: 4, height: 4, xf: Affine::translate((-2.0, -2.0)), link: None, placement: Default::default() };
|
||||
let im = ImageObject {
|
||||
key: "dot".into(),
|
||||
width: 4,
|
||||
height: 4,
|
||||
xf: Affine::translate((-2.0, -2.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
};
|
||||
let image = Node::new(d.alloc_id(), NodeKind::Image(Box::new(im)));
|
||||
if let Some(c) = art.children_mut() {
|
||||
c.push(Arc::new(image));
|
||||
@@ -1476,7 +1484,7 @@ fn blurred_image_doc(key: &str, seed: u8) -> Document {
|
||||
let mut d = Document::new(200.0, 100.0);
|
||||
d.images.insert(key.into(), ImageBlob::new("image/png", png(16, 16, seed)));
|
||||
let xf = Affine::translate((20.0, 10.0)) * Affine::scale(5.0);
|
||||
let im = ImageObject { key: key.into(), width: 16, height: 16, xf, link: None, placement: Default::default() };
|
||||
let im = ImageObject { key: key.into(), width: 16, height: 16, xf, link: None, placement: Default::default(), pixels: None };
|
||||
let mut n = Node::new(d.alloc_id(), NodeKind::Image(Box::new(im)));
|
||||
n.appearance.effects.push(effect("blur.gaussian", serde_json::json!({"radius": 1.0})));
|
||||
with_art(d, vec![n])
|
||||
|
||||
@@ -285,6 +285,7 @@ fn image_doc(effects: Vec<Effect>) -> Document {
|
||||
xf: Affine::translate((20.0, 20.0)),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
})),
|
||||
);
|
||||
n.appearance.effects = effects;
|
||||
|
||||
@@ -10,7 +10,7 @@ fn doc_with_red_image() -> Document {
|
||||
image::RgbaImage::from_pixel(4, 4, image::Rgba([255, 0, 0, 255])).write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png).unwrap();
|
||||
d.images.insert("red".into(), ImageBlob::new("image/png", png));
|
||||
let (id, layer) = (d.alloc_id(), d.layers[0].id);
|
||||
let im = ImageObject { key: "red".into(), width: 40, height: 40, xf: Affine::IDENTITY, link: None, placement: Default::default() };
|
||||
let im = ImageObject { key: "red".into(), width: 40, height: 40, xf: Affine::IDENTITY, link: None, placement: Default::default(), pixels: None };
|
||||
d.insert(Some(layer), 0, Node::new(id, NodeKind::Image(Box::new(im)))).unwrap();
|
||||
d
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user