mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 21:14:18 +00:00
EPS import: an image's transient data stops counting against the memory budget
The sample planes an image is decoded from, and the strings a procedure data source hands back to fill them, are freed once the image is decoded, so they stop counting against the 1 GiB budget then; the pixels kept still count. A file of many images whose procedure returns one large buffer each time no longer runs out of budget.
This commit is contained in:
@@ -657,8 +657,12 @@ impl Interp<'_> {
|
||||
return ps_err("rangecheck", "DataSource");
|
||||
}
|
||||
let plane = row.checked_mul(s.h).filter(|p| *p <= MAX_DATA).ok_or(PsError::Limit("decoded data is too large"))?;
|
||||
// The planes and the strings a procedure gives to fill them live only while the image is
|
||||
// decoded: they stop counting once it is (the pixels made from them still count).
|
||||
let before = self.allocated();
|
||||
self.alloc(plane.saturating_mul(sources.len()))?;
|
||||
let mut planes = self.read_sources(sources, row * s.h, if multi { row } else { row * s.h })?;
|
||||
let transient = self.allocated().saturating_sub(before);
|
||||
for p in &mut planes {
|
||||
p.resize(row * s.h, 0);
|
||||
}
|
||||
@@ -734,6 +738,8 @@ impl Interp<'_> {
|
||||
rgba.extend([rgb[0], rgb[1], rgb[2], if masked { 0 } else { 255 }]);
|
||||
}
|
||||
}
|
||||
drop(planes);
|
||||
self.unalloc(transient);
|
||||
Ok(Some(Pixels { w: s.w as u32, h: s.h as u32, rgba, inks, matrix: s.matrix }))
|
||||
}
|
||||
|
||||
|
||||
@@ -341,6 +341,17 @@ impl<'a> Interp<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The bytes counted against [`MAX_MEMORY`] so far.
|
||||
pub(crate) fn allocated(&self) -> usize {
|
||||
self.allocated
|
||||
}
|
||||
|
||||
/// Stop counting `bytes` the program no longer holds: buffers that lived only while one
|
||||
/// operator ran, freed when it returned.
|
||||
pub(crate) fn unalloc(&mut self, bytes: usize) {
|
||||
self.allocated = self.allocated.saturating_sub(bytes);
|
||||
}
|
||||
|
||||
fn tick(&mut self) -> Res {
|
||||
self.spend(1)
|
||||
}
|
||||
|
||||
@@ -1381,6 +1381,20 @@ fn the_planes_of_multi_source_images_are_charged() {
|
||||
assert!(r.warnings.iter().any(|w| w.contains("too much memory")), "{:?}", r.warnings);
|
||||
}
|
||||
|
||||
/// The planes an image is decoded from, and the strings a procedure gives to fill them, stop
|
||||
/// counting against the memory budget once the image is decoded: they are freed then. A procedure
|
||||
/// that hands back one large buffer for every image (1 MiB here, for a one-pixel image) charged the
|
||||
/// whole buffer each time, and a file of many images came in as its preview.
|
||||
#[test]
|
||||
fn an_images_transient_data_is_not_charged_after_it() {
|
||||
let body = "/buf 1048576 string def\n1100 { 1 1 8 [1 0 0 1 0 0] { buf } image } repeat\n";
|
||||
let r = import(&eps(body)).unwrap();
|
||||
assert!(!r.warnings.iter().any(|w| w.contains("too much memory")), "{:?}", r.warnings);
|
||||
let mut images = 0;
|
||||
r.document.walk(|n| images += usize::from(matches!(n.kind, NodeKind::Image(_))));
|
||||
assert_eq!(images, 1100);
|
||||
}
|
||||
|
||||
/// #3568: a single sample plane over the data limit is refused.
|
||||
#[test]
|
||||
fn an_oversized_image_plane_is_refused() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# File format parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-06 · **Change:** minor (SVG import: filter and mask regions clip, #5876, #5875; SVG import: Gaussian blurs keep `color-interpolation-filters`, #5877; PDF and `.ai` export: objects' URLs as links, #5785; SVG import: `color-interpolation="linearRGB"` gradients, #5878; `.ai` import: paths with a Calligraphic brush open brushed, #372) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-06 · **Change:** minor (EPS import: an image's transient data stops counting against the memory budget once it is decoded; SVG import: filter and mask regions clip, #5876, #5875; SVG import: Gaussian blurs keep `color-interpolation-filters`, #5877; PDF and `.ai` export: objects' URLs as links, #5785; SVG import: `color-interpolation="linearRGB"` gradients, #5878; `.ai` import: paths with a Calligraphic brush open brushed, #372) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Every format Illustrator opens, places, saves or exports, against VectorCraft's format table (`FORMATS`,
|
||||
`OPEN_EXTS`, `PLACE_EXTS` in `crates/engine/src/cmd/fileio/formats.rs`). Illustrator's list comes from its public
|
||||
@@ -191,6 +191,7 @@ the app's own editing copy of a file (an EPS after its `%%EOF`, a `.ai`'s `AIPri
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-06 | minor | EPS import: the buffers an image is decoded from (its sample planes, and the strings a procedure data source hands back to fill them) stop counting against the PostScript reader's 1 GiB memory budget once the image is decoded, as they are freed then; the pixels kept still count. A user's Illustrator 25.2 EPS with 71 CMYK images (used locally, not committed) used to stop with "the program uses too much memory" and come in as its screen preview; it now opens with its art. The budget itself is unchanged. Scores and estimates unchanged. |
|
||||
| 2026-11-06 | minor | SVG import: filter and mask regions clip (SVG 1.1 §15.5, §14.4). An object whose imported blur, shadow or glow reaches past its filter's region comes in inside a clip group cut to the region (#5876), and a mask's art is cut to the mask's region, in user space or the object's bounding box (#5875). Objects that fit their regions, and our own exports, are unchanged; primitive subregions are still ignored. Tests `import_live::a_blur_is_cut_at_its_filter_region`, `import_live::a_mask_counts_only_inside_its_region` (crate `vectorcraft-svg`); scores unchanged |
|
||||
| 2026-11-06 | minor | SVG import: a Gaussian blur keeps the colour space its filter asks for with `color-interpolation-filters` (initially `linearRGB`, SVG 1.1 §15.7.6): a linear-light blur becomes Gaussian Blur with the new `linear` parameter, which blurs the colours in linear light (black beside white meets at about 188/255 instead of 128), and SVG export writes it back on the `feGaussianBlur` (#5877). Blurs that ask for sRGB, and the blurs our own export writes, are as before. CSS export still writes `blur()`. Tests `pixel::tests::linear_light_blur_mixes_light_not_values` (crate `vectorcraft-effects`), `import_live::a_gaussian_blur_keeps_its_colour_space` (crate `vectorcraft-svg`); scores unchanged |
|
||||
| 2026-11-06 | minor | PDF export and PDF-compatible `.ai` saves write each object's URL (Attributes panel) as a link annotation with a URI action (web and mail URLs only) over the bounds of the object that shows, trimmed by its clipping groups (ISO 32000-1, 12.5.6.5 and 12.6.4.7); hidden objects, layers that don't print and prints have none, and PDF/X files leave them out with a warning (#5785). Own-fixture tests in `tests::links`; PDF import doesn't read links back as URLs yet; scores unchanged |
|
||||
|
||||
Reference in New Issue
Block a user