mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-03 06:30:00 -06:00
Envelopes: Anti-Alias and Preserve Shape Using change how distorted images draw
Envelope Options stored Anti-Alias and Preserve Shape Using, but nothing that draws an image read them: a distorted image was always smoothed and always cut into clip groups. - With Anti-Alias off, each piece of a distorted image is marked pixelated (saved as `pixelated`). The renderer draws it with nearest-neighbor sampling and without mips, SVG export writes `image-rendering: pixelated`, and PDF export writes it without /Interpolate. - With Preserve Shape Using Transparency, each piece is the image with a white opacity mask in the piece's shape instead of a clip group. The renderer paints an image whose mask is one plain white path straight into that path, as it does for an image in a clip group, when the path lies inside the image's frame. Docs: docs/mcp.md, docs/target-app-parity.md.
This commit is contained in:
@@ -4,17 +4,21 @@ use super::{BlendMode, Exporter, Image, NodeKind, Rect, Size, Surface};
|
||||
impl Exporter<'_> {
|
||||
/// Image `im` placed `size` points wide and high, resampled and compressed as the Compression
|
||||
/// settings say ([`crate::images::recode`], [`crate::images::recode_cmyk`] for CMYK images);
|
||||
/// cached by key (and size when images are resampled). `None`, with [`UNDECODED`] among the
|
||||
/// warnings, for an image that is missing, can't be decoded or is in [`Self::left_out`].
|
||||
fn load_image(&mut self, im: &vectorcraft_doc::ImageObject, size: (f64, f64)) -> Option<Image> {
|
||||
/// cached by key (and size when images are resampled). With `interpolate` (and the export's
|
||||
/// own setting), viewers may smooth it. `None`, with [`UNDECODED`] among the warnings, for an
|
||||
/// image that is missing, can't be decoded or is in [`Self::left_out`].
|
||||
fn load_image(&mut self, im: &vectorcraft_doc::ImageObject, size: (f64, f64), interpolate: bool) -> Option<Image> {
|
||||
let key = im.key.as_str();
|
||||
let c = self.compression;
|
||||
let sized = [c.color.downsample, c.gray.downsample, c.mono.downsample].iter().any(|d| *d != crate::Downsample::None);
|
||||
let cache = if sized { format!("{key}\u{0}{:.3}x{:.3}", size.0, size.1) } else { key.to_string() };
|
||||
let interpolate = interpolate && self.interpolate;
|
||||
let mut cache = if sized { format!("{key}\u{0}{:.3}x{:.3}", size.0, size.1) } else { key.to_string() };
|
||||
if !interpolate && self.interpolate {
|
||||
cache.push_str("\u{0}pixelated");
|
||||
}
|
||||
if let Some(i) = self.images.get(&cache) {
|
||||
return i.clone();
|
||||
}
|
||||
let interpolate = self.interpolate;
|
||||
let doc = self.doc;
|
||||
let out = self.out.clone();
|
||||
let img = doc.image_blob(im).filter(|_| !self.left_out.contains(key)).and_then(|blob| {
|
||||
@@ -70,13 +74,14 @@ impl Exporter<'_> {
|
||||
img
|
||||
}
|
||||
|
||||
/// Draw image `im`: `img` when given (its pixels already written), else as it is loaded.
|
||||
pub(super) fn image(&mut self, s: &mut Surface, im: &vectorcraft_doc::ImageObject, img: Option<Image>) {
|
||||
/// Draw image `im`: `img` when given (its pixels already written), else as it is loaded; with
|
||||
/// `pixelated` ([`vectorcraft_doc::NodeExtras::pixelated`]) viewers are asked not to smooth it.
|
||||
pub(super) fn image(&mut self, s: &mut Surface, im: &vectorcraft_doc::ImageObject, img: Option<Image>, pixelated: bool) {
|
||||
// An image placed or sized beyond [`MAX_COORD`] is left out.
|
||||
if !writable(s, im.xf, Rect::new(0.0, 0.0, im.width.max(1).into(), im.height.max(1).into())) {
|
||||
return;
|
||||
}
|
||||
let Some(img) = img.or_else(|| self.load_image(im, placed_size(im))) else { return };
|
||||
let Some(img) = img.or_else(|| self.load_image(im, placed_size(im), !pixelated)) else { return };
|
||||
let Some(size) = Size::from_wh(im.width.max(1) as f32, im.height.max(1) as f32) else { return };
|
||||
s.push_transform(&xf(im.xf));
|
||||
s.draw_image(img, size);
|
||||
|
||||
@@ -182,7 +182,7 @@ impl Exporter<'_> {
|
||||
self.shape(s, n, &bp, *rule, page);
|
||||
}
|
||||
NodeKind::Text(t) => self.text(s, n, t, page),
|
||||
NodeKind::Image(im) => self.image(s, im, alpha),
|
||||
NodeKind::Image(im) => self.image(s, im, alpha, n.extras().pixelated),
|
||||
NodeKind::SymbolInstance { symbol, xf } => {
|
||||
// Within the objects a frame may draw of symbol instances, as on screen: nested
|
||||
// instances multiply.
|
||||
|
||||
Reference in New Issue
Block a user