mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-11-05 13:35:38 +00:00
pdfgutter: never rewrite a page tree it cannot account for
This commit is contained in:
10 files changed
+534
-61
No files matched your search
+55
-6
@@ -217,13 +217,62 @@ pixel, and a parity test that demanded it would be a test of pdfium rather
|
||||
than of this.
|
||||
|
||||
What is compared instead is everything that decides: the aspect ratio, which
|
||||
pages get sampled, whether a given ink profile has a gutter, and the verdict
|
||||
a set of ratios and gutters adds up to. Both sides are handed the same
|
||||
profiles and have to agree exactly.
|
||||
pages get sampled, the reduction from pixels to a column profile, whether a
|
||||
given profile has a gutter, and the verdict a set of ratios and gutters adds
|
||||
up to. Both sides are handed the same pixels and the same profiles, and have
|
||||
to agree exactly.
|
||||
|
||||
**Measured:** 72 cases, including profiles either side of the ink threshold by
|
||||
one ten-thousandth and profiles too narrow to hold the three bands the test
|
||||
looks at.
|
||||
The two renderers do have to be pointed at the same rectangle, which is what
|
||||
`-cropbox` is for — see the next note.
|
||||
|
||||
**Measured:** 94 cases, including profiles either side of the ink threshold by
|
||||
one ten-thousandth, profiles too narrow to hold the three bands the test looks
|
||||
at, and greymaps whose heights do not divide evenly so that both sides have to
|
||||
round a fraction the same way.
|
||||
|
||||
## pdfgutter — the page is the crop box, consistently
|
||||
|
||||
**Python:** takes the aspect ratio from the media box and the ink profile
|
||||
from `page.render()`, which draws the **crop box**. On a page that carries
|
||||
both — most scanned books do — those are two different rectangles, so the
|
||||
shape is measured on one and the ink on the other. The bands the gutter is
|
||||
looked for in then fall somewhere other than the middle of what was
|
||||
rendered, and a real gutter is missed.
|
||||
|
||||
**Rust:** the crop box is what a reader shows, so it is what everything
|
||||
measures: the ratio, the render (`pdftoppm -cropbox`), and where the cut
|
||||
goes. A page with no crop box is its media box, which is what the spec says
|
||||
and what most files are.
|
||||
|
||||
**Why this is acceptable:** the original is not internally consistent, and on
|
||||
a wide sheet cropped to show only one of its two pages it gets the answer
|
||||
wrong in the destructive direction — the sheet still measures wide, so it is
|
||||
split again, down the middle of a page rather than between two. Measuring one
|
||||
rectangle throughout is the only version of this that is right.
|
||||
|
||||
**Measured:** a wide sheet cropped to one page is no longer a split
|
||||
candidate, and a cropped spread's gutter lands where it is looked for. The
|
||||
arithmetic that both sides share is compared exactly, as above.
|
||||
|
||||
## pdfgutter — a page tree that does not add up is refused
|
||||
|
||||
**Python:** pdfium enumerates the pages and the question never comes up.
|
||||
|
||||
**Rust:** the page tree is walked directly, and a walk is stricter than a
|
||||
renderer: a node missing its `/Type`, a `/Type` written as a reference, a kid
|
||||
that is a dictionary rather than a reference to one — each of those is a page
|
||||
a strict walk does not see and a reader does. So the number of pages found is
|
||||
checked against the number the file says it has, and a document where they
|
||||
disagree is refused with exit 2.
|
||||
|
||||
**Why this is acceptable:** splitting replaces the page tree, and a page left
|
||||
out of the new tree is a page deleted. A file this does not fully understand
|
||||
is one it must not rewrite. Refusing costs a document that could perhaps have
|
||||
been handled; not refusing costs pages, silently, in the copy you keep.
|
||||
|
||||
**Measured:** five shapes that a strict walk under-counts, each refused rather
|
||||
than written short. A document with nothing wide enough to cut is not
|
||||
rewritten at all, so every page comes through however the tree is built.
|
||||
|
||||
## pdfgutter — the thresholds are arguments, not environment variables
|
||||
|
||||
|
||||
@@ -70,3 +70,25 @@
|
||||
{"name": "two-of-three", "kind": "verdict", "ratios": [1.4, 1.4, 1.4], "gutters": [true, true, false]}
|
||||
{"name": "just-over-the-ratio", "kind": "verdict", "ratios": [1.1501, 1.1501, 1.1501, 1.1501], "gutters": [true, true, true, true]}
|
||||
{"name": "exactly-the-ratio", "kind": "verdict", "ratios": [1.15, 1.15, 1.15, 1.15], "gutters": [true, true, true, true]}
|
||||
{"name": "black-and-white-columns", "kind": "greymap", "width": 4, "height": 2, "pixels": [0, 255, 0, 255, 0, 255, 0, 255]}
|
||||
{"name": "either-side-of-the-threshold", "kind": "greymap", "width": 3, "height": 1, "pixels": [158, 159, 160]}
|
||||
{"name": "the-threshold-itself-everywhere", "kind": "greymap", "width": 5, "height": 4, "pixels": [160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160]}
|
||||
{"name": "one-below-the-threshold-everywhere", "kind": "greymap", "width": 5, "height": 4, "pixels": [159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159]}
|
||||
{"name": "a-page-with-a-gutter", "kind": "greymap", "width": 100, "height": 40, "pixels": [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 25Line truncated
|
||||
{"name": "a-single-row", "kind": "greymap", "width": 17, "height": 1, "pixels": [0, 200, 200, 0, 200, 200, 0, 200, 200, 0, 200, 200, 0, 200, 200, 0, 200]}
|
||||
{"name": "a-single-column", "kind": "greymap", "width": 1, "height": 9, "pixels": [0, 255, 0, 255, 0, 160, 159, 1, 254]}
|
||||
{"name": "awkward-7x3", "kind": "greymap", "width": 7, "height": 3, "pixels": [0, 37, 74, 111, 148, 185, 222, 11, 48, 85, 122, 159, 196, 233, 22, 59, 96, 133, 170, 207, 244]}
|
||||
{"name": "awkward-11x7", "kind": "greymap", "width": 11, "height": 7, "pixels": [0, 37, 74, 111, 148, 185, 222, 3, 40, 77, 114, 11, 48, 85, 122, 159, 196, 233, 14, 51, 88, 125, 22, 59, 96, 133, 170, 207, 244, 25, 62, 99, 136, 33, 70, 107, 144, 181, 218, 255, 36, 73, 110, 147, 44, 81, 118, 155, 192, 229, 10, 47, 84, 121, 158, 55, 92, 129, 166, 203, 240, 21, 58, 95, 132, 169, 66, 103, 140, 177, 214, 251, 32, 69, 106, 143, 180]}
|
||||
{"name": "awkward-13x13", "kind": "greymap", "width": 13, "height": 13, "pixels": [0, 37, 74, 111, 148, 185, 222, 3, 40, 77, 114, 151, 188, 11, 48, 85, 122, 159, 196, 233, 14, 51, 88, 125, 162, 199, 22, 59, 96, 133, 170, 207, 244, 25, 62, 99, 136, 173, 210, 33, 70, 107, 144, 181, 218, 255, 36, 73, 110, 147, 184, 221, 44, 81, 118, 155, 192, 229, 10, 47, 84, 121, 158, 195, 232, 55, 92, 129, 166, 203, 240, 21, 58, 95, 132, 169, 206, 243, 66, 103, 140, 177, 214, 251, 32, 69, 106, 143, 180, 217, 254, 77, 114, 151, 188, 225, 6, 43, 80, 117, 154, 191, 228, 9, 88, 125, 162, 199, 236, 17, 54, 91, 128, 165, 202, 239, 20, 99, 136, 173, 210, 247, 28, 65, 102, 139, 176, 213, 250, 31, 110, 147, 184, 221, 2, 39, 76, 113, 150, 187, 224, 5, 42, 121, 158, 195, 232, 13, 50, 87, 124, 161, 198, 235, 16, 53, 132, 169, 206, 243, 24, 61, 98, 135, 172, 209, 246, 27, 64]}
|
||||
{"name": "awkward-3x101", "kind": "greymap", "width": 3, "height": 101, "pixels": [0, 37, 74, 11, 48, 85, 22, 59, 96, 33, 70, 107, 44, 81, 118, 55, 92, 129, 66, 103, 140, 77, 114, 151, 88, 125, 162, 99, 136, 173, 110, 147, 184, 121, 158, 195, 132, 169, 206, 143, 180, 217, 154, 191, 228, 165, 202, 239, 176, 213, 250, 187, 224, 5, 198, 235, 16, 209, 246, 27, 220, 1, 38, 231, 12, 49, 242, 23, 60, 253, 34, 71, 8, 45, 82, 19, 56, 93, 30, 67, 104, 41, 78, 115, 52, 89, 126, 63, 100, 137, 74, 111, 148, 85, 122, 159, 96, 133, 170, 107, 144, 181, 118, 155, 192, 129, 166, 203, 140, 177, 214, 151, 188, 225, 162, 199, 236, 173, 210, 247, 184, 221, 2, 195, 232, 13, 206, 243, 24, 217, 254, 35, 228, 9, 46, 239, 20, 57, 250, 31, 68, 5, 42, 79, 16, 53, 90, 27, 64, 101, 38, 75, 112, 49, 86, 123, 60, 97, 134, 71, 108, 145, 82, 119, 156, 93, 130, 167, 104, 141, 178, 115, 152, 189, 126, 163, 200, 137, 174, 211, 148, 185, 222, 159, 196, 233, 170, 207, 244, 181, 218, 255, 192, 229, 10, 203, 240, 21, 214, 251, 32, 225, 6, 43, 236, 17, 54, 247, 28, 65, 2, 39, 76, 13, 50, 87, 24, 61, 98, 35, 72, 109, 46, 83, 120, 57, 94, 131, 68, 105, 142, 79, 116, 153, 90, 127, 164, 101, 138, 175, 112, 149, 186, 123, 160, 197, 134, 171, 208, 145, 182, 219, 156, 193, 230, 167, 204, 241, 178, 215, 252, 189, 226, 7, 200, 237, 18, 211, 248, 29, 222, 3, 40, 233, 14, 51, 244, 25, 62, 255, 36, 73, 10, 47, 84, 21, 58, 95, 32, 69, 106, 43, 80, 117, 54, 91, 128, 65, 102, 139, 76, 113, 150]}
|
||||
{"name": "awkward-101x3", "kind": "greymap", "width": 101, "height": 3, "pixels": [0, 37, 74, 111, 148, 185, 222, 3, 40, 77, 114, 151, 188, 225, 6, 43, 80, 117, 154, 191, 228, 9, 46, 83, 120, 157, 194, 231, 12, 49, 86, 123, 160, 197, 234, 15, 52, 89, 126, 163, 200, 237, 18, 55, 92, 129, 166, 203, 240, 21, 58, 95, 132, 169, 206, 243, 24, 61, 98, 135, 172, 209, 246, 27, 64, 101, 138, 175, 212, 249, 30, 67, 104, 141, 178, 215, 252, 33, 70, 107, 144, 181, 218, 255, 36, 73, 110, 147, 184, 221, 2, 39, 76, 113, 150, 187, 224, 5, 42, 79, 116, 11, 48, 85, 122, 159, 196, 233, 14, 51, 88, 125, 162, 199, 236, 17, 54, 91, 128, 165, 202, 239, 20, 57, 94, 131, 168, 205, 242, 23, 60, 97, 134, 171, 208, 245, 26, 63, 100, 137, 174, 211, 248, 29, 66, 103, 140, 177, 214, 251, 32, 69, 106, 143, 180, 217, 254, 35, 72, 109, 146, 183, 220, 1, 38, 75, 112, 149, 186, 223, 4, 41, 78, 115, 152, 189, 226, 7, 44, 81, 118, 155, 192, 229, 10, 47, 84, 121, 158, 195, 232, 13, 50, 87, 124, 161, 198, 235, 16, 53, 90, 127, 22, 59, 96, 133, 170, 207, 244, 25, 62, 99, 136, 173, 210, 247, 28, 65, 102, 139, 176, 213, 250, 31, 68, 105, 142, 179, 216, 253, 34, 71, 108, 145, 182, 219, 0, 37, 74, 111, 148, 185, 222, 3, 40, 77, 114, 151, 188, 225, 6, 43, 80, 117, 154, 191, 228, 9, 46, 83, 120, 157, 194, 231, 12, 49, 86, 123, 160, 197, 234, 15, 52, 89, 126, 163, 200, 237, 18, 55, 92, 129, 166, 203, 240, 21, 58, 95, 132, 169, 206, 243, 24, 61, 98, 135, 172, 209, 246, 27, 64, 101, 138]}
|
||||
{"name": "random-grey-0", "kind": "greymap", "width": 2, "height": 2, "pixels": [61, 102, 201, 177]}
|
||||
{"name": "random-grey-1", "kind": "greymap", "width": 5, "height": 64, "pixels": [148, 75, 133, 55, 133, 210, 167, 137, 55, 166, 159, 11, 103, 36, 103, 58, 233, 198, 37, 50, 212, 8, 50, 216, 202, 225, 153, 81, 208, 119, 55, 106, 199, 98, 70, 68, 252, 53, 234, 3, 232, 245, 61, 245, 252, 188, 219, 93, 1, 125, 46, 13, 238, 192, 231, 58, 134, 65, 243, 145, 230, 206, 150, 87, 236, 224, 154, 157, 23, 39, 107, 159, 215, 51, 237, 34, 239, 231, 8, 89, 223, 140, 38, 43, 64, 87, 220, 146, 239, 57, 103, 240, 34, 219, 78, 4, 196, 148, 20, 182, 129, 107, 135, 162, 31, 12, 143, 107, 32, 100, 150, 238, 69, 165, 133, 156, 146, 219, 244, 31, 114, 79, 20, 234, 59, 51, 133, 239, 194, 166, 168, 189, 95, 227, 169, 48, 230, 211, 20, 185, 47, 162, 223, 187, 234, 187, 23, 151, 134, 140, 45, 115, 200, 16, 87, 84, 240, 54, 46, 18, 223, 23, 71, 166, 125, 17, 141, 97, 75, 127, 148, 62, 227, 65, 36, 230, 159, 207, 115, 181, 52, 123, 132, 70, 177, 235, 113, 229, 155, 30, 224, 63, 97, 32, 252, 64, 197, 143, 250, 179, 231, 25, 217, 13, 115, 158, 124, 52, 204, 213, 69, 117, 79, 234, 95, 244, 44, 142, 205, 224, 32, 1, 123, 42, 138, 127, 248, 83, 203, 134, 237, 216, 11, 71, 48, 88, 218, 9, 137, 250, 170, 127, 158, 92, 36, 155, 13, 62, 37, 24, 45, 234, 32, 18, 47, 195, 251, 158, 190, 172, 143, 76, 61, 28, 22, 185, 92, 59, 172, 250, 180, 129, 238, 54, 106, 17, 87, 139, 197, 161, 9, 107, 251, 36, 12, 248, 116, 90, 94, 85, 196, 87, 35, 96, 128, 52, 84, 249, 212, 106, 37, 223, 177, 96, 162, 77, 99, 6, 21, 134, 157, 217, 239, 95, 33, 207, 12, 228, 130, 142]}
|
||||
{"name": "random-grey-2", "kind": "greymap", "width": 64, "height": 3, "pixels": [198, 161, 48, 247, 67, 202, 76, 24, 200, 110, 121, 48, 41, 178, 74, 245, 203, 189, 55, 247, 21, 74, 11, 247, 81, 170, 249, 224, 77, 140, 65, 144, 168, 156, 249, 197, 149, 205, 198, 10, 116, 103, 186, 85, 97, 6, 67, 17, 149, 38, 179, 174, 247, 189, 206, 208, 232, 246, 35, 34, 180, 186, 79, 100, 147, 77, 184, 139, 192, 252, 172, 92, 167, 180, 17, 217, 236, 141, 42, 226, 40, 164, 254, 17, 68, 108, 187, 68, 207, 225, 134, 161, 90, 124, 250, 14, 87, 237, 107, 161, 142, 158, 3, 189, 221, 65, 162, 69, 90, 58, 226, 17, 140, 181, 130, 152, 140, 133, 71, 36, 186, 187, 4, 214, 153, 147, 225, 92, 242, 235, 116, 174, 255, 148, 29, 122, 189, 61, 184, 230, 35, 125, 232, 235, 76, 51, 134, 220, 205, 222, 84, 57, 56, 174, 58, 107, 175, 78, 73, 198, 252, 152, 173, 123, 79, 235, 241, 253, 7, 56, 66, 211, 211, 23, 46, 40, 105, 161, 168, 176, 90, 221, 123, 99, 91, 207, 224, 91, 244, 225, 39, 228]}
|
||||
{"name": "random-grey-3", "kind": "greymap", "width": 64, "height": 3, "pixels": [239, 115, 229, 55, 13, 250, 124, 77, 188, 184, 183, 2, 225, 153, 95, 247, 160, 234, 96, 153, 63, 116, 228, 254, 218, 179, 183, 160, 71, 62, 245, 113, 246, 187, 11, 84, 98, 43, 200, 203, 213, 2, 183, 94, 44, 27, 185, 112, 248, 204, 186, 52, 152, 110, 173, 47, 12, 226, 138, 190, 54, 53, 162, 154, 71, 44, 129, 100, 158, 57, 58, 255, 150, 45, 247, 2, 250, 10, 7, 144, 56, 102, 155, 210, 248, 49, 27, 97, 7, 105, 73, 157, 145, 227, 190, 150, 180, 137, 106, 33, 193, 237, 220, 72, 42, 107, 211, 99, 224, 240, 58, 187, 0, 211, 196, 73, 154, 90, 60, 167, 77, 145, 233, 66, 64, 67, 100, 200, 252, 170, 242, 132, 159, 188, 119, 113, 203, 119, 115, 170, 89, 165, 190, 188, 200, 208, 98, 55, 151, 68, 152, 163, 172, 86, 118, 48, 107, 127, 222, 222, 105, 165, 16, 21, 165, 191, 152, 145, 111, 255, 85, 68, 179, 0, 233, 124, 168, 64, 148, 195, 177, 68, 199, 213, 138, 1, 140, 139, 58, 43, 43, 100]}
|
||||
{"name": "random-grey-4", "kind": "greymap", "width": 2, "height": 2, "pixels": [232, 173, 207, 94]}
|
||||
{"name": "random-grey-5", "kind": "greymap", "width": 8, "height": 5, "pixels": [178, 69, 89, 139, 210, 54, 174, 36, 127, 33, 8, 247, 247, 111, 250, 90, 229, 91, 227, 80, 193, 181, 107, 223, 229, 112, 94, 111, 69, 157, 229, 4, 138, 69, 242, 143, 44, 75, 149, 221]}
|
||||
{"name": "random-grey-6", "kind": "greymap", "width": 5, "height": 64, "pixels": [178, 251, 117, 200, 103, 113, 203, 92, 127, 92, 91, 109, 150, 65, 139, 74, 183, 154, 40, 170, 232, 224, 90, 80, 132, 108, 42, 222, 104, 100, 125, 204, 2, 6, 44, 248, 90, 146, 203, 153, 21, 67, 131, 219, 55, 75, 211, 220, 168, 191, 60, 7, 245, 145, 78, 143, 125, 180, 154, 225, 209, 229, 48, 234, 87, 82, 12, 115, 129, 109, 213, 55, 7, 231, 234, 226, 193, 34, 35, 136, 81, 233, 32, 230, 36, 173, 154, 227, 124, 171, 80, 232, 104, 96, 10, 128, 70, 187, 78, 119, 250, 229, 148, 155, 220, 105, 83, 230, 192, 163, 214, 60, 174, 173, 226, 202, 234, 70, 66, 250, 3, 213, 41, 16, 139, 5, 190, 8, 147, 58, 9, 139, 174, 237, 240, 189, 70, 152, 229, 233, 169, 124, 160, 168, 64, 242, 61, 172, 151, 113, 8, 187, 8, 216, 250, 27, 146, 0, 214, 237, 184, 82, 67, 207, 122, 135, 161, 64, 19, 1, 247, 254, 3, 238, 47, 26, 172, 29, 181, 20, 196, 118, 212, 61, 102, 95, 144, 143, 94, 109, 64, 118, 202, 54, 135, 236, 125, 83, 208, 120, 240, 245, 140, 232, 77, 86, 113, 132, 158, 85, 85, 217, 163, 64, 72, 101, 197, 165, 196, 148, 200, 175, 112, 225, 190, 205, 215, 13, 220, 60, 38, 59, 75, 188, 71, 32, 232, 166, 53, 6, 240, 236, 82, 212, 29, 247, 107, 140, 182, 188, 132, 147, 24, 214, 99, 151, 45, 144, 144, 54, 214, 233, 118, 158, 212, 131, 153, 208, 198, 91, 31, 62, 0, 108, 68, 162, 41, 227, 60, 247, 111, 67, 31, 181, 138, 70, 67, 183, 222, 63, 56, 56, 238, 137, 160, 126, 173, 203, 210, 134, 213, 74, 200, 147, 34, 254, 90, 241, 59, 222, 14, 202, 220, 252, 109, 32, 178, 83, 174, 23]}
|
||||
{"name": "random-grey-7", "kind": "greymap", "width": 5, "height": 64, "pixels": [237, 130, 80, 75, 116, 48, 246, 14, 244, 146, 93, 102, 14, 155, 255, 149, 103, 114, 123, 156, 222, 218, 216, 65, 16, 0, 132, 229, 67, 124, 89, 57, 213, 122, 83, 223, 7, 41, 221, 218, 68, 71, 193, 124, 23, 134, 104, 23, 158, 142, 108, 111, 213, 230, 221, 67, 107, 146, 252, 243, 219, 185, 127, 218, 83, 44, 24, 65, 1, 165, 217, 220, 189, 131, 9, 233, 73, 156, 219, 123, 98, 15, 29, 76, 246, 159, 8, 60, 151, 122, 165, 55, 148, 39, 113, 197, 134, 16, 112, 155, 9, 188, 142, 147, 19, 101, 240, 220, 47, 7, 9, 140, 93, 215, 200, 246, 165, 64, 9, 140, 231, 13, 169, 135, 88, 134, 114, 229, 157, 6, 168, 82, 18, 53, 192, 85, 187, 75, 212, 209, 106, 215, 225, 242, 152, 242, 201, 225, 240, 209, 26, 225, 238, 147, 124, 0, 133, 39, 206, 17, 90, 81, 19, 185, 110, 131, 177, 219, 29, 143, 194, 159, 227, 147, 190, 194, 201, 23, 75, 207, 99, 13, 14, 45, 99, 161, 73, 19, 132, 227, 36, 52, 228, 27, 174, 34, 165, 221, 14, 192, 26, 163, 169, 233, 230, 44, 45, 235, 219, 75, 65, 48, 148, 249, 44, 238, 79, 255, 220, 249, 250, 194, 33, 98, 118, 140, 76, 110, 252, 45, 64, 80, 248, 86, 154, 79, 87, 29, 251, 246, 56, 159, 42, 180, 122, 129, 73, 40, 156, 205, 76, 236, 58, 108, 80, 250, 97, 229, 236, 130, 23, 96, 60, 145, 68, 242, 202, 232, 3, 102, 238, 234, 61, 178, 6, 24, 75, 48, 242, 63, 101, 40, 213, 232, 92, 56, 83, 115, 53, 12, 37, 41, 43, 21, 67, 151, 211, 102, 71, 71, 135, 220, 179, 127, 16, 114, 93, 82, 47, 64, 109, 66, 241, 45, 196, 184, 127, 155, 206, 252]}
|
||||
{"name": "random-grey-8", "kind": "greymap", "width": 8, "height": 5, "pixels": [234, 23, 77, 84, 189, 212, 152, 21, 100, 47, 204, 255, 80, 21, 236, 208, 132, 213, 84, 81, 236, 76, 34, 121, 55, 100, 82, 85, 221, 50, 138, 15, 154, 136, 117, 41, 152, 225, 247, 94]}
|
||||
{"name": "random-grey-9", "kind": "greymap", "width": 5, "height": 64, "pixels": [46, 52, 170, 182, 133, 34, 95, 14, 143, 42, 127, 87, 126, 224, 170, 50, 131, 96, 231, 82, 67, 153, 28, 75, 164, 196, 4, 50, 104, 144, 222, 217, 236, 245, 36, 205, 231, 133, 156, 81, 126, 125, 253, 20, 146, 36, 6, 116, 243, 136, 74, 172, 28, 247, 188, 115, 111, 74, 217, 88, 71, 54, 230, 166, 236, 105, 220, 203, 236, 76, 221, 65, 120, 61, 200, 95, 98, 165, 105, 189, 38, 141, 76, 73, 130, 15, 168, 99, 223, 215, 161, 155, 176, 126, 137, 108, 122, 254, 158, 77, 238, 133, 96, 167, 8, 57, 87, 255, 231, 85, 186, 155, 55, 222, 127, 27, 54, 1, 223, 34, 12, 72, 76, 218, 73, 204, 169, 123, 172, 234, 160, 80, 211, 129, 74, 102, 158, 133, 20, 76, 96, 150, 163, 87, 102, 106, 47, 94, 189, 82, 95, 79, 31, 176, 55, 63, 247, 100, 191, 27, 130, 64, 32, 100, 63, 116, 154, 100, 89, 135, 129, 133, 231, 128, 175, 24, 95, 189, 70, 122, 13, 182, 218, 59, 109, 137, 184, 4, 238, 139, 178, 189, 187, 212, 73, 166, 67, 121, 66, 174, 130, 66, 111, 172, 80, 241, 190, 255, 164, 179, 78, 222, 134, 204, 253, 205, 30, 182, 60, 240, 134, 248, 74, 16, 52, 216, 42, 91, 216, 191, 198, 237, 90, 105, 11, 88, 249, 61, 245, 212, 57, 142, 191, 176, 199, 41, 103, 1, 167, 241, 87, 71, 125, 85, 82, 160, 165, 229, 145, 80, 34, 161, 195, 103, 144, 232, 105, 47, 210, 238, 111, 58, 147, 179, 42, 48, 140, 93, 78, 6, 202, 90, 146, 54, 222, 103, 222, 57, 232, 106, 224, 145, 192, 203, 154, 144, 39, 115, 107, 143, 255, 252, 21, 93, 6, 244, 223, 195, 149, 135, 117, 242, 69, 246, 130, 15, 76, 253, 111, 21]}
|
||||
@@ -70,3 +70,25 @@
|
||||
{"gutter_fraction": 0.6666666666666666, "kind": "verdict", "median_ratio": 1.4, "name": "two-of-three", "two_up": true}
|
||||
{"gutter_fraction": 1.0, "kind": "verdict", "median_ratio": 1.1501, "name": "just-over-the-ratio", "two_up": true}
|
||||
{"gutter_fraction": 1.0, "kind": "verdict", "median_ratio": 1.15, "name": "exactly-the-ratio", "two_up": false}
|
||||
{"kind": "greymap", "name": "black-and-white-columns", "profile": [1.0, 0.0, 1.0, 0.0]}
|
||||
{"kind": "greymap", "name": "either-side-of-the-threshold", "profile": [1.0, 1.0, 0.0]}
|
||||
{"kind": "greymap", "name": "the-threshold-itself-everywhere", "profile": [0.0, 0.0, 0.0, 0.0, 0.0]}
|
||||
{"kind": "greymap", "name": "one-below-the-threshold-everywhere", "profile": [1.0, 1.0, 1.0, 1.0, 1.0]}
|
||||
{"kind": "greymap", "name": "a-page-with-a-gutter", "profile": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.35, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}
|
||||
{"kind": "greymap", "name": "a-single-row", "profile": [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]}
|
||||
{"kind": "greymap", "name": "a-single-column", "profile": [0.5555555555555556]}
|
||||
{"kind": "greymap", "name": "awkward-7x3", "profile": [1.0, 1.0, 1.0, 1.0, 0.6666666666666666, 0.0, 0.0]}
|
||||
{"kind": "greymap", "name": "awkward-11x7", "profile": [1.0, 1.0, 1.0, 0.7142857142857143, 0.2857142857142857, 0.0, 0.42857142857142855, 1.0, 1.0, 1.0, 0.7142857142857143]}
|
||||
{"kind": "greymap", "name": "awkward-13x13", "profile": [1.0, 0.9230769230769231, 0.6153846153846154, 0.38461538461538464, 0.38461538461538464, 0.46153846153846156, 0.6923076923076923, 1.0, 0.8461538461538461, 0.6153846153846154, 0.38461538461538464, 0.3076923076923077, 0.46153846153846156]}
|
||||
{"kind": "greymap", "name": "awkward-3x101", "profile": [0.6534653465346535, 0.6534653465346535, 0.6534653465346535]}
|
||||
{"kind": "greymap", "name": "awkward-101x3", "profile": [1.0, 1.0, 1.0, 1.0, 0.6666666666666666, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.3333333333333333, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.3333333333333333, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.3333333333333333, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.3333333333333333, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.3333333333333333, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.3333333333333333, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.3333333333333333, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.6666666666666666, 1.0, 1.0, 1.0, 0.6666666666666666, 0.0, 0.0, 0.6666666666666666, 1.0, 1.0, 1.0, 0.6666666666666666, 0.0, 0.0, 0.6666666666666666, 1.0, 1.0, 1.0, 0.6666666666666666, 0.0, 0.0, 0.6666666666666666, 1.0, 1.0, 1.0, 0.6666666666666666, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.3333333333333333, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0]}
|
||||
{"kind": "greymap", "name": "random-grey-0", "profile": [0.5, 0.5]}
|
||||
{"kind": "greymap", "name": "random-grey-1", "profile": [0.625, 0.640625, 0.6875, 0.609375, 0.65625]}
|
||||
{"kind": "greymap", "name": "random-grey-2", "profile": [0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 1.0, 0.0, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.0, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.0, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 1.0, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 1.0, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 1.0, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 1.0, 0.6666666666666666, 1.0, 1.0, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.0, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666]}
|
||||
{"kind": "greymap", "name": "random-grey-3", "profile": [0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 1.0, 1.0, 0.3333333333333333, 1.0, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 1.0, 0.6666666666666666, 0.6666666666666666, 1.0, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 1.0, 0.6666666666666666, 0.0, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 1.0, 1.0, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 1.0, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 1.0, 0.3333333333333333, 0.3333333333333333, 1.0, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 1.0, 1.0, 0.6666666666666666, 0.6666666666666666]}
|
||||
{"kind": "greymap", "name": "random-grey-4", "profile": [0.0, 0.5]}
|
||||
{"kind": "greymap", "name": "random-grey-5", "profile": [0.4, 1.0, 0.6, 0.8, 0.4, 0.8, 0.4, 0.6]}
|
||||
{"kind": "greymap", "name": "random-grey-6", "profile": [0.59375, 0.546875, 0.625, 0.5, 0.703125]}
|
||||
{"kind": "greymap", "name": "random-grey-7", "profile": [0.671875, 0.671875, 0.609375, 0.625, 0.671875]}
|
||||
{"kind": "greymap", "name": "random-grey-8", "profile": [0.8, 0.8, 0.8, 0.8, 0.4, 0.6, 0.6, 0.8]}
|
||||
{"kind": "greymap", "name": "random-grey-9", "profile": [0.671875, 0.671875, 0.640625, 0.484375, 0.703125]}
|
||||
@@ -21,12 +21,19 @@ import numpy as np
|
||||
_MIN_RATIO = 1.15
|
||||
_MIN_GUTTER_FRAC = 0.6
|
||||
_TEXT_COL_INK = 0.02
|
||||
_INK_THRESHOLD = 160
|
||||
|
||||
|
||||
def _ratio(width: float, height: float) -> float:
|
||||
return width / height if height else 0.0
|
||||
|
||||
|
||||
def _col_ink_profile(pixels: list[int], width: int, height: int) -> list[float]:
|
||||
"""The reduction the renderer's output went through, minus the render."""
|
||||
arr = np.asarray(pixels, dtype=np.uint8).reshape(height, width)
|
||||
return [float(x) for x in (arr < _INK_THRESHOLD).mean(axis=0)]
|
||||
|
||||
|
||||
def _has_gutter(ink: np.ndarray) -> bool:
|
||||
w = len(ink)
|
||||
center = ink[int(0.46 * w):int(0.54 * w)]
|
||||
@@ -67,6 +74,10 @@ def answer(case: dict) -> dict:
|
||||
return {"gutter": _has_gutter(np.asarray(case["ink"], dtype=float))}
|
||||
if kind == "sample":
|
||||
return {"indices": _sample_indices(case["pages"])}
|
||||
if kind == "greymap":
|
||||
return {
|
||||
"profile": _col_ink_profile(case["pixels"], case["width"], case["height"])
|
||||
}
|
||||
if kind == "verdict":
|
||||
return _verdict(case["ratios"], case["gutters"])
|
||||
raise SystemExit(f"no such case: {kind}")
|
||||
|
||||
@@ -76,6 +76,28 @@ fn every_answer_matches_python() {
|
||||
note("indices", format!("{ours:?}"), &theirs["indices"]);
|
||||
}
|
||||
}
|
||||
"greymap" => {
|
||||
let width = case["width"].as_u64().expect("a width") as usize;
|
||||
let height = case["height"].as_u64().expect("a height") as usize;
|
||||
let pixels: Vec<u8> = case["pixels"]
|
||||
.as_array()
|
||||
.expect("an array")
|
||||
.iter()
|
||||
.map(|value| value.as_u64().expect("a number") as u8)
|
||||
.collect();
|
||||
|
||||
// The renderer is not the thing under test; the reduction it
|
||||
// feeds is. Both sides are handed the same pixels.
|
||||
let mut greymap = format!("P5\n{width} {height}\n255\n").into_bytes();
|
||||
greymap.extend_from_slice(&pixels);
|
||||
let ours = pdfgutter::ink::profile(&greymap, pdfgutter::INK_THRESHOLD)
|
||||
.expect("a readable greymap");
|
||||
|
||||
let theirs_profile = floats(&theirs["profile"]);
|
||||
if ours != theirs_profile {
|
||||
note("profile", format!("{ours:?}"), &theirs["profile"]);
|
||||
}
|
||||
}
|
||||
"verdict" => {
|
||||
let ratios = floats(&case["ratios"]);
|
||||
let gutters: Vec<bool> = case["gutters"]
|
||||
@@ -124,7 +146,7 @@ fn every_answer_matches_python() {
|
||||
#[test]
|
||||
fn every_kind_of_case_is_present() {
|
||||
let cases = cases();
|
||||
for kind in ["ratio", "gutter", "sample", "verdict"] {
|
||||
for kind in ["ratio", "gutter", "sample", "verdict", "greymap"] {
|
||||
assert!(
|
||||
cases.iter().any(|case| case["kind"] == kind),
|
||||
"no {kind} case"
|
||||
|
||||
Reference in new issue
Block a user