mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 10:47:11 -06:00
Merge pull request #2647 from dotCooCoo/fix/too-large-note-counts-rgba
Images: the too-large note counts the image's pixels as RGBA
This commit is contained in:
@@ -448,10 +448,10 @@ pub(super) fn new_from_template(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
/// that default: wasm32 has 4 GB to address and aborts when an allocation fails.
|
||||
pub(crate) use vectorcraft_doc::MAX_RASTER_ALLOC;
|
||||
|
||||
/// What to say of encoded image `bytes` that need more than [`MAX_RASTER_ALLOC`] to decode (its
|
||||
/// header says so; the pixels aren't read): the renderer, which has the same allowance, draws
|
||||
/// nothing for them, so Open, Place and the Links panel say it (#1479). `None` for images that
|
||||
/// decode, and for bytes that aren't an image.
|
||||
/// What to say of encoded image `bytes` that need more than [`MAX_RASTER_ALLOC`] to decode,
|
||||
/// counted as RGBA (4 bytes a pixel) or as the decoder gives them when that is more (its header
|
||||
/// says so; the pixels aren't read): Open, Place and the Links panel say it (#1479). `None` for
|
||||
/// images within the allowance, and for bytes that aren't an image.
|
||||
pub(crate) fn too_large_note(bytes: &[u8]) -> Option<String> {
|
||||
use image::ImageDecoder as _;
|
||||
if let Some((w, h)) = vectorcraft_doc::cmyk::oversized_tiff(bytes) {
|
||||
@@ -459,7 +459,10 @@ pub(crate) fn too_large_note(bytes: &[u8]) -> Option<String> {
|
||||
}
|
||||
let d = image::ImageReader::new(Cursor::new(bytes)).with_guessed_format().ok()?.into_decoder().ok()?;
|
||||
let (w, h) = d.dimensions();
|
||||
(d.total_bytes() > MAX_RASTER_ALLOC).then(|| format!("an image of {w} × {h} pixels is too large to draw"))
|
||||
// The allowance also counts the pixels as RGBA: an image of fewer than 4 bytes a pixel (gray,
|
||||
// gray with alpha, RGB) takes more than the decoder counts (#1717).
|
||||
let rgba_over = u64::from(w) * u64::from(h) > MAX_RASTER_ALLOC / 4;
|
||||
(rgba_over || d.total_bytes() > MAX_RASTER_ALLOC).then(|| format!("an image of {w} × {h} pixels is too large to draw"))
|
||||
}
|
||||
|
||||
/// Decode an image's header (and, for formats stored as PNG, its pixels). CMYK TIFFs are kept as
|
||||
|
||||
@@ -49,6 +49,36 @@ fn an_image_too_large_to_draw_is_reported() {
|
||||
assert_eq!(crate::cmd::fileio::load("wall.png", &png_header(200_000, 200_000)).unwrap().warnings, [NOTE]);
|
||||
assert!(crate::cmd::fileio::load("fine.png", &png_header(16_000, 16_000)).unwrap().warnings.is_empty());
|
||||
}
|
||||
|
||||
/// A gray image is counted as RGBA, 4 bytes a pixel: 23,171 × 23,170 1-bit pixels decode to 537 MB
|
||||
/// of gray and are 2,147,488,280 bytes as RGBA, past the 2 GiB allowance; 23,170 × 23,170 are
|
||||
/// 2,147,395,600 bytes, within it.
|
||||
#[test]
|
||||
fn a_gray_image_too_large_as_rgba_is_reported_on_place() {
|
||||
const NOTE: &str = "an image of 23171 × 23170 pixels is too large to draw";
|
||||
let dir = Folder::new("huge-gray-place");
|
||||
let (over, within) = (dir.file("over.png"), dir.file("within.png"));
|
||||
write(&over, &png_header(23_171, 23_170));
|
||||
write(&within, &png_header(23_170, 23_170));
|
||||
let mut s = session();
|
||||
assert_eq!(run(&mut s, "file.place", json!({"path": over, "at": [200, 150], "link": false}))["warnings"], json!([NOTE]));
|
||||
assert_eq!(run(&mut s, "file.place", json!({"path": within, "at": [20, 20], "link": false}))["warnings"], json!([]));
|
||||
let l = run(&mut s, "links.list", json!({}));
|
||||
let notes: Vec<&Value> = l["links"].as_array().unwrap().iter().map(|r| &r["note"]).collect();
|
||||
assert_eq!(notes, [&Value::Null, &json!(NOTE)], "top first: the image within the allowance has nothing to say");
|
||||
}
|
||||
|
||||
/// File › Open says the same of a gray image past the allowance as RGBA, and nothing of one within it.
|
||||
#[test]
|
||||
fn a_gray_image_too_large_as_rgba_is_reported_on_open() {
|
||||
let dir = Folder::new("huge-gray-open");
|
||||
let (over, within) = (dir.file("over.png"), dir.file("within.png"));
|
||||
write(&over, &png_header(23_171, 23_170));
|
||||
write(&within, &png_header(23_170, 23_170));
|
||||
let mut s = session();
|
||||
assert_eq!(open(&mut s, &over)["warnings"], json!(["an image of 23171 × 23170 pixels is too large to draw"]));
|
||||
assert_eq!(open(&mut s, &within)["warnings"], json!([]));
|
||||
}
|
||||
fn close(a: f64, b: f64) -> bool {
|
||||
(a - b).abs() < 1e-6
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user