Fix #839: Save for Web accepts a typed width or height

The dialog's W and H fields send decimal numbers (300.0) and the settings
wanted a whole u32, so the preview failed with "invalid type: floating
point". Pixel sizes now take any number and round it to whole pixels;
negative, huge and non-numeric sizes are still refused.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bflatasticandClaude Opus 5.5 committed 2026-10-10 10:27:52 +07:00
1 parent 021a9474f8
commit 5df4ddd4b6
2 files changed
+20

No files matched your search

+13
View File
@@ -142,6 +142,17 @@ fn de_key<'de, T: Keyed, D: Deserializer<'de>>(d: D) -> std::result::Result<T, D
T::parse(&s).ok_or_else(|| D::Error::custom(format!("`{s}`: {}", T::KEYS)))
}
/// A size in pixels: a number, rounded to whole pixels (`300.0` is 300).
fn de_pixels<'de, D: Deserializer<'de>>(d: D) -> std::result::Result<Option<u32>, D::Error> {
let Some(v) = Option::<f64>::deserialize(d)? else { return Ok(None) };
let px = v.round();
if !(px.is_finite() && px >= 0.0 && px <= f64::from(u32::MAX)) {
return Err(D::Error::custom(format!("{v} is not a size in pixels")));
}
// In range and whole: the cast is exact.
Ok(Some(px as u32))
}
/// The file format.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -361,8 +372,10 @@ pub struct WebSettings {
/// JPEG: embed the sRGB profile.
pub embed_profile: bool,
/// The image width in pixels (the height follows).
#[serde(deserialize_with = "de_pixels")]
pub width: Option<u32>,
/// The image height in pixels (the width follows).
#[serde(deserialize_with = "de_pixels")]
pub height: Option<u32>,
/// The image size in percent of the art's size in points.
pub percent: Option<f64>,
+7
View File
@@ -285,9 +285,16 @@ fn image_size_region_and_metadata() {
assert_eq!(size(&mut s, json!({"width": 80})), (80, 60));
assert_eq!(size(&mut s, json!({"height": 15})), (20, 15));
assert_eq!(size(&mut s, json!({"percent": 150})), (60, 45));
// The dialog's fields send decimal numbers: rounded to whole pixels.
assert_eq!(size(&mut s, json!({"width": 80.0})), (80, 60));
assert_eq!(size(&mut s, json!({"height": 14.6})), (20, 15));
for bad in [
json!({"percent": 0}),
json!({"width": 0}),
json!({"width": 0.2}),
json!({"width": -5}),
json!({"height": 1e300}),
json!({"height": "tall"}),
json!({"format": "bmp"}),
json!({"colors": "many"}),
json!({"matte": "plaid"}),