mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 09:59:47 -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:
@@ -90,12 +90,64 @@ pub(crate) fn plain_image(n: &Node, im: &vectorcraft_doc::ImageObject, region: &
|
||||
if !(n.visible && n.has_default_transparency() && n.appearance.items.is_empty() && n.appearance.effects.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
inside_frame(im, region, 1.0)
|
||||
}
|
||||
|
||||
/// Is `region` inside image `im`'s frame (within `slack` pixels)?
|
||||
fn inside_frame(im: &vectorcraft_doc::ImageObject, region: &BezPath, slack: f64) -> bool {
|
||||
let det = im.xf.determinant();
|
||||
if !(det.abs() > 1e-12 && det.is_finite()) {
|
||||
return false;
|
||||
}
|
||||
let b = im.xf.inverse().transform_rect_bbox(region.bounding_box());
|
||||
b.x0 >= -1.0 && b.y0 >= -1.0 && b.x1 <= im.width as f64 + 1.0 && b.y1 <= im.height as f64 + 1.0
|
||||
b.x0 >= -slack && b.y0 >= -slack && b.x1 <= im.width as f64 + slack && b.y1 <= im.height as f64 + slack
|
||||
}
|
||||
|
||||
/// Can image node `n` (`im`), whose opacity mask is one plain white path with Clip on (see
|
||||
/// [`white_shape_mask`]) shaped like `region`, be painted straight into the region: the mask shows
|
||||
/// the image fully inside the shape and hides it outside, as a clipping path does. The region must
|
||||
/// lie inside the image's frame, since outside the frame the mask shows nothing.
|
||||
pub(crate) fn shape_masked_image(n: &Node, im: &vectorcraft_doc::ImageObject, region: &BezPath) -> bool {
|
||||
n.visible
|
||||
&& n.opacity >= 1.0
|
||||
&& n.blend == vectorcraft_color::BlendMode::Normal
|
||||
&& !n.isolate
|
||||
&& n.knockout == vectorcraft_doc::Knockout::Neutral
|
||||
&& !n.knockout_shape
|
||||
&& n.appearance.items.is_empty()
|
||||
&& n.appearance.effects.is_empty()
|
||||
&& inside_frame(im, region, 1e-6)
|
||||
}
|
||||
|
||||
/// Is opacity mask `m` one path filled with opaque white and nothing else, with Clip on and
|
||||
/// Invert off (each piece of an envelope's distorted image with Preserve Shape Using
|
||||
/// Transparency)?
|
||||
pub(crate) fn white_shape_mask(m: &vectorcraft_doc::OpacityMask) -> bool {
|
||||
use vectorcraft_color::{BlendMode, Color, Paint};
|
||||
let a = &m.art;
|
||||
let shows = |p: &Paint| !matches!(p, Paint::None);
|
||||
let white = |p: &Paint| matches!(p, Paint::Solid { color, tint, .. } if *color == Color::WHITE && *tint >= 1.0);
|
||||
let mut fills = 0;
|
||||
for i in &a.appearance.items {
|
||||
match i {
|
||||
AppearanceItem::Fill(f) if f.visible && shows(&f.paint) => {
|
||||
if !(white(&f.paint) && f.opacity >= 1.0 && f.blend == BlendMode::Normal && f.effects.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
fills += 1;
|
||||
}
|
||||
AppearanceItem::Stroke(s) if s.visible && shows(&s.paint) => return false,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
m.clip
|
||||
&& !m.invert
|
||||
&& !m.disabled
|
||||
&& fills == 1
|
||||
&& a.visible
|
||||
&& a.has_default_transparency()
|
||||
&& a.appearance.effects.is_empty()
|
||||
&& matches!(a.kind, NodeKind::Path { guide: false, .. })
|
||||
}
|
||||
|
||||
/// Opacity-mask coverage of one premultiplied pixel: luminance, with the area outside the mask
|
||||
|
||||
Reference in New Issue
Block a user