mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-08 03:41:28 +00:00
Clipboard: leave out the PNG of art too large to scale to 4096 pixels
Copy scaled its PNG down to fit 4096 pixels a side but never below 0.01 pixels a point, so art over 409,600 pt across produced a PNG far past that side, up to the general raster export limit of a gigabyte of pixels, on an ordinary copy. Such art now gets no PNG flavour.
This commit is contained in:
committed by
bflatastic
parent
400a49666a
commit
15cd642be8
@@ -125,6 +125,8 @@ pub struct Flavour {
|
||||
|
||||
/// Longest side (px) of the PNG Copy offers: larger art is scaled down to fit.
|
||||
const COPY_PNG_SIDE: f64 = 4096.0;
|
||||
/// The smallest scale (pixels a point) the PNG encoder renders at.
|
||||
const MIN_COPY_PNG_SCALE: f64 = 0.01;
|
||||
/// Most bytes of text `clipboard.importText` takes.
|
||||
const MAX_TEXT: usize = 1 << 20;
|
||||
/// Most bytes of images the SVG markup may embed and still go out as plain text. A paste reads the
|
||||
@@ -293,7 +295,8 @@ impl Clipboard {
|
||||
|
||||
/// What Copy offers other apps, best first, with Include SVG Code (`svg`) and On Copy: PDF
|
||||
/// (`pdf`) as given (see `clipboard.flavours`). A [`Flavour`] that can't be made (art too large
|
||||
/// to render) is left out; the PNG is scaled down to at most [`COPY_PNG_SIDE`] pixels a side.
|
||||
/// to render) is left out; the PNG is scaled down to at most [`COPY_PNG_SIDE`] pixels a side, and
|
||||
/// left out when even [`MIN_COPY_PNG_SCALE`] can't bring it that small.
|
||||
pub fn flavours(&self, svg: bool, pdf: bool) -> Vec<Flavour> {
|
||||
self.flavours_with_warnings(svg, pdf).0
|
||||
}
|
||||
@@ -320,7 +323,14 @@ impl Clipboard {
|
||||
PDF => self.pdf().inspect_err(|e| log::warn!("clipboard PDF: {e}")).ok().flatten().map(&mut keep),
|
||||
_ => {
|
||||
let side = self.bounds().map_or(1.0, |b| b.width().max(b.height()));
|
||||
let scale = (COPY_PNG_SIDE / side).clamp(0.01, 1.0);
|
||||
let scale = (COPY_PNG_SIDE / side).min(1.0);
|
||||
// The encoder renders at no fewer than MIN_COPY_PNG_SCALE pixels a point: art
|
||||
// too large to fit COPY_PNG_SIDE at that scale gets no PNG, rather than one
|
||||
// of up to a gigabyte of pixels.
|
||||
if !(scale >= MIN_COPY_PNG_SCALE) {
|
||||
log::warn!("clipboard PNG: art {side} pt across is too large to copy as a picture");
|
||||
continue;
|
||||
}
|
||||
self.png(scale).inspect_err(|e| log::warn!("clipboard PNG: {e}")).ok().flatten().map(|(png, _, _, notes)| keep((png, notes)))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -350,6 +350,25 @@ fn type_only_copies_offer_their_text() {
|
||||
assert!(run(&mut s, "clipboard.exportText", json!({}))["text"].is_null());
|
||||
}
|
||||
|
||||
/// Art too large to fit the clipboard's PNG side at the encoder's smallest scale gets no PNG,
|
||||
/// instead of a picture hundreds of megabytes large.
|
||||
#[test]
|
||||
fn copy_leaves_out_the_png_of_art_too_large_to_scale_down() {
|
||||
let mut s = session();
|
||||
let id = run(&mut s, "shape.rectangle", json!({"x": 0, "y": 0, "width": 1_000_000, "height": 1_000_000}))["id"].clone();
|
||||
run(&mut s, "select.set", json!({"ids": [id]}));
|
||||
run(&mut s, "edit.copy", json!({}));
|
||||
assert!(s.clipboard.flavour_types(false, false).contains(&PNG));
|
||||
assert!(s.clipboard.flavours(false, false).iter().all(|f| f.mime != PNG));
|
||||
// Art that fits at that scale still gets its PNG, at most 4096 pixels a side.
|
||||
let id = run(&mut s, "shape.rectangle", json!({"x": 0, "y": 0, "width": 200_000, "height": 100}))["id"].clone();
|
||||
run(&mut s, "select.set", json!({"ids": [id]}));
|
||||
run(&mut s, "edit.copy", json!({}));
|
||||
let png = s.clipboard.flavours(false, false).into_iter().find(|f| f.mime == PNG).expect("a PNG");
|
||||
let img = image::load_from_memory(&png.data).unwrap();
|
||||
assert!(img.width() <= 4096 && img.height() <= 4096, "{}x{}", img.width(), img.height());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_offers_flavours_by_the_preferences() {
|
||||
let mut s = session();
|
||||
|
||||
Reference in New Issue
Block a user