M10: odd and even pages are page numbers, as Acrobat counts them (#3984) (#4034)

* M10: odd and even pages are page numbers, as Acrobat counts them (#3984)

Even pages only with the range 4–11 printed pages 5, 7, 9 and 11: `narrow` took odd and
even places in the chosen pages, and its comment said Acrobat does the same. Acrobat
counts page numbers: "if you set the range to 2, 7–10 and choose Even Pages Only, only
pages 2, 8, and 10 print" (Adobe Acrobat DC Help, last updated 11/28/2019, Options in the
Print dialog box, p. 515; the same example in Using Adobe Acrobat 9 Pro, p. 413). Odd and
even now keep the pages whose number is odd or even, for a typed range, picked thumbnails
and the current page alike, in the order given, and Reverse turns that round. The header,
footer and watermark ranges (marks_ui) and Extract's odd/even filter in #3729 already
count page numbers.

The new test pins Acrobat's example and the report's ranges. select_listed's tests and
cut_stack_printing_through_tools counted places; the latter now asks for even pages of
2–10, which by page number are the 2, 4, 6, 8 and 10 it printed before, so its expected
output is unchanged and would fail with places (3, 5, 7, 9).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M10: say that odd and even are page numbers in doc_print, and what page labels still lack (#3984)

Review on #4034: the doc_print description says odd/even count page numbers, and the parity note says a document with page labels still counts page numbers there, which the Acrobat help consulted doesn't settle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* M10: cite the cut-stack print test at its path under tests/it (#3984)

main moved the automation integration tests into tests/it, so the
evidence path added for odd/even printing no longer existed and
`cargo xtask parity` failed after the rebase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mtlcl410
2026-10-23 10:42:02 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 71efe25d02
commit 4825b67d15
5 changed files with 39 additions and 11 deletions
+1 -1
View File
@@ -527,7 +527,7 @@ pub fn tools() -> Vec<ToolDef> {
t(
"doc_print",
"Print",
"Print with Acrobat's Print dialog options, or save the print-ready PDF. pages: a range such as \"1-3, 6, 9-\" (page labels allowed; default all); subset odd/even; reverse. layout: fit (default), actual, shrink, custom (scale %), multiple (per_sheet 2/4/6/9/16, order, border, auto_rotate; cut-stack order arranges single-sided sheets for cutting into piles and stacking left to right, top to bottom, keeping sheet order within each pile; duplex must be off), booklet (booklet_subset both/front/back, binding left/right), poster (scale %, overlap pt, cut_marks). orientation auto/portrait/landscape; comments_forms document / document-and-markups (default) / document-and-stamps / form-fields-only; paper Letter/Legal/Tabloid, ARCH A/B/C/D/E1/E, ANSI C/D/E, A0/A1/A2/A3/A4/A5/A6, or US #10 Envelope (short names or full preset labels); use layout actual for 100% in the print-ready PDF; printer drivers may still substitute paper or scale. Then path (save) or printer (a name or \"default\") with copies, collate, duplex off/long-edge/short-edge, grayscale, and options (driver options from printer_options, CUPS).",
"Print with Acrobat's Print dialog options, or save the print-ready PDF. pages: a range such as \"1-3, 6, 9-\" (page labels allowed; default all); subset odd/even (by page number, as Acrobat counts them: pages 2, 7-10 with even prints 2, 8 and 10, not every second page of the range); reverse. layout: fit (default), actual, shrink, custom (scale %), multiple (per_sheet 2/4/6/9/16, order, border, auto_rotate; cut-stack order arranges single-sided sheets for cutting into piles and stacking left to right, top to bottom, keeping sheet order within each pile; duplex must be off), booklet (booklet_subset both/front/back, binding left/right), poster (scale %, overlap pt, cut_marks). orientation auto/portrait/landscape; comments_forms document / document-and-markups (default) / document-and-stamps / form-fields-only; paper Letter/Legal/Tabloid, ARCH A/B/C/D/E1/E, ANSI C/D/E, A0/A1/A2/A3/A4/A5/A6, or US #10 Envelope (short names or full preset labels); use layout actual for 100% in the print-ready PDF; printer drivers may still substitute paper or scale. Then path (save) or printer (a name or \"default\") with copies, collate, duplex off/long-edge/short-edge, grayscale, and options (driver options from printer_options, CUPS).",
)
.with(schema(
json!({
+3 -1
View File
@@ -6422,7 +6422,9 @@ fn cut_stack_printing_through_tools() {
&mut a,
"doc_print",
json!({
"doc": doc, "pages": "2-10", "subset": "odd", "reverse": true,
// Even pages by page number (#3984): 2, 4, 6, 8 and 10 (counting places in the range,
// "even" would have been 3, 5, 7 and 9).
"doc": doc, "pages": "2-10", "subset": "even", "reverse": true,
"layout": "multiple", "order": "cut-stack", "per_sheet": 2, "auto_rotate": false,
"orientation": "landscape", "path": "range.pdf"
}),
+10 -5
View File
@@ -45,8 +45,8 @@ fn hyphenated_label_range(part: &str, count: usize, labels: &[String]) -> Option
}
/// The pages to print (0-based, in print order). `range` is `None` for all pages; it may list
/// numbers and labels with `-` ranges (open-ended allowed: `5-`, `-3`). The subset counts the
/// selected pages (the first selected is "odd"), as Acrobat does.
/// numbers and labels with `-` ranges (open-ended allowed: `5-`, `-3`). The subset keeps the odd or
/// even pages of those chosen, by page number (see [`narrow`]).
pub fn select_pages(count: usize, range: Option<&str>, labels: &[String], subset: Subset, reverse: bool) -> Result<Vec<usize>, PrintError> {
let mut pages = Vec::new();
match range.map(str::trim).filter(|r| !r.is_empty()) {
@@ -95,12 +95,17 @@ pub fn select_listed(count: usize, pages: &[usize], subset: Subset, reverse: boo
narrow(pages.to_vec(), subset, reverse)
}
/// Odd or even positions of the chosen pages, then the print order.
/// The odd or even pages of those chosen, by page number (the first page of the document is 1,
/// odd; `pages` are 0-based), then the print order. Acrobat counts the same way (#3984): "if you
/// set the range to 2, 7–10 and choose Even Pages Only, only pages 2, 8, and 10 print" (Adobe
/// Acrobat DC Help, last updated 11/28/2019, Options in the Print dialog box, p. 515; the same
/// example in Using Adobe Acrobat 9 Pro, p. 413). Counting places in the range instead printed
/// 7 and 9 there, and a range starting on an even page started its "even" pages on an odd one.
fn narrow(pages: Vec<usize>, subset: Subset, reverse: bool) -> Result<Vec<usize>, PrintError> {
let mut out: Vec<usize> = match subset {
Subset::All => pages,
Subset::Odd => pages.into_iter().step_by(2).collect(),
Subset::Even => pages.into_iter().skip(1).step_by(2).collect(),
Subset::Odd => pages.into_iter().filter(|p| p % 2 == 0).collect(),
Subset::Even => pages.into_iter().filter(|p| p % 2 == 1).collect(),
};
if reverse {
out.reverse();
+23 -2
View File
@@ -71,8 +71,10 @@ fn page_selection() {
assert_eq!(select_pages(1, None, &[], Subset::Even, false), Err(PrintError::NoPages));
// An explicit list (selected thumbnails): positions, never labels, in the order given.
assert_eq!(select_listed(5, &[1, 3], Subset::All, false).unwrap(), [1, 3]);
assert_eq!(select_listed(5, &[0, 2, 4], Subset::Even, false).unwrap(), [2]);
assert_eq!(select_listed(5, &[0, 2, 4], Subset::Odd, true).unwrap(), [4, 0]);
// Picked pages keep their page numbers: pages 1, 3 and 5 are all odd.
assert_eq!(select_listed(5, &[0, 2, 4], Subset::Even, false), Err(PrintError::NoPages));
assert_eq!(select_listed(5, &[0, 2, 4], Subset::Odd, true).unwrap(), [4, 2, 0]);
assert_eq!(select_listed(5, &[1, 2, 3], Subset::Even, false).unwrap(), [1, 3]);
assert_eq!(select_listed(5, &[1, 5], Subset::All, false), Err(PrintError::OutOfRange(6, 5)));
assert!(matches!(select_listed(0, &[usize::MAX], Subset::All, false), Err(PrintError::OutOfRange(_, 0))));
assert_eq!(select_listed(5, &[], Subset::All, false), Err(PrintError::NoPages));
@@ -940,3 +942,22 @@ fn text_direction_reads_on_past_a_refused_form() {
text_direction(&doc, content, &res, Matrix::IDENTITY, 0, &mut score, &mut DecodeBudget::new(1 << 20, 0));
assert_eq!(score, 1);
}
/// #3984: odd and even are page numbers, as Acrobat counts them, not places in the range.
#[test]
fn odd_and_even_pages_are_page_numbers_not_places_in_the_range() {
let even = |range: &str| select_pages(12, Some(range), &[], Subset::Even, false).unwrap();
let odd = |range: &str| select_pages(12, Some(range), &[], Subset::Odd, false).unwrap();
// Adobe Acrobat DC Help (11/28/2019), Options in the Print dialog box, p. 515: "if you set the
// range to 2, 7–10 and choose Even Pages Only, only pages 2, 8, and 10 print".
assert_eq!(even("2, 7-10"), [1, 7, 9]);
// The report: 4–11 and 3–11 both print pages 4, 6, 8 and 10 as Even pages only.
assert_eq!(even("4-11"), [3, 5, 7, 9]);
assert_eq!(even("3-11"), [3, 5, 7, 9]);
assert_eq!(odd("4-11"), [4, 6, 8, 10]);
// Typed order is kept, and Reverse turns it round.
assert_eq!(even("10, 3, 4"), [9, 3]);
assert_eq!(select_pages(12, Some("10, 3, 4"), &[], Subset::Even, true).unwrap(), [3, 9]);
// A range with no page of the kind prints nothing.
assert_eq!(select_pages(12, Some("3, 5"), &[], Subset::Even, false), Err(PrintError::NoPages));
}
+2 -2
View File
@@ -8013,8 +8013,8 @@ milestone = "M10"
status = "shipped"
commands = ["print.dialog"]
tools = ["doc_print"]
evidence = ["crates/print/src/tests.rs::page_selection"]
notes = ""
evidence = ["crates/print/src/tests.rs::page_selection", "crates/print/src/tests.rs::odd_and_even_pages_are_page_numbers_not_places_in_the_range", "crates/automation/tests/it/automation.rs::cut_stack_printing_through_tools"]
notes = "Odd and even are page numbers, as Acrobat counts them (Adobe Acrobat DC Help, 11/28/2019, Options in the Print dialog box, p. 515: a range of 2, 7–10 with Even Pages Only prints pages 2, 8 and 10), for a typed range, picked thumbnails and the current page; Reverse turns the chosen pages round (#3984). Not yet: with page labels, odd and even still count page numbers (a document whose front matter is numbered i, ii, iii… keeps label 2 among the odd pages when it is page 5); the Acrobat help consulted doesn't say how Acrobat counts there, and the other Print-dialog behaviours #3984 mentions are open."
[[feature]]
id = "print.scaling"