Merge branch 'pr-495' into batch/t5

# Conflicts:
#	contributors/people.toml
This commit is contained in:
bflatastic
2026-10-16 01:35:28 +07:00
2 changed files with 66 additions and 2 deletions
+13 -2
View File
@@ -665,8 +665,19 @@ fn screenshot(b: &mut dyn Backend, a: &Map<String, Value>) -> Result<ToolResult,
let side = (x1 - x0).max(y1 - y0).max(1e-6);
scale = scale.min(max / side);
}
let bytes = b.render_png(&ids, scale)?;
let (w, h) = png_info(&bytes);
let mut bytes = b.render_png(&ids, scale)?;
let (mut w, mut h) = png_info(&bytes);
// Layer bounds leave out effects (shadows) and overflow of unclipped frames, but the render
// includes them: shrink to the measured image until it fits `maxSize` (rounding can add a pixel).
for _ in 0..4 {
let side = f64::from(w.max(h));
if side <= max {
break;
}
scale *= max / side;
bytes = b.render_png(&ids, scale)?;
(w, h) = png_info(&bytes);
}
Ok(ToolResult::image(
&bytes,
"image/png",
@@ -0,0 +1,53 @@
//! `screenshot` with `ids` must honour `maxSize` for the rendered paint area (shadows, overflow).
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod common;
use common::{Client, png_dims};
use serde_json::{Value, json};
fn dimensions(client: &mut Client, args: Value) -> (u32, u32) {
let result = client.call("screenshot", args);
assert_eq!(result["isError"], false, "{result}");
let size = png_dims(result["content"][0]["data"].as_str().unwrap());
let meta: Value = serde_json::from_str(result["content"][1]["text"].as_str().unwrap()).unwrap();
assert_eq!(meta["width"], size.0, "{meta}");
assert_eq!(meta["height"], size.1, "{meta}");
size
}
#[test]
fn layer_screenshots_fit_the_requested_size() {
let mut shadow_client = Client::new();
let shadow = shadow_client.create(json!({
"type": "rectangle", "x": 0, "y": 0,
"width": 100, "height": 100,
"props": {"effects": [{
"type": "dropShadow", "color": "#00000080",
"offset": [0, 40], "radius": 60
}]}
}));
let shadow_size = dimensions(&mut shadow_client, json!({"ids": [shadow], "maxSize": 100}));
let mut frame_client = Client::new();
let frame = frame_client.create(json!({
"type": "frame", "x": 0, "y": 0,
"width": 100, "height": 100, "props": {"clip": false}
}));
frame_client.create(json!({
"type": "rectangle", "parent": frame,
"x": 900, "y": 900, "width": 100, "height": 100
}));
let frame_size = dimensions(&mut frame_client, json!({"ids": [frame], "maxSize": 100}));
assert!(shadow_size.0 <= 100 && shadow_size.1 <= 100, "shadow screenshot exceeds maxSize: {shadow_size:?}");
assert!(shadow_size.0 >= 90 && shadow_size.1 >= 90, "shadow screenshot shrank too far: {shadow_size:?}");
assert!(frame_size.0 <= 100 && frame_size.1 <= 100, "frame screenshot exceeds maxSize: {frame_size:?}");
assert!(frame_size.0 >= 90 && frame_size.1 >= 90, "frame screenshot shrank too far: {frame_size:?}");
}
#[test]
fn plain_layer_screenshot_sizes_are_unchanged() {
let mut client = Client::new();
let rect = client.create(json!({"type": "rectangle", "x": 0, "y": 0, "width": 100, "height": 100}));
assert_eq!(dimensions(&mut client, json!({"ids": [rect], "maxSize": 100})), (100, 100));
assert_eq!(dimensions(&mut client, json!({"ids": [rect], "scale": 2})), (200, 200));
}