mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 10:17:02 -06:00
Merge pull request #2964 from dotCooCoo/fix/pdfinfo-thumbnail-page
MCP: document.pdfInfo refuses a thumbnail that is not a page number
This commit is contained in:
@@ -183,15 +183,22 @@ pub(super) fn pdf_info(_: &mut Session, p: &Value) -> Result<Value> {
|
||||
})
|
||||
.collect();
|
||||
let mut out = json!({"pages": pages.len(), "needsPassword": false, "pageInfo": pages});
|
||||
if let Some(n) = p.get("thumbnail").and_then(Value::as_u64) {
|
||||
let page = usize::try_from(n).ok().and_then(|n| n.checked_sub(1)).filter(|i| *i < info.pages.len());
|
||||
let page = page.ok_or_else(|| bad(INFO, format!("thumbnail: no page {n} (the PDF has {})", info.pages.len())))?;
|
||||
if let Some(page) = thumbnail_page(p, info.pages.len(), "PDF")? {
|
||||
let (doc, _) = page_document(&bytes, page, &o)?;
|
||||
out["thumbnail"] = json!(thumbnail(&doc, p)?);
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// The page (0-based) `document.pdfInfo`'s `thumbnail` names, from 1 to `count`; `None` when it is
|
||||
/// absent or null. Any other value (0, a negative or fractional number, a string) is an error that
|
||||
/// names the pages the `what` has.
|
||||
fn thumbnail_page(p: &Value, count: usize, what: &str) -> Result<Option<usize>> {
|
||||
let Some(v) = p.get("thumbnail").filter(|v| !v.is_null()) else { return Ok(None) };
|
||||
let page = v.as_u64().and_then(|n| usize::try_from(n).ok()).and_then(|n| n.checked_sub(1)).filter(|i| *i < count);
|
||||
page.map(Some).ok_or_else(|| bad(INFO, format!("thumbnail: no page {v} (the {what} has {count})")))
|
||||
}
|
||||
|
||||
/// `document.pdfInfo` of a PostScript file (an EPS, a `.ps` file, a `.ai` in PostScript form): one
|
||||
/// page, the page [`vectorcraft_eps::page`] reads, with no PDF boxes. Its thumbnail is the file as
|
||||
/// the EPS reader reads it without any editing data it carries: what the page prints, or the
|
||||
@@ -200,10 +207,7 @@ fn postscript_info(bytes: &[u8], p: &Value) -> Result<Value> {
|
||||
let page = vectorcraft_eps::page(bytes).map_err(err)?;
|
||||
let info = json!({"width": page.width(), "height": page.height(), "rotation": 0, "boxes": {}});
|
||||
let mut out = json!({"pages": 1, "needsPassword": false, "pageInfo": [info]});
|
||||
if let Some(n) = p.get("thumbnail").and_then(Value::as_u64) {
|
||||
if n != 1 {
|
||||
return Err(bad(INFO, format!("thumbnail: no page {n} (the file has 1)")));
|
||||
}
|
||||
if thumbnail_page(p, 1, "file")?.is_some() {
|
||||
let doc = vectorcraft_eps::import_with(bytes, false).map_err(err)?.document;
|
||||
out["thumbnail"] = json!(thumbnail(&doc, p)?);
|
||||
}
|
||||
|
||||
@@ -228,6 +228,27 @@ fn pdf_info_reads_postscript_as_one_page() {
|
||||
assert!(e.contains("no page 2"), "{e}");
|
||||
}
|
||||
|
||||
/// `document.pdfInfo`'s `thumbnail` is a page number from 1, for a PDF and for PostScript alike:
|
||||
/// any other value is an error that names the pages, and an absent or null one gives no thumbnail.
|
||||
#[test]
|
||||
fn pdf_info_refuses_a_thumbnail_that_is_not_a_page_number() {
|
||||
let ps = b"%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 100 50\n%%EndComments\n0 0 1 setrgbcolor 0 0 50 20 rectfill\n";
|
||||
let mut s = Session::new();
|
||||
for (bytes, pages) in [(&three_pages()[..], "(the PDF has 3)"), (ps, "(the file has 1)")] {
|
||||
for n in [json!(-1), json!(0), json!(1.5), json!("1"), json!(true)] {
|
||||
let e = s.execute("document.pdfInfo", &json!({"dataBase64": b64(bytes), "thumbnail": n})).unwrap_err().to_string();
|
||||
assert!(e.contains(&format!("thumbnail: no page {n} {pages}")), "{n}: {e}");
|
||||
}
|
||||
for none in [json!({"dataBase64": b64(bytes)}), json!({"dataBase64": b64(bytes), "thumbnail": null})] {
|
||||
assert!(s.execute("document.pdfInfo", &none).unwrap().get("thumbnail").is_none(), "{pages}");
|
||||
}
|
||||
let v = s.execute("document.pdfInfo", &json!({"dataBase64": b64(bytes), "thumbnail": 1, "thumbnailSize": 64})).unwrap();
|
||||
let png = vectorcraft_format::base64_decode(v["thumbnail"].as_str().unwrap()).unwrap();
|
||||
let img = image::load_from_memory(&png).unwrap();
|
||||
assert_eq!(img.width().max(img.height()), 64, "{pages}");
|
||||
}
|
||||
}
|
||||
|
||||
/// A page showing only text, with an editor's private data when `private`.
|
||||
fn text_page(private: bool, also: &str) -> PdfPage {
|
||||
PdfPage {
|
||||
|
||||
Reference in New Issue
Block a user